ポンクソフト

ブロック崩しの作成 - 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 block;
DDOBJ pad;
DDOBJ ball;
ブロック・パドル・ボールの各画像を表わすスプライトオブジェクトです。それぞれの画像の大きさは
です。
bool bf[5][10];
画面上に複数のブロックがあり、それぞれのブロックについて「表示されている/消えている」を管理しなければいけないので、二次元配列 bf を用意しています。この配列の要素それぞれについて、ブロックが存在すれば true、存在しなければ false となります。
ブロックの表示領域は画面上、横 10 × 縦 5 ブロックあり、配列のどの要素がどのブロックに相当するのかは以下の図の通りです。
block_bf.gif

メイン関数

elWindow(640, 480, TRUE);
elWindow は画面をウインドウモードにする el の関数ですが、第3引数を TRUE にするとマウスが画面からはみ出さないようになります。

ウインドウ生成関数

  block = elDraw::LoadObject("block.bmp");
  pad = elDraw::LoadObject("pad.bmp");
  ball = elDraw::LoadObject("ball.bmp");
各ビットマップをスプライトに読み込んでいる部分です。
  for (int y = 0; y < 5; y++) {
    for (int x = 0; x < 10; x++) {
      if (x == 0 || x == 9 || y == 0) bf[y][x] = false;
      else bf[y][x] = true;
    }
  }
初期のブロックの状態を配列 bf にセットしています。全て true(ブロックあり)にするのではなく、ボールが通りやすいように左右と上の端は false(ブロックなし)にしています。

メイン画面

static int bx = 50, by = 160;
ボールの中央を表わす座標です。今回は当たり判定を簡略化するためにボールを点として扱います。その点の座標が (bx, by) です。
static int ax = 1, ay = 4;
ボールの速度です。初期状態では右に 1 、下に 4 の速度になっています。
static int px = 0;
パドルの x 座標です。これはパドル中央ではなく左端の座標です。
static int score = 0;
得点です。
static bool over = false;
ゲームオーバー、つまりボールを画面下に落とすと true になります。
px = MousePX;
MousePX は el の変数で、常にマウスの x 座標が入ります。マウスの x 座標をそのままパドルの x 座標としています。
if (px > 640 - 128) px = 640 - 128;
elWindow 関数によってマウスは画面からはみ出さないようになっているのですが、画面右へはパドルの長さ分だけはみ出すことがあるので、それを防いでいる部分です。
bx += ax; by += ay;
ボールの座標に速度を加えて移動します。
  if (bx < 0) {bx = 0; ax = -ax;}
  else if (bx > 640) {bx = 640; ax = -ax;}
  if (by < 0) {by = 0; ay = -ay;}
右や左や上の壁に当たったときに、速度を反転してボールを反射させています。
else if (by > 480) over = true;
下の壁に当たったときはゲームオーバーフラグを立てています。
  if (by >= 420 && by < 420 + 16 && bx >= px && bx < px + 128) {
    by = 420;
    ay = -ay;
    ax = (bx - px) / 16 - 4;
    if (ax >= 0) ax++;
  }
ボールの中央座標がパドルの領域内に入ったらボールとパドルが当たったと見なし、ボールを反射させています。
反射する際、y 方向の速度はそのまま反転していますが、x 方向の速度はパドルに当たった位置によって変化させています。パドルを横に8等分し、それぞれについてボールが当たったときの x 方向の速度は以下の図のようになります。
block_padsplit.gif
  int x2 = bx / 64, y2 = by / 32;
  if (y2 < 5 && bf[y2][x2]) {
    bf[y2][x2] = false;
    int x3 = bx % 64;
    int y3 = by % 32;
    if (x3 < 4 || x3 >= 64 - 4) ax = -ax; 
    if (y3 < 4 || y3 >= 32 - 4) ay = -ay; 
    score++;
  }
