yumeの日記: Unity制作 メデューサ・ゲーム #1
●メデューサ・ゲーム
寝る前に簡単にゲームのルールを考えた:
・ゲームは2Dで、上から俯瞰したような(見取り図のような)視点、または疑似的な角度のついた(クロノ・トリガーみたいな)視点。
・ステージ上にはメデューサ(プレイヤー)、兵士、猫、壁がある。
・メデューサは:
・2次元の視界を持つ。視界は壁によってさえぎられる(前回までに作ったもの)
・マウスクリックで目標点を指定し、そこまで一定の速度で歩く。
・視界に兵士か猫を3秒間入れ続けると、それを「石化」させる。
・兵士は:
・メデューサよりも足が速い。
・壁にさえぎられていない直線状ならば、メデューサの座標をとらえて接近する。移動速度はメデューサよりも早い。
・メデューサに触れると、1秒後にメデューサを「捕獲」する。
・猫は:
・動かない、または、時々気まぐれな位置にゆっくりと少しだけ移動する。
・勝利条件は2種類(または、ステージによって異なる):
・ステージ上のすべての兵士を石化させる
・ステージの所定の位置まで移動する
・敗北条件は2種類:
・敵に「捕獲」される
・猫を「石化」させてしまう
まずは兵士と猫のベースとなるキャラクターの基盤、Characterプレハブを作ろう。
・壁に対する当たり判定
・移動速度
・メデューサに見られているか、現時点で連続で何秒見られているか。
まずはPlayer同様にRigidBody2D、Collider、SpriteRendererコンポーネントをアタッチ。
このCharacterプレハブをもとに、さらにSoldierのプレハブを作りたい。
公式曰く、
プレハブをいじったものを新たにプレハブに登録すると、
オリジナルプレハブ(新たな独立したプレハブ)か、プレハブバリアント(元のプレハブの影響を受けるプレハブ)を作れるらしい。便利。
さて、Characterは実際に壁にぶつかったりできるようになったが、プレイヤーにぶつかったときはボールのごとく跳ね返るだけだ。
プレイヤーにぶつかった場合は単に衝突するのではなく、何らかの処理(Soldierであれば「捕獲」アクションの開始など)にしたい。
Qiita @nutti曰く、
・衝突時の処理はOnColliosionEnter
公式曰く、
・オブジェクトのコライダーが他のコライダーに衝突したとき呼び出される。
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == Player) //Playerは定数
{
Debug.Log(collision.gameObject.name); //ここでなんかする
}
}
こんな感じだろう。デバッグにもログが返ってくる。Soldierの場合は「捕獲」アクションを開始することだ。
具体的な捕獲アクションは置いておいて、次に、視界に入ったときの「石化」処理を書く。
「視界」は現在、描画はMesh Rendererで行われているが、概念としては単なる座標の集合だ。
使えそうなコライダーは
・MeshCollider
・PolygonCollider2D
だが、どちらを使うべきだろう……。
公式曰く、
MeshCollider.sharedMeshで衝突検出のためのメッシュを指定できる。
すでにメッシュは視界のために生成しているわけだから、これをそのまま反映すればいいんだろうか。一旦そのようにしてみよう。
……。ダメだ。Meshは指定して、Soldier側は「とにかくなんでもCollisionでログを出す」としたが動いていないように見える。
うーん、編集画面を見る限りは、どうやらコライダー自体は作れているようなんだけど……。
Mesh Colliderは2D向けではないのかもしれない。じゃあPolygonColliderで……まてよ。
そもそも、「視界内に入っているCharacter」とは、言い換えると「壁にさえぎられない直線状」であればそれでよいのでは……。
それでいいな。それでいいわ。
・メデューサはすべてのCharacter(=自分を除くすべての動くやつ)への方向に毎フレームRayCastする
・RayCastが壁に当たったら、その分は無視
・Characterに当たったら、当たり続ける限りそいつに「石化メソッド」を実行させる。
・「石化メソッド」は、CharactoerにevilDamageを追加する
・evilDamageがresistPowerを超えたとき、そのキャラクターは石化する
視界がつながった時間をちゃんと算出しなければならない。
Qiita @Nagatch曰く、
・Time.deltaTimeには最後のフレームからの経過時間(ms)が格納されている。
これを足し続ければいいか。さて実際にRayCastを飛ばして困ったのは、
前回はLinecastして当たる対象は「レイヤーマスク」でPolyWallレイヤーにあるものだけを指定したが、
今回は壁とCharacter両方を検出しなければならない。
まぁ、Characterのレイヤーを「PolyWall」にすればいいわけだが、ちょっとマヌケっぽいやり方だ。
stackoverrun.com @Programmer曰く、
public int playerLayer = 9;
int layerMask = ~(1 << playerLayer); //Exclude layer 9
で「9」を除いたintを返せる、ということらしいがこの書き方は初めてみた。
今はちょっと時間がないので明日調べよう。
日記を読み返したりしてふと気づいたが、Update()とFixedUpdate()が2D Visibilityスクリプトの中で正しく使い分けできえてなかったような。
視界関係はUpdate()に入っていたので、FixedUpdateに移す……。すると前回のメッシュのあらぶりが完璧に消えた。よかった~~。
Unity制作 メデューサ・ゲーム #1 More ログイン