Unity:ツインスティックシューターを作ろう!_1:入力と移動

スクリーンショット 2021-09-19 000900

・次は何を作ろうか

 ストップウォッチアプリは完成した! 次はゲームっぽいものを作ろう! ということでツインスティックシューターを作ることにした。
 ツインスティックシューターというのはXBOX360のジオメトリウォーズというDL専売タイトルに端を発した2Dシューティングの1ジャンルだ。説明しなくても知ってるよね。基本は見下ろし画面でコントローラーの左スティックで自機を移動させて、右スティックで360度周囲の敵に狙いを付けてショット攻撃する。あとは緊急回避用の全体攻撃(ボム)があるくらいで「撃って避けるだけ」のとてもシンプルなゲームだ。
 バランス調整の妙はともかく、制作に用意する素材量の少なさ&仕様のシンプルさでひとまず形にするまでの手間が圧倒的に少なくて済む。……にもかかわらず、過去に一度作ろうとしてフェードアウトしてしまったので、今度はちゃんと形にしてやろうと思ったわけです。

・入力を取得する

 自機の移動から作り始めることにしよう。手順としては
①:コントローラー/キーボードの入力を取れるようにする
②:入力を自機の移動に反映させる
この2つの処理を完成させればいい。
 ①の入力を取るのに最近(?)Unityに実装された新しいInputSystemを使うことにした。色々と検索して次のサイトを一番の参考にさせて頂いた。

これは今までキーボードやマウスやあるいはコントローラーのボタンだったり、更にはコントローラーが抜けたり差し替えた時の反応まで一つ一つ管理する処理を作らなきゃいけなかったのが、ほぼ大部分をUnity側で担当してくれることになったものらしい。今回の場合でも幾つか設定をするだけで入力の判定や整合性の辻褄合わせはあっという間に完了してしまった。

スクリーンショット 2021-09-19 020021

 まずPackageManagerからInputSystemをインストールして

スクリーンショット 2021-09-19 020113

 PlayerSettingsで新しい入力システムを有効にする。シーン中の適当なオブジェクト(Emptyとか)にPlayer Inputというコンポーネントを付けると扱えるようになる。コンポーネント中のcreate Actionというボタンを押すと「このソフトでは、この動作はこのボタン入力を取るよ」という設定ができる。

スクリーンショット 2021-09-19 020437

 今回のツインスティックシューターでは画像の通りに設定した。ゲームパッドの左スティックとキーボードのwasdで移動、右スティックとカーソルキーで射撃方向を操作する。Lookと名前が付いた操作は本来はカメラ視点の操作を想定しているものだけれど、実際どう使うかは制作者の勝手だ。後はパッドの右トリガーとキーボードのスペースキーをボム用にFireの操作に確保した。Interactionの設定項目はボタンを押した時、離した時、押しっぱなし、2回入力などの判定があるのでボム用ボタンには押した時だけを取得するように設定する。何も設定しないと全部判定を取るっぽい。

・プレイヤーを動かす

 コントローラーの入力を取れるようにしたらプレイヤーを動かせるようにしよう。PlayerInputのコンポーネントから「この入力に対して、このスクリプトのあの命令を実行して」とEventsで指定をする。UIのボタンとかでおなじみのアレだ。

スクリーンショット 2021-09-19 201145

 今回のゲームではプレイヤーのprefabルートに貼り付けられたプレイヤー制御のスクリプト中に入力を受け取る処理を用意して、そこに入力の値を渡している。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;

public class PlayerAction : MonoBehaviour
{
   //キャラ移動用のベクトル
   Vector3 move;
   //キャラ向き用のベクトル
   Vector3 look;

   public void OnMove(InputAction.CallbackContext context)
   {
       //コントローラーなどの入力をVector3に強制代入(x,y,0)
       move = context.ReadValue<Vector2>();
   }

   public void OnLook(InputAction.CallbackContext context)
   {
       //コントローラーなどの入力をVector3に強制代入(x,y,0)
       look = context.ReadValue<Vector2>();
   }

   public void OnFire(InputAction.CallbackContext context)
   {
       if (context.phase == InputActionPhase.Performed)
       {
           Debug.Log("Fire");
       }
   }

   // Update is called once per frame
   void Update()
   {
       const float Speed = 10f;
       //キャラ移動用のベクトルをxyからxzに変換して移動
       transform.Translate(new Vector3(move.x, 0, move.y) * Speed * Time.deltaTime, Space.World);

       //キャラ向き用のベクトルで向きを変える。
       //右ステックが無入力の時z方向に戻ってしまうので、ベクトルの大きさがある値より小さい時は入力をカット
       //この値(0.125)はPlayerSettingsの入力のミニマムデッドの値を直打ち。多分良くない
       if(look.sqrMagnitude > 0.125*0.125)
       {
           transform.rotation = Quaternion.FromToRotation(Vector3.forward, new Vector3(look.x, 0, look.y));
       }
   }
}

 というわけでプレイヤーのスクリプト。言い訳がましい注釈入ってるけどこんな感じでひとまず動いた。ところでベクトル宣言する時ってなんでわざわざnewって付けるんですかね? プログラム1年生なのでわかりません。

 今日はここまで。次は弾を発射させよう。

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