C言語ゲームプログラミング 第7回講座




2014年10月より個人の方を対象に、Study C無料提供を開始しました。
C言語を勉強中の方は、学習・教育に最適なC言語インタープリタのStudy Cを使ってみてください(個人の方は無料です)。
大学・高専・高校などの教育機関での採用実績も多数あるロングセラー商品Study Cが、個人向けに無料提供を始めました。
インタープリタの手軽さに加え、ゲームや3Dタートルグラフィックで楽しく勉強したりと、C言語の学習を協力にサポートします。
ブロック崩しゲーム 3Dツリー クリスマスツリー
また、このようなボタンの用意されているページでは、掲載しているプログラムをStudy Cに直接ロードし実行したりすることができます。
Study Cにロードする Study Cにロードし編集する Study Cにロードし実行する
Study C無料利用についての詳細は、このページを参照してください。



1.キー入力

これまで、C言語学習塾ユーザ専用ページのケーススタディではgetch()とkbhit()関数を使ってキーボードからの入力を行うように説明していました。

ちょっと復習してみると、kbhit()関数は何かキー入力されたかどうかを検知しTRUE(真の値)を返してきます。 kbhit()関数がTRUEを返したとき、getch()関数を使用して何のキーが押されたかを取得します。 getch()関数は、カーソル左キーの場合7、右キーの場合8を返します。

次のプログラムはカーソルの左右キーで画面上のボールを左右に動かすプログラムです。 getch()関数の返す値によってボールのX座標(b_xx)を変化させ新たな位置にボールを描いています。 ボールを描いた位置はbold_xx変数に保持しておき次回別の位置にボールを描く直前に、その位置をfillrect()関数で消去しています。

#include <graph.h>

main()
{
        HBITMAP hbmp_ball;
        int     b_xx,           //ボールの位置
                bold_xx;        //ボールの旧位置
        unsigned long
                tick;

        gl_openwin(-1, -1, 640, 480, 0);

        hbmp_ball = gl_loadbitmap("ball.bmp");
        if(hbmp_ball == NULL){
                printf("ビットマップファイルが見つかりません.\n");
                exit(0);
        }

        bold_xx = -1;
        b_xx = 320;
        tick = GetTickCount();

        for(;;){
                if(GetTickCount() >= tick && GetTickCount() < tick + 50)
                        continue;
                tick = GetTickCount();

                if(kbhit()){
                        switch(getch()){
                        case 7: //キー入力は左カーソル
                                b_xx -= 10;
                                //ボールが画面からはみ出さないようにする処理
                                if(b_xx < 0)
                                        b_xx = 0;
                                break;
                        case 8: //キー入力は右カーソル
                                b_xx += 10;
                                //ボールが画面からはみ出さないようにする処理
                                if(b_xx > 640 - 16)
                                        b_xx = 640 - 16;
                                break;
                        }
                }

                if(bold_xx != b_xx){    //ボールの旧位置から移動していれば再描画
                        //旧位置(bold_xx)のボールを消去、bold_xxが-1の時(起動直後)は何もしない
                        if(bold_xx != -1){
                                gl_fillrect(bold_xx, 240, bold_xx + 16, 240 + 16, RGB(0, 0, 0));
                        }
                        //新しい位置にボールを描く
                        gl_drawbitmap(hbmp_ball, b_xx, 240, 16, 16, 0, 0);
                        //旧位置(bold_xx)を新しいボールの位置に置き換える
                        bold_xx = b_xx;
                }
                gl_refresh();
        }
}

このプログラムを実行してカーソル左右キーを押してみてください。 一件この関数で問題ないように思えますが、下記のようなゲームには不向きな点がいくつかあります。

(1)カーソルキーを押し続けると、一瞬動きが止まった後ボールが動き出します。 これはキーボードのオートリピート機能による動きです。
(2)カーソルキーで何かを動かしながら別のキーでビームを出すような使い方ができません。 (3)ShiftやCtrlキーの検出ができません。


2.キー状態の取得

ゲームに最適な関数としてgl_getkeystate()関数を用意しました。 この関数は、指定したキーが現在押されているかをチェックすることができます。

gl_getkeystate(kc);
kc : チェックしたいキーコードを指定します。
キーコードは'A'〜'Z'(大文字で指定します)、'0'〜'9'やgraph.hインクルードファイルに定義された定数で指定します。
カーソルキーならVK_LEFT、VK_UP、VK_RIGHT、VK_DOWNを使用します。
その他
        スペースキー:VK_SPACE
        Shift:VK_SHIFT
        Ctrl:VK_CONTROL
        ESC:VK_ESCAPE

返り値が負の値の場合、キーが押されているということになります。

例)
gl_getkeystate('A');
Aキーが押されている場合負の値を返します。

gl_getkeystate(VK_LEFT);
左カーソルキーが押されている場合負の値を返します。

gl_getkeystate(VK_SHIFT);
Shiftキーが押されている場合負の値を返します。

gl_getkeystate(VK_ESCAPE);
ESCAキーが押されている場合負の値を返します。

gl_getkeystate()関数を使用して前のプログラムを書き換えます。

#include <graph.h>

main()
{
        HBITMAP hbmp_ball;
        int     b_xx, bold_xx;
        unsigned long
                tick;

        gl_openwin(-1, -1, 640, 480, 0);

        hbmp_ball = gl_loadbitmap("ball.bmp");
        if(hbmp_ball == NULL){
                printf("ビットマップファイルが見つかりません.\n");
                exit(0);
        }

        bold_xx = -1;
        b_xx = 320;
        tick = GetTickCount();

        for(;;){
                if(GetTickCount() >= tick && GetTickCount() < tick + 50)
                        continue;
                tick = GetTickCount();

                //左カーソルキーが押されていれば移動処理を行います。
                if(gl_getkeystate(VK_LEFT) < 0){
                        b_xx = b_xx - 10;
                        if(b_xx < 0)
                                b_xx = 0;
                }
                //右カーソルキーが押されていれば移動処理を行います。
                if(gl_getkeystate(VK_RIGHT) < 0){
                        b_xx = b_xx + 10;
                        if(b_xx > 640 - 16)
                                b_xx = 640 - 16;
                }

                if(bold_xx != b_xx){
                        if(bold_xx != -1){
                                gl_fillrect(bold_xx, 240, bold_xx + 16, 240 + 16, RGB(0, 0, 0));
                        }
                        bold_xx = b_xx;
                        gl_drawbitmap(hbmp_ball, b_xx, 240, 16, 16, 0, 0);
                }
                gl_refresh();
        }
}

今度のプログラムは、キーを遅続けたとき一瞬とまるといった問題が解消されます。