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

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

日記 by yume

メデューサ・ゲーム(仮)

QoLの調整。

--

●ドア改良
ドアを柱に直す工程で、まず「メカニズム」という概念を考え直す。
これまではスイッチはドアにのみ連動するものだったので、スイッチと連携するものはドア前提で作っていたが、その手前に「メカニズム」というもっと抽象的な概念を挟む。
スイッチはメカニズムに電力を追加する。
メカニズムは派生し、派生先は電力が入ったとき、自分に合ったアクションを起こす。例えばドアの場合は、電力が追加された扉を開く。
ドア以外のメカニズムは今のところないが、これで何か追加するときも少し楽になっただろう。

ただ、ちょっと厄介な問題がいくつかあった
・ドアの開閉アニメーションに合わせてColliderを上下させる
>なぜか視界頂点への更新がうまくいかず、視界がゆがんでしまう……。しばらくいじったがどうもダメっぽい。
 うーん、ただ浮遊して動く壁を作ったら、それはちゃんとうまく動いてくれるんだがなぁ。Colliderをアニメーションで持ち上げているのが原因か。
 Colliderをアニメーションでなく関数の中で制御すればうまくいくかもしれないが、ここは単にアニメの適当なタイミングでアクティブ状態を切り替えるとした。
・経路グリッドを更新する
>今回はanimationで経路グリッド更新メソッドを呼び出した。
1. コライダーをオフにする
2. 次のフレームで経路グリッドを更新する
という形で作ると、2度目以降の開閉でグリッドが正しく更新されない。
それとは別にキー入力で任意のタイミングで更新するとうまく動くから、これはアニメーションのタイミングの問題のようだ。
5フレームほど離して経路更新を呼び出すと綺麗に動くようになった。うーん……。なぜだろう。
ともかく、ドアを新たな柱タイプのものにすべて差し替えた。プレハブを綺麗に設定しておけばこの差し替え作業は要らなかったなぁ。

--

●ドア上のアイテムの処理
柱はすげーでっかくなったので、肝心のアイテムに対する処理を変える。
拾うときは:
        ・アイテムの位置にミスティが強制的に移動し、拾う。
        >これはDOTWeenを使うと驚くほど簡単にできた。
置くときは:
        ・ドアのゾーン上だったとしたら、ドアのゾーン外の一番近いところに出てから置く。
        >ドアのゾーンの外の一番近いところ、をどう判別するか……。しかも2方向は壁になっているパターンが多い。
         挙動としては拾うときとそろっていてこれが理想的だが……。
うーん、例えば、柱から上下左右に1マス分離れた各ポイントにColliderがあるかチェックし、Colliderが無いポイントを選んでそこに移動させる……というのはどうか。

/// <summary>
/// プレイヤーがアイテムを配置するとき、ゾーン外の適切な場所を返す。
/// </summary>
/// <returns>SetPotision</returns>
public Vector2 GetSafePoint()
{
        float closestPoint = 10.0f;
        Vector2 safePotision = Vector2.zero;

        //上から時計回りに4箇所探索。

        for (int i = 0; i < 4; i++)
        {
                Vector3 checkPotisionOffset = Vector3.zero;

                if (i == 0) checkPotisionOffset = new Vector3(0.0f, 1.0f, 0.0f); //上
                if (i == 1) checkPotisionOffset = new Vector3(1.0f, 0.0f, 0.0f); //右
                if (i == 2) checkPotisionOffset = new Vector3(0.0f, -1.0f, 0.0f); //下
                if (i == 3) checkPotisionOffset = new Vector3(-1.0f, 0.0f, 0.0f); //左

                Vector2 endPosition = transform.position + checkPotisionOffset;
                RaycastHit2D lineCast = Physics2D.Linecast(transform.position, endPosition, safePointCheckMask);
                if (lineCast.collider == null)
                {
                        float checkDistance = Vector2.Distance(playerBody.transform.position, endPosition);
                        if (checkDistance < closestPoint) //最も近い点を採用する。
                        {
                                closestPoint = checkDistance;
                                safePosition = endPosition;
                        }
                }
        }

        return safePotision;
}

そんで、帰ってきたポジションに向かって0.5秒かけてDOTweenで移動し、同じく0.5秒だけ待って(DOVirtual.DelayedCallを使う)いつものアイテム設置処理を入れる。
テストしたらたまに左にびょんって飛ぶときあるな……。あ、そうか。4点ひとつもとれなかった場合、Vector2.zeroが返ってくるけど、これはステージ中央を意味する。
仮にドアが閉じかけの段階で設置に挑戦して、ドア自身のColliderにLineCastが全部はじかれた場合4点すべて取れないことになる。
safePositionの初期値をありえない値(300.0f,300.0f)にしておいて、そのままこの数値が返ってきた場合は無視するという仕組みにすればいいかな。(あとつづり間違えてるな)

あとドアのアニメーションでコリジョンが出るのにラグができたせいで、ドアに埋まることができるようになってしまった。ちょっとコツがいるし、あまり偶然起きるというたぐいのものではないけど、これもいずれ修正しよう。

--

●ミスティの視界と鏡の視界を差別化
今鏡が見ているエリアと、ミスティが見ているエリアを見分けられるようにしたい。
ミスティの視野エリアのメッシュは鏡と同じようにステンシルの値を渡すが、鏡の視界と違って全くの透明ではなく、ほぼ透明の白を乗せてみよう。
シェーダーはわからんけど、Unityのシェーダーラボのステンシルだけはなんとか理解できた。
ステンシルをチェックするシェーダーは:
MaskRead(視界の模様、乗算つき)
MaskWrite(FOVのメッシュ領域)
MaskWriteWhite(ミスティのFOVのメッシュ領域)
の3つにわける。MaskWriteはシェーダーのバッファに「2」を書き加える。
MaskWriteWhiteは「3」に書き換えて、自分の領域が3未満なら自分の領域に半透明の白を描画する。
MaskReadは1以下の領域にだけ描画する。

--

●新しいステージ
サングラス兵士を使ったステージを作っているが、どうもA*Projectの基本的なパトロールシステムが賢すぎてうまくいかない。
サングラス兵士はもうちょっとおバカにしたいんだけど、パトロールスクリプトをさらに変更するのはちょっと大変。
BGMの件もあって、ゲームのシナリオ部分、第一話を完成させてゲームの基本的な流れすべてを実装したいので、この辺りは後回しにしよう。

今日の分に加えて:
・各ステージの猫獲得のためのUI
・インタラクトキーとかのUIを左下の文字じゃなくて、吹き出し状のUI
ができたら第一話の制作に入ろう。うおー。

この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。
typodupeerror

私はプログラマです。1040 formに私の職業としてそう書いています -- Ken Thompson

読み込み中...