パスワードを忘れた? アカウント作成
14320905 journal
日記

yumeの日記: Unity制作 メデューサ・ゲーム #1

日記 by yume

●メデューサ・ゲーム

寝る前に簡単にゲームのルールを考えた:
・ゲームは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に移す……。すると前回のメッシュのあらぶりが完璧に消えた。よかった~~。

typodupeerror

長期的な見通しやビジョンはあえて持たないようにしてる -- Linus Torvalds

読み込み中...