monoの開発ブログ

アクションゲームを作ろう

アクションゲームの試作品を作ってみました。

緑の■を操作して青いゴールまで進むゲームです。カーソルキーの左右で移動、上でジャンプできます。

スクリーンショット

アクションゲームが得意な人ならそれほど苦労しない難易度なんじゃないかと思います(適当)。

技術的なこと

Processing

開発にはProcessingを利用しました。ProcessingはJavaっぽい言語に簡単にグラフィックを扱うための関数を追加したようなツールで、今回作ったようなミニゲームをサクサク書くことができます。作成したプログラムはJavaアプレットやスタンドアローンなJavaアプリケーションとして出力できるほか、JavaScriptを利用した処理系も用意されており、幅広い環境で動作させることができます。

Verlet法

キャラクタの動作にVerlet法のような考え方を用いています。普通、キャラクタの状態というと位置と速度で管理すると思いますが、Verlet法では位置と前フレームでの位置を用いてキャラクタを管理します。キャラクタを動かすときは、前フレームでの位置と現在の位置から速度を計算し、それに応じて動きます。

一見回りくどいように思えますが、ゲーム開発においてはとても大きな利点があります。それは、位置を直接いじることができるということです。

位置と速度でキャラクタを管理した場合、位置を直接書き換えても速度はそのままであるため、動きが破綻してしまいます。一方、Verlet法では位置を変更するとそれに応じて位置から求められる速度も変動するため、動きが破綻しません。もちろん物理的に正しい動きにはならないのですが、開発者の都合で位置を直接書き換えてもそれっぽく動いてくれるのはありがたいですね。

以下の例では、キャラクタの移動をVerlet法を用いて実現しています。ポイントは当たり判定部分で、天井にめり込んだ場合に直接位置を書き換えています。この程度であればどのように実装しても大して苦労しないのですが、複数のオブジェクトの拘束などを真面目に考えだすととても厄介なので、Verlet法が役に立つのではないでしょうか。

// マップ
int[][] map;

// 現在の位置と前フレームの位置のみを保持
float x, y;
float prev_x, prev_y;

for(; ; ) {

  // 速度は前フレームの位置を利用して求める
  float vx = x - prev_x;
  float vy = y - prev_y;

  // このフレームでの加速度を計算する
  float ax = -K * vx; // 空気抵抗
  float ay = -K * vy + G; // 空気抵抗+重力
  if(左キーが押された) { ax -= A; } // キー入力による加速
  if(右キーが押された) { ax += A; }
  if(ジャンプ中である) { ay -= B; } // ジャンプ

  // 速度に加速度を加算
  vx += ax;
  vy += ay;
  // 移動前の座標を記憶
  prev_x = x;
  prev_y = y;
  // 速度だけ移動
  x += vx;
  y += vy;

  // 上方向の当たり判定
  if(vy < 0) {
    // 自分の頭のセル単位の位置を計算
    int ix = (int)((x + CHARACTER_SIZE / 2) / CHARACTER_SIZE);
    int iy = (int)((y - 1) / CHARACTER_SIZE);
    // 天井に衝突していた場合
    if(map[ix][iy] == WALL) {
      // 天井にめり込まないように移動
      y = (iy + 1) * CHARACTER_SIZE;
    }
  }

}

参考