🐯

curses を使ったサンプルゲーム

2025/01/26に公開

curses のサンプル、hello 動かすだけなのは味気ないので、落ちゲーのテトリスもどき、に差し替えてみた。

モノ: https://github.com/tenk-a/samples/tree/cmake_toolchain_and_pdcurses/curses_otige

src 以外は基本 hello と同じなので、ターゲットOSは、
win64 win32 mac linux dos32 dos16

ビルド方法等はこっちを見て、と。

cons

curses を使ったサンプルといいつつ、ゲーム側では curses を直接は扱わず、簡易ライブラリ的なものをワンクッションかましている。

curses ライブラリのないロースペックなマシン向けも想定していて、最小限のテキスト描画やマシン固有処理とかをまとめている。

https://github.com/tenk-a/samples/blob/cmake_toolchain_and_pdcurses/curses_otige/src/cons.h

今回のはヘッダにもなっていない、100行程の、使い切りの include ファイルで済ませている。
(curses以外の対応を行うときは、もうすこしちゃんと切り分ける)

使用の雰囲気は

int main(void) {
    if (cons_init() == 0)          // cons:コンソール画面初期化.
        return 1;
    for (;;) {
        cons_updateBegin();        // cons:毎フレームの開始処理.
        (ゲームの毎フレームの処理)
        cons_clear();              // cons:画面クリア.
        (ゲームの毎フレームの描画) 
        cons_updateEnd();          // cons:毎フレーム終わり処理.
    }
    cons_term();                   // cons:コンソール終了処理.
    return 0;
}

ゲームの毎フレームの処理では cons_key() でキー、cons_timer() で時間経過、を取得したりしてゲーム進行。
毎フレームの表示は cons_xycprintf(x,y,co,...) 等を使う。

  • cons_init()
    ゲーム向けに curses 初期化。

    • timeout(50) 設定で getch() でキー入力がない時 50 ミリ秒経過でタイムアウトする。
      20FPS ぽくなるが、キー入力時は 50 ミリ秒より早く終わるので正確ではない。
    • 文字の色については、基本7色(1..7) に、明るい色(+8)にする、文字黒で背景色に(+16)にする、 の 1..31 を設定している。
      (とくに今回のゲームでは空白の反転でブロックを表現するため)
  • cons_updateBegin()
    毎フレームの開始処理。
    現在のキーと時間を取得して static 変数に保存。
    cons_key()、cons_timer() は変数の値を返す。
    ※ キーや時間は、1フレーム処理の途中で、値が変わってほしくないため。

  • cons_clear()
    画面バッファ・クリア。
    ncurses は仕組み的に clear() より erase() を使うのが良い模様。
    pdcurses も半角文字だけを使っている場合は erase() で問題なさそうだが、win10 プロンプト画面で UNICODE 全角文字を使うと消し忘れが発生し、clear() だと残さず消えるので、clear() を採用。

  • cons_updateEnd()
    curses の refresh() して画面反映。

ゲーム側

ソース: https://github.com/tenk-a/samples/blob/cmake_toolchain_and_pdcurses/curses_otige/src/otige.c

ゲーム自身については割愛。いろいろ適当...

あわよくば、8bit CPU、などと思ってたりもするので、ついつい古い開発環境とかを思い、なるべく小さい型を使うとか、割り算さけてビット演算するとか、している。C言語は普通は int への昇格があるので下手に小型やキャストを利用すると返って余分な命令が生成されたりするので微妙だけど...

Discussion