ポンクソフト

神経衰弱の作成 - C言語とelで様々なゲームを作ろう

前ページ C言語とelで様々なゲームを作ろう TOP 次ページ

目次

  1. C言語とelで様々なゲームを作ろう
  2. Visual C++ .NET での設定
  3. テンプレートファイルの解説
  4. シューティングゲームの作成(チュートリアル)
  5. パックマン的ゲームの作成(チュートリアル)
  6. ブロック崩しの作成
  7. 15パズルの作成
  8. 横スクロールジャンピングゲームの作成
  9. オセロの作成
  10. 神経衰弱の作成
  11. 7ならべの作成
  12. テトリスの作成
  13. ぷよぷよの作成

ソース・プロジェクトファイル

ソースファイル
プロジェクトファイル(Visual C++ 6.0)

ゲームの説明

トランプの神経衰弱です。左クリックでカードをめくり、右クリックで間違えたカードを閉じます。全部のカードをめくるまでにかかった時間が表示されます。

プログラムの解説

定数・グローバル変数

DDOBJ bmpCard, bmpMark, bmpNumber;
カード(表と裏)、マーク(4種類)、番号(13種類)のスプライトオブジェクトです。使用画像は以下のようになっていて、必要な部分を切り出してそれぞれのトランプを作り出しています。
suijaku_bmp.gif

構造体

struct {
  int mark;
  int no;
  bool rev;
} ba[4][13];
カードは x 方向に 13 枚、y 方向に 4 枚、計 52 枚のカードを並べますが、それぞれのカードの状態を表わすのが、二次元配列 ba です。構造体のメンバは以下のような意味を持ちます。

ウインドウ生成関数

bmpCard = elDraw::LoadObject("card.bmp");
bmpMark = elDraw::LoadObject("mark.bmp");
bmpNumber = elDraw::LoadObject("number.bmp");
カード・マーク・番号の各画像をスプライトに読み込んでいます。
int deal[4][13] = {0};
for (int y = 0; y < 4; y++) {
  for (int x = 0; x < 13; x++) {
    int mk, no;
    do {mk = rand() % 4; no = rand() % 13;} while (deal[mk][no]);
    ba[y][x].mark = mk;
    ba[y][x].no = no;
    ba[y][x].rev = true;
    deal[mk][no] = 1;
  }
}
神経衰弱なので、まずカードをシャッフルして場に並べなければなりません。その処理を行なっているのが上の部分です。以下に説明を書きます。
int deal[4][13] = {0};
シャッフルをして、配り終えたカードをチェックする配列です。配り終えたカードの配列要素には 1 が入ります。
int mk, no;
do {mk = rand() % 4; no = rand() % 13;} while (deal[mk][no]);
マーク (mk) と番号 (no) をランダムでひとつ選んでいます。配り終えていないカードが選択されるまでループします。
ba[y][x].mark = mk;
ba[y][x].no = no;
ba[y][x].rev = true;
選んだマークと番号を場にセットし、さらに裏返しフラグをセットします。
deal[mk][no] = 1;
配り終えたチェックを入れます。

メイン画面 変数

static int omote = 0;
確定していない、表になっているカードの枚数です。2枚揃えて表になったカードは含まれません。カードをめくっていないときは0、1枚めくったときは1、2枚めくって番号が揃わなかったときに2となります。
static int ox, oy;
1枚目にめくったカードの座標が入ります。
static int nx, ny;
現在めくろうとしているカードの座標が入ります。
static int nokori = 52;
残りカード(裏になっているカード)の枚数が入ります。これが0になったらゲームクリアです。
static DWORD startTime;
static DWORD pastTime;
ゲーム開始時間と経過時間です。単位はミリ秒。
if (elChangeScreen()) startTime = timeGetTime();
ゲーム開始時にゲーム開始時間をセットしています。elChangeScreen は、MainScreen が呼ばれる最初の一回だけ、true になる関数です。MainScreen の中で初期設定を行いたいときに使います。timeGetTime は、システムが起動してからの時間をミリ秒単位で返す関数です。

メイン画面 カードめくり処理