ボールとブロックとの当たり判定の部分です。
int x2 = bx / 64, y2 = by / 32;
この部分によってボールがある位置のブロックの番号を算出しています。int 型で割り算をした場合、端数が切り捨てられる性質を利用しています。x2 が横の番号(左から 0, 1 ... 9)、y2 が縦の番号(上から 0, 1 ... 4)です。
if (y2 < 5 && bf[y2][x2]) {
まず y2 < 5 でボールがブロックの領域に入っているかチェックし、そこにブロックがある場合(bf[y2][x2])、ボールとブロックが当たったと見なしています。
bf[y2][x2] = false;
ブロックが消えたので false を代入します。
int x3 = bx % 64;
int y3 = by % 32;
x3 と y3 は、ブロックの中でどの位置にボールがいるかを示す相対座標です。剰余を使うことによってどの位置にあるブロックでも関係なく同じ処理をすることができます。
if (x3 < 4 || x3 >= 64 - 4) ax = -ax;
ブロックの左端または右端に当たった場合、x 方向の速度を反転しています。
if (y3 < 4 || y3 >= 32 - 4) ay = -ay;
ブロックの上端または下端に当たった場合、y 方向の速度を反転しています。
この辺の処理をもう少し細かくすれば、ボールをもっと自然に反射させることができると思います。
score++;
最後に得点を +1 しています。
  for (y = 0; y < 5; y++) {
    for (x = 0; x < 10; x++) {
      if (bf[y][x]) elDraw::Layer(x * 64, y * 32, block, 0, 0, 64, 32);
    }
  }
配列 bf の値をチェックして、ブロックが存在するときのみそれを表示しています。
elDraw::Layer(bx - 8, by - 8, ball, 0, 0, 16, 16);
ボールを表示しています。(bx, by) はボールの中央座標なので、左上になるように直しています。
elDraw::Layer(px, 420, pad, 0, 0, 128, 16);
パドルを表示しています。
SHOW2(0, 450, "スコア : %d", score * 10);
スコアを表示している部分です。score はそのままだと 1 点ずつ増えて地味なので、表示のときだけ 10 倍しています。
  if (over) {
    elSystem::Message("ゲームオーバー");
    elDraw::Exit();
  }
ゲームオーバーになったら(フラグが立っていたら)ポップアップメッセージを表示して終了します。
  if (score >= 32) {
    elSystem::Message("ゲームクリア!");
    elDraw::Exit();
  }
ブロックを 32 個消したらゲームクリアなので、ポップアップメッセージを表示して終了します。
前ページ C言語とelで様々なゲームを作ろう TOP 次ページ
このエントリーをはてなブックマークに追加 そっか0

このページに関するコメントをどうぞ

お名前:


kuv
このプログラムでは、連結判定の時はつながっているぷよごとに結合番号をつけ、消せる場合はelist配列の結合番号と同じ要素番号のところにフラグを立てる、という方法をとっています。
ですが、例えばぷよをわざとつながらないように置いていった場合、結合番号の最大数がelist配列の要素数をオーバーしてしまうのではないでしょうか?
それに対応するにはelist配列の要素数をフィールドの大きさと同じ6*13=78にしなければいけないと思うのですが、30にしているのには何か意図があるのでしょうか?
2017/07/11 14:52

しお
vectorではなくlistを使っているのはなぜなのでしょうか?
2017/05/07 19:06

surach
なぜ弾のX座標が sx = px + 24;で時機の中央になるんですか?
2017/05/05 11:09

何度やってもできないー^^
ファイルが見つかりませんとなるのですが・・・
どうすれば?
2017/01/20 17:23

ww
dxlibは外部から自分で導入するものです。しっかり導入しましたか?
2016/12/26 12:29

ww
IncludePathとLibraryPathはdxライブラリを導入したときのフォルダパスが間違っているため、dxlib.hがあるフォルダパスを設定しなおせば動きます。
2016/12/26 12:28

ww
MTdは、プロジェクトのプロパティの設定項目から変更できる。
Debugモードの設定が、違うようですね↓
2016/12/26 12:26

笑子
実行したところ、白い画面が出てきてしまいます。解決策は、あるのでしょうか?
2016/11/10 23:38


背景を挿入したいのですが,どこにどんな風にプログラムを加えればいいのでしょうか?
2016/09/24 21:44

華仙 学
オセロプログラムに関してです。
Visual Studio 2015を使ってます。このプログラムを打ち込んだところ、「'RuntimeLibrary'の不一致が検出されました。値'MTd_StaticDebug'がMDd_DynamicDebugの値'othello.obj'と一致しません」と出てしまいます。いろいろ調べていますがなかなか解決しません。何か解決策はあるでしょうか?
2016/08/17 21:12

残りを読む »