押したキーを表示する - キー読み取り版
押したキーを読み取り、画面に表示します。
- 2022-06-12
- 公開
コード
main.c
- #include <genesis.h>
- #define BUTTON_REPEAT_TRIGGER_COUNT 30
- #define BUTTON_REPEAT_INTERVAL 5
- #define DEFAULT_POSITION_X 12;
- #define DEFAULT_POSITION_Y 13;
- // テキスト表示位置
- static u16 posX = DEFAULT_POSITION_X; // 表示文字のX座標
- static u16 posY = DEFAULT_POSITION_Y; // 表示文字のY座標
- /**
- * 渡された1文字を状態に対応するパレットで画面に表示する
- * @param c 表示する文字
- * @param state 状態
- */
- static void drawChar(char c, u16 state) {
- // 表示するボタンの頭文字の設定(0は終端文字)
- char chr[2];
- chr[0] = c;
- chr[1] = 0;
- // テキストのパレットを、ボタンの押下があれば0、なければ1に設定
- VDP_setTextPalette(state ? PAL0 : PAL1);
- // 対応するボタンの頭文字を表示
- VDP_drawText(chr, posX, posY);
- // 表示の横位置をずらす
- posX += 2;
- }
- /**
- * 1Pコントローラの変化したボタンに対応した画面上の文字の色を変更する
- * @param state ボタン
- */
- static void drawButtonChar(u16 state) {
- drawChar('U', state & BUTTON_UP);
- drawChar('D', state & BUTTON_DOWN);
- drawChar('L', state & BUTTON_LEFT);
- drawChar('R', state & BUTTON_RIGHT);
- drawChar('A', state & BUTTON_A);
- drawChar('B', state & BUTTON_B);
- drawChar('C', state & BUTTON_C);
- drawChar('X', state & BUTTON_X);
- drawChar('Y', state & BUTTON_Y);
- drawChar('Z', state & BUTTON_Z);
- drawChar('S', state & BUTTON_START);
- }
- /**
- * コントローラの状態
- */
- typedef struct {
- u16 current; // 押下しているキー
- u16 trigger; // 押し始めたキー
- u16 off; // 離したキー
- u16 repeat; // 押し続けているキー
- u16 repeatCount; // リピートカウント
- } JoyState;
- /**
- * コントローラの状態を保持するグローバル変数
- */
- JoyState joyState;
- /**
- * VBlankごとに1回だけボタンの情報を取得する
- */
- static void joyExec() {
- u16 state = JOY_readJoypad(JOY_1);
- joyState.trigger = state & ~joyState.current;
- joyState.off = joyState.current & ~state;
- joyState.current = state;
- // 「押し続けているキー」の設定
- // NOTE: 「押し続けているキー」は、押し始めたあと指定の時間無効化され、
- // それ以降押下している間は一定の間隔でオンオフを繰り返す
- if (joyState.trigger) {
- joyState.repeat = joyState.current;
- joyState.repeatCount = BUTTON_REPEAT_TRIGGER_COUNT;
- }
- else if (!joyState.repeatCount) {
- joyState.repeat = joyState.current;
- joyState.repeatCount = BUTTON_REPEAT_INTERVAL;
- }
- else {
- joyState.repeat = 0;
- }
- // カウント
- if (joyState.current) {
- if (joyState.repeatCount > 0) {
- joyState.repeatCount--;
- }
- }
- }
- int main(u16 hard) {
- // ボタンを押していない時のテキスト色をパレット1に設定する
- // NOTE: SGDKではテキスト色はパレット0~3の15番を使用する
- // 1パレットは16個単位だが、色を表す値は区切りなく連続して存在している
- // つまり16+15はパレット1の15番目の色ということ
- PAL_setColor(16+15, 0x0666);
- // 初期テキスト
- VDP_drawText("1P Pad:", posX-6, posY-1);
- VDP_drawText("trig:", posX-6, posY);
- VDP_drawText("off :", posX-6, posY+1);
- VDP_drawText("curt:", posX-6, posY+2);
- VDP_drawText("rpt :", posX-6, posY+3);
- // パレットを1に設定(文字色変更)
- VDP_setTextPalette(PAL1);
- // 初期テキスト2
- VDP_drawText("U D L R A B C X Y Z S", posX, posY);
- VDP_drawText("U D L R A B C X Y Z S", posX, posY+1);
- VDP_drawText("U D L R A B C X Y Z S", posX, posY+2);
- VDP_drawText("U D L R A B C X Y Z S", posX, posY+3);
- // コントローラ状態を初期化(0埋め)
- memset(&joyState, 0, sizeof(JoyState));
- // メインループ
- while (TRUE) {
- SYS_doVBlankProcess();
- // ボタン状態取得
- joyExec();
- // テキスト表示位置の初期化
- posX = DEFAULT_POSITION_X;
- posY = DEFAULT_POSITION_Y;
- // 押し始めたボタン
- drawButtonChar(joyState.trigger);
- // テキスト表示位置をずらす
- posX = DEFAULT_POSITION_X;
- posY++;
- // 離したボタン
- drawButtonChar(joyState.off);
- // テキスト表示位置をずらす
- posX = DEFAULT_POSITION_X;
- posY++;
- // 押しているボタン
- drawButtonChar(joyState.current);
- // テキスト表示位置をずらす
- posX = DEFAULT_POSITION_X;
- posY++;
- // 押し続けているボタン
- drawButtonChar(joyState.repeat);
- }
- return 0;
- }
実行結果
上記コードをSGDK1.70でコンパイルし
Gens v2.14 Souvenirで実行したスクリーンショット
解説
ボタンの状態変化を受けて処理を実行するJOY_setEventHandlerと異なり、メインループで毎回(つまりVBlankごとに)ボタンの状態を読み取ります。
ボタンの状態による変化を細かく起こしたい場合は、こちらの方が向いているかもしれません。
処理を実行する場所で毎回ボタンの状態を読み取るのではなく、読み取り自体はVBlank中に1度だけにすることで、チャタリングの防止になるそうです(参考リンク先の情報による)。