パソコン活用研究シリコンバレー(C、C++、の活用研究)

Pongゲーム


==========================================================================================
ChatGPTで作成したPongゲーム(ー>Pongゲームを作ってみた)は全画面消去―>全画面再描画を繰り返して
いるので、時々画面がちらつくことがあります。
このちらつき解消のため、変化のあった部分だけ消去、描画するようにプログラムを少しだけ変更してみました。
これでスムーズに動くプログラムになっています。

The Pong game created with ChatGPT repeatedly erases and redraws the full screen, which sometimes causes
the screen to flicker. To eliminate this flickering, we modified the program slightly so that it only erases and redraws
the part of the screen that has changed. The program now runs smoothly.
==========================================================================================

Pongゲームの画面
左右のパドル(左側がPlayer)でボールを打ち返すシンプルなゲーム


1 Pongゲームのコード


@メインルーチンと関数

メインルーチンはwhileループの中でぐるぐる回っており、
押されたキーの取得 -> プレーヤのパドルの移動と再描画 -> ボールを消す -> コンピュータ側のパドルの
移動と再描画 -> ボールの描画 -> 衝突判定
を繰り返しています。

プレーヤの再描画、ボールを消す、コンピュータ側のパドルの移動と再描画、ボールの描画 
は関数を作り、関数をコールして処理しています。

関数
erasePaddle  パドルの消去
drawPaddle  パドルの描画
eraseBall  ボールの消去
drawBall  ボールの描画
movepaddle2  コンピュータ側のパドルの移動
setup  ゲームの初期設定


ChatGPTに作らせたバージョン(ー>Pongゲームを作ってみた)はsystem("cls")で全画面を消去していたため
多少画面がチラチラしていましたが、このバージョンではerasePaddle, eraseBallという消去のための関数を用意して
画面の変更のあった部分だけを消去しています。


A gotoxy
コンパイラはBorland C++ ver5.5なので、スクリーンの座標位置はgotoxy関数で指定している。
座標位置の指定方法はコンパイラによって異なるので、他のコンパイラではgotoxyは使えない。

B キー入力
プレーヤ側のパドル移動のためのキー入力は
if (kbhit()) {
char key = getch();
というお決まりの方法で行っています。

getchはCの標準ライブラリ関数ではないので、動作はコンパイラと環境(OS等)に依存することに
なりますが、コンパイラBorland C++と環境としてはMS-DOS,WindowsのDOSプロンプトやコマンドプロンプト
の組み合わせであればリアルタイムキー入力とまずまずの動作をします。

上記の場合、getchはおそらく入力されたキーの取得はキー入力バッファから読み取っているのではなく、
もっと手前で取得しているように見えます。
従ってキーのオートリピートの設定等にあまり影響されずにリアルタイムキー入力を実装できます。
※オートリピート発生のタイムラグや間隔の設定がslowなことにより、押すキーを切り替えた時に、キー入力が
ない状態が発生するなど、シビアなリアルタイムシューティングゲームだと多少問題になる現象が発生します。

もし、キーバッファからキーの値を取得しているとすると、キーの取得のたびにキーバッファのクリアなどの
処理を入れないと、オートリピートによる影響でうまくリアルタイムキー入力を実現できません。
Linux上のCコンパイラだとCによるリアルタイムキー入力のプログラムは少し工夫が必要になるようです。

BASICのINKEY$はキーの値をキーバッファから読み込むので、リアルタイムキー入力の必要なプログラム
を作ろうとするとこの問題が発生します。
詳しくはBASICでの説明になりますが、リアルタイムキースキャン(INPを使う)をご参照下さい。



pingpong2.c

#include <stdio.h>
#include <conio.h>
#include <windows.h>

#define PADDLE_HEIGHT 5
#define PADDLE_WIDTH 1

int ballX, ballY;
int ballDirX, ballDirY;
int paddle1Y, paddle2Y;
void erasePaddle(int,int);
void drawPaddle(int,int);
void setup(void);
void movepaddle2(void);
void eraseBall(int,int);
void drawBall(int,int);


void erasePaddle(int x, int y) {
        gotoxy(x,y);
        printf(" ");
}

void drawPaddle(int x, int y) {
        gotoxy(x, y);
        printf("|");
        
}

void eraseBall(int x, int y) {
         gotoxy(x, y);
    printf(" ");
}

void drawBall(int x, int y) {
    gotoxy(x, y);
    printf("O");
}

void setup() {
        int i;
    ballX = 40;
    ballY = 12;
    ballDirX = -1;
    ballDirY = 1;
    paddle1Y = 10;
    paddle2Y = 10;
        gotoxy(3,1);printf("##########################################################################");
        gotoxy(3,29);printf("##########################################################################");
         for (i = 0; i < PADDLE_HEIGHT; i++) {
        gotoxy(2, paddle1Y + i);
        printf("|");
                gotoxy(77,paddle2Y+i);
                printf("|");
         }
    }
        

void movepaddle2() {
    // Simple AI: Match the ball's vertical position
    if (ballY < paddle2Y + PADDLE_HEIGHT / 2 && paddle2Y > 2) {
       erasePaddle(77,paddle2Y+PADDLE_HEIGHT-1); paddle2Y--;  drawPaddle(77, paddle2Y);
    } else if (ballY > paddle2Y + PADDLE_HEIGHT / 2 && paddle2Y < 24) {
      erasePaddle(77,paddle2Y);  paddle2Y++; drawPaddle(77, paddle2Y+PADDLE_HEIGHT-1);
    }
}


int main() {
        int i,score;
        score=0;
        // Clear the screen
        system("cls");
    setup();

    while (1) {
        
        
        // Move the paddles
        if (kbhit()) {
            char key = getch();
            if (key == 'w' && paddle1Y > 2)
                {erasePaddle(2,paddle1Y+PADDLE_HEIGHT-1);paddle1Y--; drawPaddle(2, paddle1Y);}
            if (key == 's' && paddle1Y < 24)
                { erasePaddle(2,paddle1Y);    paddle1Y++;  drawPaddle(2, paddle1Y+PADDLE_HEIGHT-1);}
        }

        eraseBall(ballX,ballY);
        // Update the ball's position
        ballX += ballDirX;
        ballY += ballDirY;

       movepaddle2();

        // Draw ball and score
       
        drawBall(ballX, ballY);
        gotoxy(30,30);printf("score %d",score);

        // Ball collision with top and bottom walls
        if (ballY >= 28 || ballY <= 2)
            ballDirY = -ballDirY;

        // Ball collision with paddles
        if (ballX == 3 && (ballY >= paddle1Y && ballY <= paddle1Y + PADDLE_HEIGHT-1))
                { ballDirX = -ballDirX; score=score+1;}
        if (ballX == 76 && (ballY >= paddle2Y && ballY <= paddle2Y + PADDLE_HEIGHT-1))
            ballDirX = -ballDirX;

        // Ball out of bounds (scoring)
        if (ballX <= 0 || ballX >= 80) {
            break; // exit
        }

        Sleep(80); // Sleep to control the game speed
    }
        gotoxy(40,15);printf("Miss!");
    return 0;
}
2 




Summary in English

1) Main Routine and Functions The main routine goes around and around in a while loop, The following processes are repeated:
obtaining the key pressed, moving and redrawing the player's paddle, erasing the ball, moving and redrawing the paddle on the
computer side, drawing the ball, and detecting collision. The processes of redrawing the player, erasing the ball, moving and
redrawing the paddle on the computer side, and drawing the ball are processed by creating functions and calling these functions.


TopPage