ラベル 2Dアクションゲーム の投稿を表示しています。 すべての投稿を表示
ラベル 2Dアクションゲーム の投稿を表示しています。 すべての投稿を表示

2014年11月4日火曜日

敵を発生させるスクリプト

またも間が空いてしまった。ブログの記事に時間を割くよりは制作を優先したらこうなった。今回は Nostalgia のマップに配置したタイルの ID に対応する敵をタイルの位置に発生させるスクリプトを晒す。マップコンポーネントを追加したゲームオブジェクトに以下のスクリプトを追加して使う。例によって品質は KS だ。

using UnityEngine;
using System.Collections;
using Nostalgia;

public class EnemySpawner : MonoBehaviour
{
  [SerializeField] private GameObject[] enemyPrefabs;
  private Map enemySpawnerMap;
  private Vector3[] tilePositions;
  private int[] tileIds;
  private Cell[] cells;

  void Start ()
  {
    enemySpawnerMap = GetComponent<Map> ();
    cells = enemySpawnerMap.cells;
    tilePositions = new Vector3[cells.Length];
    tileIds = new int[cells.Length];
    for (int i = 0; i < cells.Length; i++) {
      tilePositions[i] = enemySpawnerMap.MapPointToWorldPoint (cells[i].position);
      tileIds [i] = cells [i].tileID;
    }
    StartCoroutine (SpawnEnemy ());
  }

  IEnumerator SpawnEnemy ()
  {
    while (true) {
      for (int i = 0; i < cells.Length; i++) {
        bool b1 = true; // 待ち時間以外の敵インスタンスの出現条件を書く
        bool b2 = true; // 敵インスタンスの向き変更条件を書く
        if (b1) {
          GameObject enemyInstance = (GameObject)Instantiate (enemyPrefabs [tileIds[i]], tilePositions[i], (b2 ? Quaternion.identity : Quaternion.Euler (0f, 180f, 0f)));
        }
      }
      yield return new WaitForSeconds (5f); // 待ち時間
    }
  }
}

敵の種類だけ異なるタイルを作るわけだが、全部透明の同じグラフィックにするとインスペクターなしで区別できない。これでは扱いづらいのでどうしたものか。それにしても Tile Component の使いどころがわからんな〜。

2014年9月25日木曜日

DRN.008 エレキマンの行動パターンを考える。

まえがき

連載第6回はエレキマンを取り上げる。ちょっとよくわからない。

エレキマン本体の行動パターン

  • 非負の整数を k として、移動した回数 n が n = 4 * k のとき
    1. 部屋の右側へ移動
  • 非負の整数を k として、移動した回数 n が n = 4 * k + 1 または n = 4 * k + 3のとき
    1. 部屋の中央に移動
  • 非負の整数を k として、移動した回数 n が n = 4 * k + 2 のとき
    1. 部屋の左側に移動/li>
  • 特定の x 座標に到達したとき
    1. サンダービームを発射
  • 自機がショットしたとき
    1. ジャンプする。
  • 壁に接触したとき
    1. ジャンプする。
  • 被弾したとき
    1. 行動をキャンセルし、ノックバック
    2. 一定時間無敵になる

こちらから攻撃しない限りはアイスマンと同様に部屋の右側、中央、左側を行ったり来たりしながら、指定 x 座標に到達するとサンダービームを発射する。ガッツブロックに引っかかったり、ノックバックさせたりで指定座標への到達できないとくり返し同じ座標に向かおうとするので、どうやら指定座標に到達してはじめて次の目標地点が変わるようだ。

サンダービームの行動パターン

  • 発射されたとき
    1. 直線運動
    2. 自機に当たると拡散

攻略法

サンダービームの予備動作中にタイミングよくショットを当てると、ハメられる。エレキマンステージ、ワイリーステージ2の両方で可能。動画を参照。

Defeat ELEC MAN without walking, jumping from hide behind on Vimeo.

あとがき

ハメると初期位置から一歩も動かずに撃破することもできるが、高火力のアイススラッシャーを上回る超火力のため事故りやすい。ノックバックするのが唯一の救い。

2014年9月24日水曜日

