Nodachisoft Nodachi Sword Icon
  
@あまじ✎ 2021年3月14日に更新

第4章1 コンソール・ゲーム用ライブラリ

イチからゲーム作りで覚えるC言語
第3章8 PlaySound関数を使って音を鳴らす : PREV
NEXT : 第4章2 C言語コンソール上で迷路脱出プログラム :

概要

いよいよ第五章では、C言語のコンソール上で動作するゲーム・プログラムを、最低限遊べる例として作成していきます。

ゲーム・プログラムを作成するにあたり、画面の描画機能であったり、キーボードからの操作機能、 ファイルの取扱い機能、音声を鳴らす機能など、さまざまなゲームプログラミングで利用できるような、 共通の機能が非常に多いです。

ここでは、今後の章で使用する最低限必要な共通の機能を、”小さな自作ゲーム用ライブラリ” として、C言語で実装します。 基本的には今までのページで紹介してきた内容を関数にまとめたものです。

なお、この後、具体的に迷路脱出ゲームや倉庫番ゲーム、シューティングゲームなどを 作成していきますが、そのゲームでは今回作成するライブラリを必要に応じて使っていきます。

なお、このページはまず飛ばして、後から必要なときに参考として読み返す形でも大丈夫です。

当ページで作成するソースコードはコチラをクリックでZIP形式でダウンロードできます。

よく使用する機能

「ランダムに生成された迷路から脱出するゲーム」や、「シューティングゲーム」など、 いずれも共通する機能があります。

簡単にどんな機能が最低限必要になりそうかをイメージしてみます。

コンソール表示制御関連機能

  • アプリ画面のサイズを変更する機能
  • 画面の指定した場所に文字などを描画する機能
  • 画面のちらつきを抑える(バッファの機能)

Windows API や ASCII エスケープシーケンスの仕組みを使って、 コンソールプログラムで使える機能をまとめます。

ファイル取扱い機能

  • テキストファイルへのデータ書き込み
  • テキストデータからのファイル読込

プレイヤーのハイスコアや、ゲームの設定について データを保存したり、読込ができるように機能をまとめます。

タイマー機能

  • ミリ秒単位での計測

ゲームの進行具合や、アニメーションのスピードを 管理するために使用します。

キーボード入力制御機能

  • 即時キーボード入力の判定

キーボードからのゲーム操作を簡単に行えるように機能をまとめます。

数学的な機能

  • 乱数の取得
  • 円と円の衝突判定

ブロック崩しゲームや、シューティングゲームなどでは、 物体と物体がぶつかったかを確認する処理が頻繁に起こります。

「ぶつかった」かどうかは、円と円などの図形が重なっているか否かを計算をすることで判定 できます。 このような処理は衝突判定と呼ばれます。 今回は2次元の円と円の図形を対象にした衝突判定について機能を実装しています。

効果音、音楽の機能

  • wave ファイルのメモリ読込と再生機能
  • mp3 ファイルの音楽をループ再生

ゲームに必要なサウンドエフェクトや、バックミュージックを再生する 機能をまとめます。

コード

それぞれの機能について具体的なコードと簡単な説明を記載しておきます。 最終的にまとめられた機能はヘッダファイルとC言語のソースコードファイルに まとめています。

ソースコードはコチラから確認できます。

コンソール表示制御関連機能のコード

画面サイズの変更や、 画面への文字の出力を扱う機能をまとめます。

構造体

まずはよく使う構造体の定義です。

 
ndcgamelib.h
// =============================================
// ライブラリ内で使う構造体を宣言
// =============================================
// RGB 色情報を格納する構造体
typedef struct {
    unsigned char r;    // 赤色(Red)   
    unsigned char g;    // 緑色(Green)
    unsigned char b;    // 青色(Blue)
} RgbColor;

// 1文字あたりの情報
typedef struct {
    char disp;          // 画面表示文字
    RgbColor color;     // 画面バッファの色情報
    RgbColor bgcolor;   // 背景色
} ScreenCell;

// 画像出力データを収める構造体
typedef struct {
    int screenWidth;   // スクリーン幅
    int screenHeight;  // スクリーンの高さ
    ScreenCell *cells; // 画面のセル情報(配列)
} ScreenBuffer;

