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

yumeの日記: メデューサ・ゲーム改・4

日記 by yume

前回の続き。(タイトル変えた)

●壁

さて、パズルの基礎となる要素をどんどん作っていく。
まず、ざっと作っていた「壁」についてもう一度精査しておこう。
壁の役割は:
・Actor(プレイヤーや、同じように歩けるもの)の移動を阻害する
・Light(表現上の視界)を阻害して、影を落とす
・EvilSight(プレイヤーや鏡からの視線)を阻害する
の3つだ。この機能を保ったまま、前作よりも効率よくステージ設計するためにTileMapで行う。
しかし問題がある。

Lightによる影は「ShadowCaster2D」というUnityの試験的機能を利用できる。
これはColliderの形状に合わせて、Light2Dがうまいこと阻害されて影を落としてくれるというバッチリな機能だ。
しかし、残念なことに、これがTileMapで簡単に生成できるTileMap colliderにはいまのところ対応していない。
調べてみると、Unityフォーラムに同じ問題についてのスレッドがあり、TileMap Colliderの形状に合わせて、同じ形状のShadowCaster2Dを生成するスクリプトを公開してくれている人がいた。

ただこれも完璧ではなくて、外壁でステージをドーナツ状にかこった場合、ShadowCasterの形状が正常に生成されないらしい(どうも輪郭だけをとるので、内側の輪郭を大きな箱のように捉えている?)。あるいはそもそも、ShadowCaster2D自体がトーラス形状に対応していないのかも?
でもまぁ、これは大きな問題ではないか。手動で調整するか、あるいは外壁的な概念は個別に作ればよいだろうから。

というわけで、具体的なWallというクラスは用意せず、ShadowCasterとColliderの組み合わせでいったんよしとする。

●邪眼スイッチと扉
パズルゲームの基本といえば、機械仕掛けの扉だろう。というわけでまずは扉を作る。
扉(というか機械式柱)は前回作ってあったアニメーションがあるので、それをまずはそのまま使う。
そして扉はスイッチに連動する。連動する機構の組み合わせについて考えよう。
・スイッチ部。例えばレバーや邪眼スイッチ(見るだけで反応するスイッチ)など。
・機械部。例えば柱や落とし穴など。
これらはそれぞれ異なる組み合わせをとりうるので、SwitchBaseとMechanismBaseを異なる抽象クラスとして定義する。各種メカニズムMechanismBaseを継承し、SwitchBaseを参照する。各種スイッチはSwitchBaseを継承する。

まだ問題がある。「邪眼の影響を受けるかどうか」という概念もまた存在し、それはメカニズム関連とは独立してるけど、メカニズム関係も使う概念なのだ。より下位(上位?)にある概念とも言えるか。
全ての邪眼(プレイヤーや鏡など)は、SeeTargetに対してLineCastすることにしている。すべてのSeeTargetコンポーネントは、ステージ開始時に自分自身を全てのEvilSightコンポーネントに登録し、LineCastが通る(=視界が通る)のを待つ。
これで、邪眼スイッチであろうが兵士であろうが、邪眼の影響を受ける全てのオブジェクトは同じコンポーネントとして扱える。

でも、そうすると、邪眼スイッチはSwitchBaseを継承し、かつSeeTargetを継承したくなってしまう。C#は多重継承はできない。うーむ。

Interfaceを使うといいんだろうか。でも、ここではUniRxを使ってイベント式で作りたい。
つまり、各スイッチはSwitchイベントを持ち、Switchが切り替わるたびにtrue/falseのイベントを発行?する。
各メカニズムは、好きなだけの数のスイッチへの参照を一方的に持ち、そのスイッチのイベントを購読する。
このUniRxイベント(UniRx.SubjectとかIObservableとか)を、Interfaceで定義しようとしてもうまくいかないのだ。
ん〜〜〜。でも、IObservableさえ各メカニズムが受け取れたらいいんだから、例えばスイッチInterfaceはIObservableの参照を渡すメソッドを定義しておけばいいのかな?
でも、それをしたとしても、ただのinterfaceはMonoBehaviourではないので、コンポーネントとして参照できない。つまりUnityエディタ上で参照関係を結びつけることができないので、スイッチとメカニズムを結びつけるのもプログラム上で処理しなければならない。
UnityエディタではInterfaceが扱いづらい。継承にこだわりすぎか。

なので、SeeSwitchはinterfaceを使うのではなく:
・SeeSwitchコンポーネントはSwitchBaseを継承し、
・同じゲームオブジェクトに、SeeTargetコンポーネントをくっつけておき、
・SeeSwitchはそのSeeTargetへの参照を持つ。
としよう。
同じように、SeeTargetなオブジェクトもそれぞれ、SeeTargetを継承するのではなく単に参照を持つように設計する。interfaceを使って無理やり継承迷路を作るよりその方が(少なくともUnity的には)すっきりしているようにも思う。

まとめてみよう。

SwitchBaseは、SwitchのOnOffの切り替えイベントSwitchEventのみを持つ。
実際に切り替えを行う条件などの挙動は、継承先が実装する。
MechanismBaseは、SwitchBaseのイベントを購読し、イベントが発行されたらTrueかFalseに応じて必要な挙動を実行する。実際の挙動は継承先が実装する。
SeeTargetは、邪眼に自身を登録しておいて、邪眼から視界が通る条件を満たすとSeeEventを発行する。

そして:
SeeSwitchはSwitchBaseを継承し、自分のSeeTargetコンポーネントのイベントを購読する。
・SeeEventが発行されたら、SwitchEventを発行する。
PillarMechanismはSwitchBaseへの参照を持ち、SwitchEventを購読する。

動作確認。よさそうだ。

柱の開閉アニメーションと実際の開閉(コライダーの表示切り替え)とラグがあるが、これはアニメーション自体を瞬時にして、余韻のような部分を強調する予定。

typodupeerror

物事のやり方は一つではない -- Perlな人

読み込み中...