DRN.007 ファイヤーマンの行動パターンを考える。

まえがき

連載第5回はファイヤーマンを取り上げる。fireman は消防士のことなんだが、コイツは廃棄物処理ロボットである。

ファイヤーマン本体の行動パターン

  • 自機との距離が一定以上のとき、一定確率で?
    1. 自機の方を向いてファイヤーストームを撃つ
  • 壁に接触したとき
    1. 向き反転
  • 被弾したとき
    1. 一定時間無敵になる
    2. 自機の方を向いてファイアーストームを撃つ
  • 上記以外のとき
    1. 移動

離れているとファイヤーストームを撃ってくるが、間合いを詰めたままだと攻撃しない限りは移動するだけである。攻撃すると ファイヤーストームで反撃する。

ファイヤーストームの行動パターン

  • 発射されたとき
    1. 自機狙い、直進
    2. 自機足下に火がしばらく残る。

攻略法

ファイヤーマンステージでは、ある程度距離を詰めてファイヤーストームを封じつつ、ショットとジャンプを同時押しでジャンプショット、着地直後にまたジャンプショットのくり返しでハメられる。

ワイリーステージ4はワープカプセルがあって部屋が狭い。ワープカプセルの外に出て同様にする。

Defeat FIRE MAN with ROCK BUSTER from hide behind on Vimeo.

あとがき

攻撃面ではとにかく撃ちまくればよかった他のボスに対するアンチテーゼとでもいう位置づけか、弱点を衝けばゴリ押し可能なこのゲームでは珍しく、弱点を衝いてもパターンを無視してゴリ押ししようとすればゴリ押し返されることがある。また、なるべく敵から離れるという定石が裏目に出るのも嫌らしい。

2014年9月23日火曜日

ミサイルは渡り移るもの。

『ロックマン』の6ボスまで予約投稿にしたのでここで一段落。制作中のゲームの動画をさらす。

ミサイル渡りjump from one missile to another. from hide behind on Vimeo.

ミサイルからミサイルへ飛び移っているのは全部敵キャラクターなのだが、敵キャラクターのグラフィックがまだないのでプレイヤーので代用。プレイヤーキャラクターはミサイルにぶら下がっているやつ。ぶら下がり状態で左右に移動できるのだが、グラフィックがまd (以下略)。爆煙やらバックファイアを書きたいが、デカいのを書くと目障りになってしまうのをどうしたらよいかな。

そんなつもりはなかったが、クラウド・ストライフと同じようなカラーリングになっちゃった。イメージイラストもなくいきなり雑なドット絵打っているので、こうしてさらしておいたらエレガントなイラストを誰か書いてくれたりしませんかネェ。プレイヤーのドット絵もまだまだ足りない。被弾時のとぶら下がり移動、壁張り付きと壁張り付き移動は 最低でも必要だ。

DRN.006 ボンバーマンの行動パターンを考える。

まえがき

連載第4回はボンバーマンを取り上げる。ボンバーマンといってもハドソンのアレではない。というか今やハドソンって (会社) (ブランド) もなくなってしまったのか。何てことだ。ボンバーマンはスーパーファミコンで出た『スーパーボンバーマン』、『スーパーボンバーマン 2』、『スーパーボンバーマン 3』、『ぱにっくボンバー W』のソフトウェアだけでなくボンバーマンの顔のデザインのスーパーマルチタップ2も持っていたし、裏ステージを出すためだけにスーパージョイカードも買ったというのに。その他にも、ハドソンのソフトウェアでは『高橋名人の冒険島 Ⅱ』、『スーパー桃太郎電鉄 DX』、『アースライト 2・ルナストライク』、『ゲームボーイウォーズ 3』、『NECTARIS』のPlayStation 版、iPhone 版も買ったナー。脱線が過ぎた。

ボンバーマン本体の行動パターン

  • 一定確率で
    1. ハイパーボムを投げる。
    2. 一定確率でさらにハイパーボムを投げる。
    3. 一定確率でさらにハイパーボムを投げる。
  • 一定確率で
    1. 自機に向かって小ジャンプ
  • 一定確率で
    1. 自機に向かって大ジャンプ
  • 被弾したとき
    1. 一定時間無敵になる