RgbColor, ScreenCell, ScreenBuffer の 3 つの構造体を用意しています。

RgbColor構造体とScreenCell構造体

rgbColor 構造体は、色情報を持ちます。赤、緑、青色の3色の情報をもっており、 それぞれ 0~255 の色の強さを設定できます。 この色の強さの組合せで約1677万色を表現できます。

スクリーンに色付きの文字を描画するとき、 下のようなイメージとなります。

スクリーンへの描画イメージ

コンソールへ文字や色を描画するときは、一度に ScreenBuffer 構造体に どんな文字や色でコンソールに出力するかのデータをため込んで、一度に出力します。

それぞれの文字データや文字の色や背景色は ScreenCell 構造体を使って ScreenBuffer 構造体の中に 配列の形で格納されます。

ScreenBuffer は画面に出力するために必要な情報をすべて一つにまとめています。

コンソール表示制御関連の関数

続いて、コンソールに色付きの文字等を自由に描画、表示するためのライブラリ関数定義を確認します。 関数の中身の実装については割愛します。 (気になる方がいたら、ソースコードの中を確認していただければと思います!)

 
ndcgamelib.h
// ゲームライブラリを初期化します。
// ライブラリを使う時に最初に呼び出してください
void initNdcGameLib(int width, int height);

// ゲームライブラリの利用を終了します。
// ライブラリ内部で使っていたメモリはクリアされます。
void freeNdcGameLib();

// スクリーンバッファのデータを全て消去して初期状態に戻す
void clearScreenBuffer();

// スクリーンバッファの指定の位置(dx, dy) にテキストを描画する
// RGB で色の指定が可能
void drawText(const double dx, const double dy, const char text[], const rgbColor color);

// スクリーンバッファの内容を実際のコンソール上に出力する
void flushScreen();

// コンソール画面のサイズを (0, 0)-(width, height) に変更する
BOOL changeConsoleSize(int width, int height);

// カーソルの点滅を表示
void showCursor();

// カーソルを非表示にする
void hideCursor();

ライブラリの初期化とメモリ解放

まずライブラリを使う時に、最初に initNdcGameLib 関数を呼び出します。 ライブラリを使い終わったら、freeNdcGameLib 関数を呼び出すルールとします。

ライブラリ利用の開始と終了

画面への文字出力や色を操作する関連を扱うときに必要となる 表示する文字の内容や、色の情報、コンソールのサイズ(縦幅、横幅)などの 様々な情報があるかと思います。

そういった画面の描画に必要なデータを保存しておくメモリを確保して、初期化して…といった処理を 毎回プログラムで作成するのは面倒なので、まとめて initNdcGameLib という関数を呼び出せば 出来るようにしておきます。

ですので、今回ライブラリの機能を使う時は、まず最初に、この initNdcGameLib 関数を呼び出してあげる必要があります。

あとは、ライブラリの中でいろいろライブラリの機能を使うために必要なメモリの確保や初期化などを まとめて書いておきます。

ライブラリの使用が終わったら、ライブラリで確保したメモリを開放してあげる処理として、 freeNdcGameLib 関数を用意しています。 メモリを解放する処理をまとめてここに書いておけばOKです。

clearScreenBuffer関数

このライブラリを使うと、画面に描画する文字や色のデータを 高速に、かつ便利な機能付きで表示することができます。 clearScreenBuffer 関数は、画面に描画するために ScreenBuffer にため込まれている データ(文字や色など)を初期化して、リセットします。

drawText関数

画面の指定した場所に文字を書き込みます。 この関数では直接、コンソールに書き込むのではなく、ScreenBuffer の中に記録しておくだけです。

実際にコンソール画面に文字を書き出すのは、次に紹介する flushScreen 関数を使います。

flushScreen 関数

ScreenBuffer の中に書き込まれている、画面へ描画する 文字や色などのデータを出力して、コンソール画面を更新します。

changeConsoleSize 関数

コンソールの画面サイズを変更します。 実装面の解説についてはコチラの記載をご参照ください。

showCursor と hideCursor 関数

ゲームアプリの実行中など、カーソルが点滅していると邪魔な時があります。 hideCursor 関数はカーソルの点滅を非表示にします。 showCursor 関数はカーソルの点滅を表示するように戻します。

