前回、プレイヤーキャラクターのアニメーションの設定を行いました。しかし、まだプレイヤーを動かすためのC#スクリプトを書いていないので、このままではプレイヤーキャラは動きません。
そこでここではプレイヤーキャラクター用のC#スクリプトを書き、キャラクターが動くようにしていきます。
キャラクター用スクリプトの基本的な処理内容とその流れ
ただ、いきなりスクリプトを載せて「こうしてください」と言っても初心者の方には分かりづらいと思いますので、まずは「アクションゲームのキャラクター用のスクリプトの基本的な処理内容とその流れ」をサラッと説明しておきましょう。
個人的なやり方ではありますが、私がアクションゲームのプレイヤーキャラを作るときは次のような処理を書くことが多いです。
- 初期化用の処理
- ボタンなどの入力処理(Updateから呼び出し)
- アニメーションの更新処理(Updateから呼び出し)
- 物理演算の処理(FixedUpdateから呼び出し)
- ダメージ・死亡処理
- 接地判定
処理の流れとしては次のような感じです。
- Startでリジッドボディ等のコンポーネントを取得して、変数にキャッシュしておく。
- Updateで入力・アニメーションの更新を行う。
- FixedUpdateで物理演算・接地判定を行う。
- 途中でダメージ処理用メソッドが呼び出されたら、HPを減らすなどの処理を行う。もしHPが0になったら死亡処理を呼び出し、他の処理を停止する。
なお、アクションゲームのプレイヤーキャラのスクリプトを書くときには気をつけるべきことがあります。それはUpdateとFixedUpdateの使い分けです。プレイヤーキャラではよく「入力」と「物理演算」の処理を行いますが、
- 入力処理:Updateから呼び出す
- 物理演算の処理:FixedUpdateから呼び出す
という風に使い分けるようにしてください。
何でそういう風に使い分ける必要があるのか?という理由まで書くと長くなるのでググってもらいたいのですが、簡単に言うと両者は呼び出されるタイミングが違うので、処理ごとに適切なタイミングで呼び出されるようにする必要があるというわけです。
プレイヤーキャラクター用のC#スクリプト
さて、前置きが少し長くなりましたがここからプレイヤーキャラ用のC#スクリプトを書いていきましょう。Assets直下の「Scritpts」→「Character」フォルダ内に新しいC#スクリプトを作り、名前を「PlayerController」にして次のスクリプトを書いてください。
using System.Collections; using System.Collections.Generic; using UnityEngine; [RequireComponent(typeof(Rigidbody2D))] [RequireComponent(typeof(SpriteRenderer))] [RequireComponent(typeof(Animator))] public class PlayerController : MonoBehaviour { [SerializeField] string jumpButtonName = "Jump"; [SerializeField] float speed = 0; [SerializeField] float jumpPower = 30; [SerializeField] Transform[] groundCheckTransforms = null; bool isActive = false; bool jump = false; bool isGrounded = false; Animator animator; SpriteRenderer spriteRenderer; Rigidbody2D rigidBody2D; void Start() { animator = GetComponent<Animator>(); spriteRenderer = GetComponent<SpriteRenderer>(); rigidBody2D = GetComponent<Rigidbody2D>(); isActive = true; } void Update() { GetInput(); UpdateAnimation(); } void FixedUpdate() { Move(); } void GetInput() { if (!isActive) { return; } jump = Input.GetButtonDown(jumpButtonName); } void Move() { if (!isActive) { return; } //接地判定 GroundCheck(); //ジャンプの速度計算 if (jump && isGrounded) { rigidBody2D.velocity = Vector3.up * jumpPower; } //実際の移動処理 rigidBody2D.velocity = new Vector2(speed, rigidBody2D.velocity.y); } void GroundCheck() { Collider2D[] groundCheckCollider = new Collider2D[groundCheckTransforms.Length]; //接地判定オブジェクトが何かに重なっているかどうかをチェック for (int i = 0; i < groundCheckTransforms.Length; i++) { groundCheckCollider[i] = Physics2D.OverlapPoint(groundCheckTransforms[i].position); //接地判定オブジェクトのうち、1つでも何かに重なっていたら接地しているものとして終了 if (groundCheckCollider[i] != null) { isGrounded = true; return; } } //ここまできたということは何も重なっていないということなので、接地していないと判断する isGrounded = false; } void UpdateAnimation() { animator.SetBool("Grounded", isGrounded); } }
C#スクリプトの解説
では、スクリプトの内容について簡単に説明しておきますね。
冒頭部分(RequiredComponent~)
まず冒頭の「RequredComponent~」のところは、「このスクリプトをゲームオブジェクトにアタッチするとき、指定したコンポーネントがなければ自動的にそれをアタッチする」ための一文です。Unityでスクリプトをアタッチしたとき、必要なコンポーネントをつけ忘れていて実行時にエラーが出ることがよくあるのですが、この文を書いておくことでそれを防止できます。
また、これを書いておくと必要なコンポーネントを削除できなくなるので、誤操作で間違ってコンポーネントを消してしまう心配もなくなります。
Start
必要なコンポーネントを取得してキャッシュしておきます。Startでわざわざこんなことをする理由は、Updateなどで頻繁にGetComponentするとゲームが重くなってしまう可能性があるからです。これはUnityの基本テクニックなので是非覚えておいてください。
Update・FixedUpdate
Updateでは、後述する入力処理とアニメーションの更新処理を呼び出します。一方でFixedUpdateでは移動処理を呼び出します。
Moveメソッド、GroundCheckメソッド
物理演算による移動処理と接地判定を行います。接地判定処理のほうは少し複雑ですが、それぞれの接地判定用オブジェクトの位置に何らかのコライダーがあるかどうかをチェックして、1つでもコライダーが重なっていれば「接地している」と判定します。
UpdateAnimationメソッド
接地判定の結果をアニメーターコントローラーに渡して、アニメーションの切り替えを行います。
スクリプトのアタッチ&設定
スクリプトを書けたら、それをプレイヤーオブジェクトにアタッチして設定を行いましょう。「Ground Check Transforms」のサイズを「3」にして、プレイヤーの子である3つの接地判定用オブジェクトをそこに登録してください(下図)。
これでひとまず、プレイヤーオブジェクトが動くようになりました。実際にゲームを動かして下のGIFのように動けば成功です(※スペースキーでジャンプ)。