ハイパーボムの行動パターン

  • 発射されたとき
    1. 自機狙い、放物線運動
    2. 接地すると爆発

ジャンプをこれにも流用できそうだ。

攻略法

ボンバーマンの小ジャンプ、大ジャンプは下をくぐれるので端に追いつめられないように適宜下をくぐって切り返す。ハイパーボムの爆風の範囲が広いので x 座標を大きくずらすと躱しやすいが、連続で投げてくることもあるので大きく逃げ過ぎて端に追いつめられないように。タイミングがよければジャンプでも避けられる。

ワイリーステージ4はワープカプセルがあって部屋が狭い。ワープカプセルの外に出て同様にする。

あとがき

ジャンプの大小は自機との距離だトカ被弾しただトカが関係していそうな気もするんだけどよくわからんので確率依存にした。困ったときは確率依存、確率依存万能説。あー、でもそれにしたおかげで内心「こっちくんな」と思いながら戦うことになるので業が深いな。このボンバーマンには関係ないけども。

2014年9月22日月曜日

DRN.005 アイスマンの行動パターンを考える。

まえがき

連載第3回はアイスマンを取り上げる。パターンが見え見えなので余り面白くないな。

アイスマン本体の行動パターン

  • 非負の整数を k として、移動した回数 n が n = 4 * k または n = 4 * k + 3 のとき
    1. 右に向かって前進
  • 非負の整数を k として、移動した回数 n が n = 4 * k + 1 または n = 4 * k + 2 のとき
    1. 左に向かって前進
  • 移動した後
    1. ジャンプ
    2. 自機の方を向いて等速で下降しながらアイススラッシャーを発射 * 3
    3. 自機の方を向いて等速で上昇しながらアイススラッシャーを発射 * 3
    4. 落下
  • 被弾したとき
    1. 一定時間無敵になる

各行動パターンが単純でパターン変更に確率が関係ない。パターン変更が確率だけに依存するガッツマンよりもさらに大味な感じがする。ジャンプ・落下は放物線運動、上昇・下降は等速直線運動を表現したつもり。ジャンプの頂点、着地点でパターン切り替えれば OK ね。

アイススラッシャーの行動パターン

  • 発射されたとき
    1. 直進
    2. 6 * n 発?撃つごとに弾速がアップ

攻略法

アイスマンステージでは床が滑る床なので多少動かしづらいが、慣れれば後方に滑って距離をかせぎながら前方に攻撃できる。部屋の端でア イススラッシャーをかわしながら 攻撃するだけ。アイススラッシャーは下をくぐれるが上を飛び越えることができない上段、下をくぐることもできれば上を飛び越えることもできる中段、下をくぐれず上を飛び越えるしかない下段の3種類があり、上段、中段、下段、下、中段、上段の順に撃ってくるので、適当にかわす。アイススラッシャーは撃てば撃つ程速くなるので早期に決着をつけるとよい。

ワイリーステージ4では床が滑らず、 ワープカプセルがあって部屋が狭い。ワープカプセルの外に出て同様にする。

あとがき

AI 的にはかなり単調なアイスマンだが、アイススラッシャーは高火力なので意外と強敵。アレだ。力こそパワー。

2014年9月21日日曜日

DRN.004 ガッツマンの行動パターンを考える。

まえがき

連載第2回は DRN.004 ガッツマンを題材にする。便宜上、自機が特殊武器スーパーアームで持ち上げられるブロックをガッツブロック (P) 、ガッツマンが投げるブロックをガッツブロック (E) とする。

ガッツマン本体の行動パターン

  • 一定確率で
    1. 前方にジャンプ
    2. 着地時に地震が発生し、地上にいる自機を転ばす。
    3. 揺れが収まるまで待機。
  • 一定確率で
    1. 後方にジャンプ
    2. 着地時に地震が発生し、地上にいる自機を転ばす
    3. 揺れが収まるまで待機。
  • 一定確率で
    1. 垂直にジャンプ
    2. 着地時に地震が発生し、地上にいる自機を転ばす
    3. 揺れが収まるまで待機。この間にガッツマンの頭上の天井からが降ってきたガッツブロック (E) を受け止める
    4. 自機を狙ってガッツブロック (E) を投げる
  • 被弾したとき
    1. 一定時間無敵になる