ファイル取扱い機能

ファイルを取り扱うための関数と簡単な使い方について記載します。

 
ndcgamelib.h
// =============================================
// ファイル操作関連の関数プロトタイプ宣言
// =============================================
// バイナリファイルを読み込み、キャラクタ型配列で内容を返す
char* readBinaryFile(const char* fileName);

// 引数 fileName で指定したファイルに saveData の文字列を書き込む
BOOL writeFile(const char* fileName, const char* saveData);

readBinaryFile でファイル名「fileName」の内容を読み込み、char の配列として 戻り値としてデータを受け取ることができます。

writeFile は saveData の内容を fileName という名前のファイルで保存します。

タイマー機能

ゲームの進行具合や、アニメーションのスピードを管理するために ミリ秒単位で、進み具体を確認できるような機能が必要となることが多いです。

 
ndcgamelib.h
// =============================================
// タイマー関連の関数プロトタイプ宣言
// =============================================
// 前回この関数を呼び出してからの時間をミリ秒で返す
long getDeltaTime();

プレイヤーの入力で停止せず、リアルタイムに画面がアニメーションしたり、 キーボードなどからの入力を受けてリアルタイムに反応するアプリは、 画面を更新する単位(フレームと呼びます)での処理が求められます。

getDeltaTime 関数は前回画面を更新したフレームから、次に更新するフレームまで、何ミリ秒かかったのかを 計測するときなどに利用します。

キーボード入力制御機能

キーボードからのゲーム操作を簡単に行えるように機能をまとめます。

 
ndcgamelib.h
// =============================================
// キーボード等による操作関連の関数プロトタイプ宣言
// =============================================
// 指定したキーが押されたなら TRUE が返る
BOOL isKeyPushed(int keyCode);

// 指定したキーが押しっぱなし状態なら TRUE が返る
BOOL isKeyDown(int keyCode);

scanf 関数などと違い、この関数を使ってもアプリは一時停止しません。 現在のキーボードの状況をリアルタイムに判断できます。

それぞれの関数は下のようなタイミングで TRUE を返します。

キーボード入力制御

  • isKeyPushed 関数はキーボードが押されたときに反応します。
  • isKeyDown 関数はキーボードが押されっぱなしに連続で反応します。

キーボードから文字を打つとき押しっぱなしだと、例えば 0.5 秒おきくらいで 文字が打ちこめるかと思いますが、 isKeyPushed 関数も同じように反応します。

例えば、シューティングゲームのように、細やかな入力制御を行いたい場合は、isKeyDown 関数で 入力の判定を行います。

キーボード即時入力の実装や、keyCode に設定できる値については 記事「第3章6 リアルタイムなキーボード入力制御」をご参照ください。

数学関連の機能

図形と図形が重なっていることの判定(衝突判定)や、乱数の生成など、数学的な関数で確認できます。

 
ndcgamelib.h
// =============================================
// 数学関連の関数プロトタイプ宣言
// =============================================
// from ~ to の範囲の整数をランダムに取得
int getRand(int from, int to);

// 衝突判定。円1と円2の図形が衝突していれば TRUE を返す
// 円1:中心(ax, ay) 半径 ar、円2:中心(bx, by) 半径 br
BOOL isCollisionCircle(
    const double ax, const double ay, const double ar,
    const double bx, const double by, const double br );

getRand 関数は from ~ to の範囲の範囲で、ランダムな整数を得られます。 最初に呼び出した時に、コンピュータの時刻をもとにシード値が決まります。

isCollisionCircle 関数は下のように円と円が重なっているかを判定します。

円と円の衝突判定

効果音、音楽の機能

サウンド関連の最低限必要となる機能として以下のようにまとめています。

 
ndcgamelib.h
// =============================================
// サウンド関連の関数プロトタイプ宣言
// =============================================
// 指定した wave 形式の音声データを読み込み、スロット番号に割り当てる
// スロット番号は 0~63 で指定可能
// 戻り値:成功なら TRUE, 失敗なら FALSE
BOOL readSoundEffect(const char *fileName, const int slotno);

