ゲームボーイはまだ終わってない!本文へジャンプ

キー操作

ゲームボーイは、十字キー4つ、STARTボタン、SELECTボタン、Bボタン、Aボタンの合計8つのボタンを備えています。

今回はそれら8つのボタンが押されたときの制御方法について見ていきます。

#include <stdio.h>
#include <gb.h>
#include <drawing.h>

void main(  )
{
    UBYTE key;      /* ボタン情報 */
    UBYTE x;        /* X座標      */
    UBYTE y;        /* Y座標      */
    UBYTE prevx;    /* 前回X座標  */
    UBYTE prevy;    /* 前回Y座標  */
    UBYTE clr;      /* 色情報     */
    UBYTE radius;   /* 円の半径   */

    x = 40;
    y = 40;
    prevx = x;
    prevy = y;
    clr = 1;
    radius = 10;
    color(BLACK, WHITE, SOLID);     /* 前景色を黒に設定 */
    circle(x, y, radius, M_FILL);   /* 半径20の塗潰し円を描く   */
        
    while(1){
        prevx = x;                    /* 前回のX座標を保存しておく*/
        prevy = y;                    /* 前回のY座標を保存しておく*/
        
        waitpad(0xFF);                /* ボタンが押されるまで待つ */
        key=joypad();                 /* 押下ボタンを取得する     */
        waitpadup();                  /* ボタンが放されるまで待つ */

        delay(100);                   /* 100ミリ秒一時停止     */
        
        if(key & J_RIGHT){            /* 右ボタンが押されたとき */
            x = x + radius * 2;       /* X座標を加算する        */
            if(x >= 160){             /* X座標が右端へはみだすとき */
                x = x - radius * 2;
            }
        }
        if(key & J_LEFT){             /* 左ボタンが押されたとき */
            x = x - radius * 2;       /* X座標を減算する        */
            if(x <= radius){          /* X座標が左端へはみだすとき */
                x = x + radius * 2;   /* X座標を元に戻す        */
            }
        }
        if(key & J_DOWN){             /* 下ボタンが押されたとき */
            y = y + radius * 2;       /* Y座標を加算する        */
            if(y >= 140){             /* Y座標が下端へはみだすとき */
                y = y - radius * 2;   /* Y座標を加算する        */
            }
        }
        if(key & J_UP){               /* 上ボタンが押されたとき */
            y = y - radius * 2;       /* Y座標を減算する        */
            if(y <= radius){          /* Y座標が上端へはみだすとき */
                y = y + radius * 2;   /* Y座標を元に戻す        */
            }
        }
        
        color(WHITE, WHITE, SOLID);           /* 前景色を白に設定 */
        circle(prevx, prevy, radius, M_FILL); /* 前回描いた円を消す   */
        
        color(BLACK, WHITE, SOLID);           /* 前景色を黒に設定 */
        circle(x, y, radius, M_FILL);         /* 半径20の塗潰し円を描く   */
    }
}

waitpad関数
UBYTE waitpad(UBYTE mask);

waitpad関数はボタンが押されるまで処理を停止させる関数です。
引数では押されるまで待つボタンの種類を指定します。
全てのボタンを対象とするときは「0xFF」を指定します。


waitpadup関数
void waitpadup(void);

waitpadup関数は押されたボタンが放されるまで処理を停止させる関数です。


joypad関数
UBYTE joypad(void);

joypad関数は押されたボタンの種類を教えてくれる関数です。
何のボタンも押されていないときに呼ばれたら0を返します。

ボタン種類と定数の対応関係
ボタン種類   ボタン定数  値
 START  J_START  0x80U
 SELECT  J_SELECT  0x40U
 B  J_B  0x20U
 A  J_A  0x10U
 下  J_DOWN  0x08U
 上  J_UP  0x04U
 左  J_LEFT  0x02U
 右  J_RIGHT  0x01U

上記サンプルコードでは押されたボタンごとに、ボタン押下後の処理を実装しています。
ここで、if文の判定式で使っている演算子が「==」ではなく「&」であることに着目してください。

GBDKでは、ボタンが押されたかどうかの情報を1バイト(8ビット)で管理し、各ビットを8つのボタンそれぞれと対応させています。
そして、ボタンが押されたとき、そのボタンと対応するビットを「1」としています。

例えば、Bボタンを押した場合、joypad関数は「0x20」を返しますが、これを2進数で表すと「00100000」となります。
このとき6ビット目が「1」になっていることに着目してください。
Bボタンは6ビット目と対応しており、その6ビット目が「1」になっているためBボタンが押されたと判断できます。

次に、複数のボタンが同時に押された場合はjoypad関数はどんな値を返すかを見てみます。

例えば、右ボタンとAボタンが同時に押された場合、joypad関数は「0x10 + 0x01」、つまり「0x11」を返します。
これを2進数で表すと「00010001」となります。
5ビット目と1ビット目が「1」になっているので、Aボタンと右ボタンが押されたと判断できます。

このようにjoypad関数は、複数のボタンが押されたときは、それぞれのボタン定数の和を返すため、演算子「==」ではひとつのボタンが押されたときの判定しかできません。

しかし、演算子「&」を使えば、複数のボタンが押されたときの判定も正しく行うことができます。

例えば、上ボタンとAボタンが押された場合のjoypad関数が返す値と各ボタン定数との論理積の結果は、

上ボタンの押下判定
    00010100
AND 00000100  ←  J_UP
-------------
    00000100

Aボタンの押下判定
    00010100
AND 00010000  ←  J_A
-------------
    00010000

と、なります。

if文は0を偽、0以外を真と判定しますので、押されたボタンを判定することができるということです。


 
 <<図形描画 アルファベット表示>>
 ゲームボーイはまだ終わってないトップへ