行動パターンの切り替えは確率だけなので単純。一連の行動が終わったらフラグを立てて、フラグが立っていたら乱数を生成してその値に応じて状態遷移。カットマンの場合、ジャンプの頂点でローリングカッターをねじ込む必要があったが、ガッツマンでは着地時に地震等をねじ込む必要がある。その他、被弾したときも一定時間無敵になるのは同じだが、行動パターンには影響がないので、前3つのパターンとは別レイヤーになっているとでもいうべきか。カメラを揺らしたり、自機を転ばしたりと、本体とその武器以外に直接影響を与えるのも特徴だ。

ガッツブロック (E) の行動パターン

  • ガッツマンが垂直にジャンプしたとき
    1. ガッツマンの頭上の天井から落下
  • ガッツマンに投げられたとき
    1. 自機に向かって直進
  • 地面に当たったとき
    1. 4つの破片に分かれ、破片のうちの2つは水平方向に直進し、残り2つは斜め上45°の方向に直進する

攻略法

ガッツマンステージではシャッター際に高台とガッツブロック (P) があるのでこの上で戦うとよい。地震はガッツマンが着地した瞬間からしばらくの間続くので、この間ジャンプで空中にいれば巻き込まれない。もちろん地震に巻き込まれないようにジャンプできるならそのほうがよいが、下手にジャンプすると地震で転ぶのが遅れ、転び状態から復帰するのも遅れてガッツブロック (E) や体当たりでダメージを受けてしまうので、ガッツマンとの距離があるときは敢えてジャンプしないで最速で転び復帰するのも手だ。ガッツブロックはガッツマンの頭の高さから自機の足下に向かって飛ぶ。高台やガッツブロック (P) の上にいると画面中央側のガッツブロック (P) の際で分裂することが多いのでシャッター際よりはある程度画面中央に寄ったほうがよい。ガッツマンに距離を詰められるかどうかは運なのだが、一応ガッツマンのジャンプをくぐることはできる。