// 音声データを一度再生する。
// 予め readSoundEffect 関数で読み込んだ先のスロット番号を指定する
// 戻り値:成功なら TRUE, 失敗なら FALSE
BOOL playSoundEffect(const int slotno);

// MCIで mp3 データなどを読み込み再生する
// 戻り値:成功なら TRUE, 失敗なら FALSE
BOOL playMediaFile(const char* fileName);

// オーディオデバイスの音量を変更します。
// 音量は引数の percent に 0.0~1.0 の範囲で設定します。
// 戻り値:成功なら TRUE, 失敗なら FALSE
BOOL setMediaVolume(const double percent);

// MCI 命令で再生しているメディアファイルが最後まで終了していたら最初から再生します。
// 定期的にこの関数を呼び出すことで、音楽のループ再生が可能です。
BOOL doLoopMediaFile();

// MCI のメディア再生位置をミリ秒単位で得る
int getMediaPlayingPosition();

// MCI で再生しているメディアファイルの長さをミリ秒単位で得る
int getMediaLength();

// MCI のメディアが停止中の状態であれば TRUE を返す
BOOL isMediaStopped();

短い効果音などはメモリに読み込んでから再生するほうが効率が良いため、 まずは readSoundEffect 関数でメモリに読み込み、playSoundEffect 関数で再生します。

効果音はスロット番号の0 から 63 までの、最大 64 個までメモリ上に読み込めるようにしてあります。

また BGM は playMediaFile 関数で mp3 などの音楽ファイルを指定することで再生が始まります。 BGM の音量調整は setSoundVolume 関数で行うことが出来ます。

BGM は MCI を通して再生します。 メモリ上に読み込んだ音声データと BGM は同時に再生することが出来ます。

参考文献

イチからゲーム作りで覚えるC言語
第3章8 PlaySound関数を使って音を鳴らす : PREV
NEXT : 第4章2 C言語コンソール上で迷路脱出プログラム :
 
 
送信しました!

コメント、ありがとうございます。

なんかエラーでした

ごめんなさい。エラーでうまく送信できませんでした。ご迷惑をおかけします。しばらくおいてから再度送信を試していただくか、以下から DM などでご連絡頂ければと思います。

Twitter:@NodachiSoft_jp
お名前:
 
連絡先:
 
メッセージ:
 
戻る
内容の確認!

以下の内容でコメントを送信します。よろしければ、「送信」を押してください。修正する場合は「戻る」を押してください

お名前:
 
連絡先:
 
メッセージ:
 
Roboto からの操作ではないという確認のため確認キーを入れてください。
確認キー=95
戻る
 / 
送信確認へ
コメント欄
コメント送信確認へ

関連ありそうな記事(5件)です!

第1章01 Visual Studio Community 2019 のインストール手順

#C11仕様#C言語#ゲームプログラミング✎ 2021-08-08
C言語でプログラミングをするために、無料で使える Visual Studio Community を使った開発環境を揃えていく手順や注意点をお話しています。
目次
第4章1 コンソール・ゲーム用ライブラリ
第4章1 コンソール・ゲーム用ライブラリ
概要
概要
よく使用する機能
よく使用する機能
コンソール表示制御関連機能
コンソール表示制御関連機能
ファイル取扱い機能
ファイル取扱い機能
タイマー機能
タイマー機能
キーボード入力制御機能
キーボード入力制御機能
数学的な機能
数学的な機能
効果音、音楽の機能
効果音、音楽の機能
コード
コード
コンソール表示制御関連機能のコード
コンソール表示制御関連機能のコード
構造体
構造体
コンソール表示制御関連の関数
コンソール表示制御関連の関数
ライブラリの初期化とメモリ解放
ライブラリの初期化とメモリ解放
clearScreenBuffer関数
clearScreenBuffer関数
drawText関数
drawText関数
flushScreen 関数
flushScreen 関数
changeConsoleSize 関数
changeConsoleSize 関数
showCursor と hideCursor 関数
showCursor と hideCursor 関数
ファイル取扱い機能
ファイル取扱い機能
タイマー機能
タイマー機能
キーボード入力制御機能
キーボード入力制御機能
数学関連の機能
数学関連の機能
効果音、音楽の機能
効果音、音楽の機能
参考文献
参考文献
Nodachisoft © 2021