if (MouseCL && omote < 2) {
マウスが左クリックされ、なおかつ1枚目か2枚目をめくろうとしているときに if 文の中の処理を行ないます。
nx = (MousePX - 60) / 40;
ny = (MousePY - 96) / 64;
nx にクリックされたカードの横方向の番号 (0 ~ 12)、ny にクリックされたカードの縦方向の番号 (0 ~ 3) が入ります。画面上のカードを表示位置が (60, 96) から開始しているのでまずそれを引き、さらにカードの大きさで割っています。
if (nx >= 0 && nx <= 12 && ny >= 0 && ny <= 3 && ba[ny][nx].rev) {
クリックされた場所がカードの上に乗っていて、なおかつそのカードが裏返っている場合、if 文の中の処理を行ないます。
if (omote == 0) {
  ox = nx; oy = ny;
  ba[oy][ox].rev = false;
  omote = 1;
1枚目をめくったときの処理です。ox, oy に座標を保存して、カードを表向きにし、変数に omote に 1 を代入して1枚目をめくった状態にします。
} else {
  ba[ny][nx].rev = false;
  if (ba[ny][nx].no == ba[oy][ox].no) {
    nokori -= 2;
    omote = 0;
  } else omote = 2;
}
2枚目をめくったときの処理です。まずカードを表向きにし、次に1枚目と2枚目の番号を比べています。番号が等しければ残り枚数を2枚減らし、omote に 0 を代入してカードをめくっていない状態にします。番号が等しくなければ omote に 2 を代入してカードを2枚めくった状態にします。
} else if (MouseCR && omote == 2) {
  ba[oy][ox].rev = true;
  ba[ny][nx].rev = true;
  omote = 0;
}
マウスが右クリックされ、なおかつカードが2枚めくられているときは、2枚のカードを裏返し、カードをめくっていない状態にします。

メイン画面 カード表示処理

for (int y = 0; y < 4; y++) {
  for (int x = 0; x < 13; x++) {
縦方向に 4 枚、横方向に 13 枚分、カードを表示する処理を繰り返します。
int x2 = x * 40 + 60;
int y2 = y * 64 + 96;
x2 と y2 に表示するカードの左上座標が入ります。
int xc = ba[y][x].rev ? 40 : 0;
xc には、カードが表だった場合には 0、裏だった場合には 40 が入り、これをビットマップ上の x 座標とすることによってカードの表か裏を正しく表示することができます。上の書き方は条件演算子というものを使って、if 文と同じような処理を行なっています。条件演算子の書き方は以下の通り。
条件 ? 処理1 : 処理2
条件が真の場合処理1が実行され、偽の場合処理2が実行されます。
elDraw::Layer(x2, y2, bmpCard, xc, 0, xc + 40, 64);
上で計算した座標を使ってカードを表示しています。
if (!ba[y][x].rev) {
  elDraw::Layer(x2 + 6, y2 + 5, bmpMark,
    ba[y][x].mark * 28, 0, ba[y][x].mark * 28 + 28, 28);
  elDraw::Layer(x2 + 6, y2 + 33, bmpNumber,
    ba[y][x].no * 28, 0, ba[y][x].no * 28 + 28, 26);
}
カードが表の場合、マークと番号をカードの上に表示しています。配列 ba のマークと番号のデータからビットマップ上の適切な x 座標を計算して表示します。

メイン画面 経過時間処理

pastTime = (timeGetTime() - startTime) / 1000;
現在時間からゲーム開始時間を引くことによって、経過時間を計算しています。単位はミリ秒なので 1000 で割って秒に直しています。
SHOW2(8, 32, "経過時間:%d 秒", pastTime);
経過時間を画面に出力しています。SHOW2 は el の関数で、printf と同じ表記が使えます。

メイン画面 ゲームクリア処理

if (nokori <= 0) {
  MESG("クリア! 所要時間は %d 秒です。", pastTime);
  elDraw::Exit();
}
残り枚数が0になったらゲームクリアのメッセージを表示して終了します。
前ページ C言語とelで様々なゲームを作ろう TOP 次ページ
このエントリーをはてなブックマークに追加 そっか0