ワイリーステージ4には高台等がないので前述の戦法は使えない。まずは天井の低いカプセルの外に出て高くジャンプできるようにする。地震は上と同様に対応する。ガッツブロック (E) が地面に当たって分裂するポイントでジャンプするとかわしやすいわけだが、ガッツブロック (E) は自機の足下狙いなのでふつうにタイミングジャンプすればいいことが多い。部屋が狭くなっている分、プレイヤーの運が試される (ぉ

あとがき

ガッツマンのように単純なパターンでパターン変更も完全に確率で制御にだとものすごく大味な気がするな。ジャンプは頂点と着地時にフックポイントを仕込んでおけばカットマンとガッツマンで共通化できそうだ。

2014年9月18日木曜日

DRN.003 カットマンの行動パターンを考える。

まえがき

2Dアクションゲームの敵の AI とでもいうべきものを作りたい。これまで赤ノコノコ等比較的単純なものをつくってきたが、もっと複雑なものをどうやって作るのか。これまで同様の単純な行動パターンの上位に、条件に応じてどれを実行するかを指示する制御があればいいかな。

面白い行動パターンがすぐに思いつくわけもないし、制作中のそれをここでネタバラシしてしまうのもアレなので、『ロックマン』シリーズのボス敵がどうなっているのか取り上げよう。1-7 まではやったから、これでしばらくはネタに困らないね。ヤッター。というわけでカットマン (FC版) の行動パターンを分析してどういう制御をすればいいのか考える。 当然のことながら、以下の行動パターンは外観上でしかないので実際とは違う。悪しからずご了承ください。

カットマン本体の行動パターン

  • 自機との距離 (X軸) が一定以上あるとき
    1. 自機に向かって歩く。
  • 自機との距離が一定未満のとき
    1. 軌道修正できないジャンプ。
    2. ジャンプの頂点付近で画面上にローリングカッターがなければ、一定の確率? でローリングカッターを投げる。
  • 被弾したとき
    1. 行動をキャンセルしノックバックし、短時間無敵状態になる。
    2. 立ち止まって、チョッキンチョッキン。
    3. 画面上にローリングカッターがなければローリングカッターを投げる。

大きく分けて 3 つのパターンがあり、自機との距離、被弾がトリガー。思いつきだけで KS コードを書いてみる。


using UnityEngine;
using System.Collections;

public class CutMan: MonoBehaviour
{
  bool counterAttackFlag = false;

  // 画面外のどこかにローリングカッターを隔離
  Vector3 positionOfOuterScreen = - Vector3.one;

  // Jump, Walk 切り替えの閾値
  float xThreshold = 5;
  Transform thisTransform;
  Transform playerTransform;
  enum ActionPattern
  {
    CounterAttack,
    Jump,
    Walk,
  };
  ActionPattern currentActionPattern = ActionPattern.Walk;
  bool switchActionPatternFlag = false;

  void Start ()
  {
    thisTransform = transform;
    playerTransform = GameObject.FindWithTag ("Player").transform;

  }

  void FixedUpdate ()
  {
    if (switchActionPatternFlag) {
      SwitchActionPattern ();
    }
    DoActionPattern ();
  }

  void SwitchActionPattern ()
  {
    Vector3 displacementFromThisToPlayer = playerTransform.position - thisTransform.position;
    float xDistance = Mathf.Abs (displacementFromThisToPlayer.x);
    float xDistanceMinusXThreshold = xDistance - xThreshold;
    
    if (counterAttackFlag) {
      currentActionPattern = ActionPattern.CounterAttack;
      counterAttackFlag = false;
      switchActionPatternFlag = false;
    } else if (xDistanceMinusXThreshold >= 0) {
      currentActionPattern = ActionPattern.Walk;
      switchActionPatternFlag = false;
    } else {
      currentActionPattern = ActionPattern.Jump;
    }
  }

  void DoActionPattern ()
  {
    switch (currentActionPattern) {
      case ActionPattern.CounterAttack:
        CounterAttack ();
        break;
      case ActionPattern.Jump:
        Jump ();
        break;
      case ActionPattern.Walk:
        Walk ();
        break;
    }
  }

  void CounterAttack ()
  {
    // ImplementMe
  }

  void Jump ()
  {
    // ImplementMe
  }

  void Walk ()
  {
    // ImplementMe
  }

  void OnTriggerEnter2D (Collider2D other)
  {
    if (other.tag == "PlayerBullet") {
      counterAttackFlag = true;
      switchActionPatternFlag = true;
    }
  }
}

パターン別のスクリプトを作って、その .enabled をこのスクリプトのswitch 文中で呼ばれるメソッドから操作するように書けばいいかな。色々書き足りないけどまた後日にでも加筆するとしよう。

ローリングカッターの行動パターン

カットマンの武器、ローリングカッターの外観上の行動パターンを以下に示す。例によって外観上のパターンで実際とは異なる。

  1. 自機狙いの射角で画面端まで直進
  2. 本体狙いで角度修正しつつ移動。本体が撃破されたときはそのまま直進。
  3. 本体に接触すると消滅

こんなところか。疲れたのでこっちは全部省略 (ぇ。

攻略法

せっかくだから攻略法も書いておく。どうやったら倒せるかも考えておかないと、『カイザーナックル』のジェネラルみたいに好き放題やったら、普通の人には倒せなくなってしまう。ところで『カイザーナックル』はいつ家庭用ゲーム機に移植されるんだろう。

カットマンステージのボス部屋には高台とガッツブロックがある。高台のシャッター際に陣取り、ローリングカッターをジャンプでかわしながら、飛びかかってきたカットマンを撃ち、下の床に落とす。自機の近くまで飛び込まれた場合、カットマンが下の床に落ちないで高台に残ることがあるが、被弾後の無敵時間終了直後に被弾させるようにしてたたき落とす。

ワイリーステージ2の道中の小部屋には高台がないので前述の戦法は使えない。行動キャンセル狙いでカットマンを攻撃。敵の無敵時間中にチョッキンチョッキンしはじめるので、無敵解除直後にヒットするのを狙って攻撃しつつ、行きのローリング・カッターを (自機が画面際の場合、画面中央へ向かって) ジャンプしてかわす。帰りのローリング・カッターはジャンプしたカットマンに連られて軌道修正されるので垂直ジャンプではなくカットマンから遠ざかるようにジャンプしてかわす。

2014年9月11日木曜日

賽の河原で小石を積み上げる単純作業

やはり雑談よりは開発ネタを書くべきなのか。記事を書かない日も KS コードを書いては調整と見直しをやっている。どのように動いて欲しいかは割とハッキリしているが、プログラミング自体は手探りなので、できたコードは KS ばかりで手戻りが多い。とはいえ、例え KS コードでも少なくとも 2, 3 作ってみないことには多少なりとも再利用できそうなものの作り方が見えてこないのでやるしかない。

制作中のゲームでは、今のところ、キー入力に応じて動くプレイヤー、行き先の足場がなくても進む、壁際で反転する敵 (マリオにおける緑ノコノコに相当)、行き先の足場がないまたは壁際で反転する敵 (マリオにおける赤ノコノコに相当)、行き先の足場がないとジャンプ、壁際で反転する敵 (何かあったっけ?) 等を作った。もっと複雑な行動パターンを作りたい。

なお、キャラクターの座標計算には、下記のサイトを参考に、velocity Vertlet 法を用いた。

参考資料

  1. みその計算物理学. "velocity Verlet法(PDF形式)". みその計算物理学. http://www.geocities.jp/supermisosan/moleculardynamics/velocityverlet.pdf, (参照 2014-09-10)
  2. T. Koishi. "数値積分の実行". Koishi's Page. http://polymer.apphy.u-fukui.ac.jp/~koishi/lecture/md_program5/, (参照 2014-09-10)

2014年9月6日土曜日

下からすり抜けて上に乗ることができる床の実装例 (Unity C#) Nostalgia (Version 1.0.2) 対応版

Nostalgia (Version 1.0.2) では前回示したようなコライダーごとにスクリプトを付ける手法は使えないようなので、プレイヤーの近傍のセルを調べてcollider.enabled を切り替える方法にした。

図で示すとこういう感じ。画像の赤色のセルはプレイヤーのいるセル、緑色のセルは、中にコライダーがあれば collider.enabled = false にするセル、青色のセルは、中にコライダーがあれば collider.enabled = true にするセルを示す。

KS コードを公開するよ。コメントをつけたやたらに長い名前の3つの変数の値をお好みで適当にいじればいいんじゃないかな。


using UnityEngine;
using System.Collections;
using Nostalgia;

public class NostalgiaColliderEnabledSwithcher : MonoBehaviour
{
  Transform playerTransform;
  Map map;
  Vector3 playerPosition;
  int numberOfHalfOfHorizontalCells;

  // 中にコライダーがあれば collider.enabled の値を変更するセル (図の青色または緑色のセル) の水平方向の数。
  int numberOfHorizontalCells = 7;
    
  // 中にコライダーがあれば collider.enabled = false にするセル (図の緑色のセル) の垂直方向の数。
  int numberOfVerticalCellsEachOfWhichMayHaveColliderToBeDisabled = 6;
    
  // 中にコライダーがあれば collider.enabled = true にするセル (図の青色のセル) の垂直方向の数。
  int numberOfVerticalCellsEachOfWhichMayHaveColliderToBeEnabled = 1;
  Point2[] offset1;
  Point2[] offset2;

  void Start ()
  {
    playerTransform = GameObject.FindGameObjectWithTag ("Player").transform;
    map = GetComponent <Map> ();
    numberOfHalfOfHorizontalCells = (numberOfHorizontalCells - 1) / 2;
    offset1 = new Point2[numberOfHorizontalCells * numberOfVerticalCellsEachOfWhichMayHaveColliderToBeDisabled];
    for (int i = 0; i < numberOfHorizontalCells; i++) {
      for (int j = 0; j < numberOfVerticalCellsEachOfWhichMayHaveColliderToBeDisabled; j++) {
        offset1 [numberOfVerticalCellsEachOfWhichMayHaveColliderToBeDisabled * i + j] = new Point2 (i - numberOfHalfOfHorizontalCells, j);
      }
    }

    offset2 = new Point2[numberOfHorizontalCells * numberOfVerticalCellsEachOfWhichMayHaveColliderToBeEnabled];
    for (int i = 0; i < numberOfHorizontalCells; i++) {
      for (int j = 0; j < numberOfVerticalCellsEachOfWhichMayHaveColliderToBeEnabled; j++) {
        offset2 [numberOfVerticalCellsEachOfWhichMayHaveColliderToBeEnabled * i + j] = new Point2 (i - numberOfHalfOfHorizontalCells, - 1 - j);
      }
    }
  }
  
  void FixedUpdate ()
  {
    playerPosition = playerTransform.position;
    Point2 mapPointOfPlayerPosition = map.WorldPointToMapPoint (playerPosition);

    Point2 [] listOfPoint2InCellWhichMayHaveColliderToBeDisabled = new Point2[numberOfHorizontalCells * numberOfVerticalCellsEachOfWhichMayHaveColliderToBeDisabled];
    for (int i = 0; i < numberOfHorizontalCells; i++) {
      for (int j = 0; j < numberOfVerticalCellsEachOfWhichMayHaveColliderToBeDisabled; j++) {
        listOfPoint2InCellWhichMayHaveColliderToBeDisabled [numberOfVerticalCellsEachOfWhichMayHaveColliderToBeDisabled * i + j] = mapPointOfPlayerPosition + offset1 [numberOfVerticalCellsEachOfWhichMayHaveColliderToBeDisabled * i + j];
      }
    }
    foreach (Point2 p in listOfPoint2InCellWhichMayHaveColliderToBeDisabled) {
      SwitchColliderEnabled (p, false);
    }

    Point2[] listOfPoint2InCellWhichMayHaveColliderToBeEnabled = new Point2[numberOfHorizontalCells * numberOfVerticalCellsEachOfWhichMayHaveColliderToBeEnabled];
    for (int i = 0; i < numberOfHorizontalCells; i++) {
      for (int j = 0; j < numberOfVerticalCellsEachOfWhichMayHaveColliderToBeEnabled; j++) {
        listOfPoint2InCellWhichMayHaveColliderToBeEnabled [numberOfVerticalCellsEachOfWhichMayHaveColliderToBeEnabled * i + j] = mapPointOfPlayerPosition + offset2 [numberOfVerticalCellsEachOfWhichMayHaveColliderToBeEnabled * i + j];
      }
    }
    foreach (Point2 p in listOfPoint2InCellWhichMayHaveColliderToBeEnabled) {
      SwitchColliderEnabled (p, true);
    }
  }

  void SwitchColliderEnabled (Point2 givenPoint2, bool b)
  {
    Cell cellOfGivenPoint2 = map.GetCell (givenPoint2);
    if (cellOfGivenPoint2 != null) {
      Collider2D colliderOfCell = cellOfGivenPoint2.collider;
      if (colliderOfCell != null) {
        colliderOfCell.enabled = b;
      }
    }
  }
}

使用した Nostalgia の Version 1.0.2 を追記した。 2014-09-25

2014年9月4日木曜日

下からすり抜けて上に乗ることができる床の実装例 (Unity C#)

すり抜け床の基本的な考え方は参考資料 1 のサイトを参考にした。角度で切り分けるのが面倒だったので y 座標でざっくり切り分けることにした。

KS コードは以下。すり抜け床にしたいゲームオブジェクトにアタッチして使う。


using UnityEngine;
using System.Collections;

public class ColliderController : MonoBehaviour
{
  Transform playerTransform;

  void Start ()
  {
    playerTransform = GameObject.FindGameObjectWithTag ("Player").transform;
  }

  void FixedUpdate ()
  {
    float f = playerTransform.position.y - thisCollider.bounds.max.y;
    if (f <= 0) {      
      collider2D.enabled = false;
    } else {
      collider2D.enabled = true;
    }
  }
}
  1. 株式会社スマイルブーム. "「すり抜け床」を考えてみる". スマイルブーム.com http://smileboom.com/blog/tkool/throughfloor.html, (参照 2014-09-02).