Unity:ツインスティックシューターを作ろう!_2:弾の発射とエフェクト

・弾を撃とう

 ツインスティックシューターでは右のスティックを倒すことで狙いを付けるのと同時に弾が自動で発射される。なので右スティックの入力が取れた時に弾のprefabをinstantiateすればいい。弾は生まれた瞬間にdestroy関数で余命を宣告され(安全のため)、あとは毎フレーム決まった速度でまっすぐ前へ飛んでいく。あとは発射の間隔を取るのにクールタイムを設けてその時間が過ぎるまで発射の命令をスキップするようにすればいい。

・当たり判定の設定

スクリーンショット 2021-09-21 004434

 弾は出るようになったが、今はまだ何もない虚空に向けてブッパしているだけだ。当たらなければ意味がない。そこでまずマップの外周に壁を用意した。プリミティブのcubeを伸ばしただけの簡単なものだが勝手にBoxColliderも付いてくるので都合が良い。

スクリーンショット 2021-09-21 004855

 プレイヤーと弾のprefabには球のColliderとRigidbodyのコンポーネントが付けられている。当たったかどうかの判定を取るには、当たるもののどちらかにはRigidbodyが付いてないといけないらしいので、能動的に動くプレイヤーと弾にRigidbodyを設定した。あ、この上の口付きの青い球がプレイヤー自機でオレンジ色の米粒がショットの弾です。弾は遊んだ時の感覚を考慮して見た目よりも判定が大きく取ってある。
 さてこれで弾が飛んでいって他のColliderにヒットしたら、その瞬間を感知する関数の中で弾自身をDestroyする。ひとまず発射して当たって消えるまでの処理は完成する。

    //何かに当たった時の処理
   void OnCollisionEnter(Collision collision)
   {
       //弾は消滅
       Destroy(gameObject);
   }

 ところがそうはうまく行かない。弾を発射した瞬間に、プレイヤーと弾のColliderが接触していて即消えてしまう。そこでLayerを使う。

スクリーンショット 2021-09-21 011343

 Inspectorの右上に付いてるLayer。これでまぁ画面に出てくるものをざっくりとグループ分けするわけだ。一番下のAdd Layer...で項目を追加できる。今回のゲームで必要になりそうな項目を考えながら追加していった。

スクリーンショット 2021-09-21 011622

 このグループ同士が物理演算の計算でぶつかるか、ぶつからないかをPlayerSettingsの中で決められるようになっている。プレイヤーは自分の弾には当たらないけど、敵と敵の弾、あとマップには当たる、みたいな。攻撃の話だけじゃなくてプレイヤーがマップの壁に当たって止まるとかもそう。

スクリーンショット 2021-09-23 122952

 そうそう。プレイヤーと弾に設定したRigidbodyには必要な設定をしなくちゃいけない。見下ろし画面のゲームなのでプレイヤーも弾も地面に対して垂直に動く必要はないからUse Gravityのチェックは外す。
 次いでConstrainsは物理でぶつかった時に変わってもらっては困るものにチェックを入れる。勝手に浮いたり沈んだりしてもらっては困るからPositionのY、あと回転はどの方向に勝手に回られても困るので回転は全て外した。これは試しにチェックを外して、マップの隅っこに押し付けたりすると判りやすいと思う。
 そしてマップにグイグイと押し付けた後、左スティックを離すと、反動でぽーんと放り出されて宇宙遊泳状態になって制御が効かなくなってしまう。これは空気抵抗を触る。設定項目の上の方にあるDragとAngular Dragが初期状態で0になっているので、これを両方ともにInfinity(無限)にする。こうすると壁などに押し返されたものが、即その場で移動も回転も停止する。昔作った時はこのことを知らずに、スクリプトで移動速度と角回転速度を毎フレーム0に上書きしていた。無知!
 ひとまずこれで設定完了だ。弾が撃てて、壁に当たって消えて、プレイヤー自身も壁で止まる。

スクリーンショット 2021-09-23 131110

 余談。Unityはゲームの表示の周期は出力モニターの設定に合うようになっていて、まぁ大抵は60Hz(フレーム)だったりするのかな? それに対して物理演算は毎秒50フレームで動いているのはよく知られてる話なんだけど、試しにこのフレームを60相当にしてプレイしてみると、壁の隅に押し付けてブルブル震えてる時の動きが目に見えて違う。昔よく「Unityのゲームってなんか挙動がショボいんだよな」って言われてた原因の一つは多分これなんじゃないかなと思う。実際、ゲーム制作者の集まるイベントでこのtips話がUnityの人から出たって聞いたような記憶がある。
 更に余談。仕事で製作中のゲームを一時停止していた時にUnityが落ちたことがあって、再起動して見るとゲームが起動しない! 慌てたものの、調べるとエディタでタイムスケールの設定が0に書き換わっていてゲームが進まなくなっていた、ということがあった。めったに起こることじゃないけど、頭の片隅にでも残しておくと助けになるかも。というだけの話。

・エフェクト作るよ

スクリーンショット 2021-09-23 133722

 ショット発射のマズルと当たっ時の粉はパーティクルで作る。マズルの火の画像を一枚用意した位で他はマテリアルそのまんまだ。パーティクルの設定は特に説明なし。複数のパーティクルやらモデルのアニメーションを組み合わせるようなエフェクトでは制御スクリプトを書くか、あるいはタイムラインを使う必要があるかもだけど、今回はやっていない。
 あとはパーティクルをまとめるrootの階層に、時間で死亡するDestroy処理のスクリプトが付けてあるくらい。これらをショットの同じタイミング、何かにヒットしたタイミングでそれぞれinstantiateしているだけだ。

 そんなこんなでここまで完成。

この記事が気に入ったらサポートをしてみませんか?