おっさんのUnity入門 2Dオブジェクトの敵キャラクターを動かす(オブジェクトの自動追尾)
前回のシーンに敵キャラクターENEMYを追加してPLAYERを追尾する動作を実装してみます。
【追加するオブジェクト】
- RED_ENEMY(スプライトをSceneへドラッグして作成)
【RED_ENEMYの設定】
このあと実装する「ゲームオーバー表示動作」で必要となる各オブジェクト識別のためのtagを追加します
Tag のプルダウンから<Add Tag ...>をクリック
「+」をクリックして「enemy」と入力します。
Box Collider 2D と Rigidbody 2D を追加して物理動作をできるようにします。
【EnemyMoveScript.cs(ENEMYへ追加するスクリプト)】
/* EnemyMoveScript.cs */ using System.Collections; using System.Collections.Generic; using UnityEngine; public class EnemyMoveScript : MonoBehaviour { GameObject player_green; private Rigidbody2D rb2d; void Start () { // オブジェクトのRigidbody2Dを取得 rb2d = GetComponent<Rigidbody2D> (); // PLAYERオブジェクトを取得 player_green = GameObject.Find ("PLAYER_GREEN"); } void Update () { // 移動関数の呼び出し EnemyMove (); } // ENEMYの移動関数1フレーム毎にUpdate関数から呼び出される void EnemyMove () { // PLAYERの位置を取得 Vector2 targetPos = player_green.transform.position; // PLAYERのx座標 float x = targetPos.x; // ENEMYは、地面を移動させるので座標は常に0とする float y = 0; // 移動を計算させるための2次元のベクトルを作る Vector2 direction = new Vector2 ( x - transform.position.x, y).normalized; // ENEMYのRigidbody2Dに移動速度を指定する rb2d.velocity = direction * 2; } }
地面を水平移動しながらPLAYERへ近づいてくる動作ができました。
【追加するオブジェクト】
- CanvasWrapper(空のオブジェクト Hierarchy > Create > Create Empty)
- gameoverText(Textオブジェクト Hierarchy > Create > UI > Text)
【CanvasWrapperの設定】
【Canvasの設定】
Canvas / Render Mode<Screne Space - Camera>
Canvas / Render Camera<Main Camera(Camera)> 右端の〇ボタンから選択する
Canvas / Order in Layer <1>
【gameoverTextの設定】
Text(Script) / Font Size <120>
Text(Script) / Alignment それぞれ真ん中のボタンをクリックする
Text(Script) / Color 四角い部分をクリックして好みの色を選択する
【PlayerMoveScript.cs】PLAYERの制御
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerMoveScript: MonoBehaviour { public Rigidbody2D rb2d; public bool isGrounded; private bool enemyTouch; // Canvasの入れ物 Canvas canvas; // UIControllerの入れ物 UIController uicontroller; void Start () { // オブジェクトのRigidbody2Dを取得 rb2d = GetComponent<Rigidbody2D> (); // UIControllerを取得する // canvasを取得してからそのコンポーネントであるスクリプトを // 取得する canvas = GameObject.Find ("CanvasWrapper") .GetComponentInChildren<Canvas>(); uicontroller = canvas.GetComponent<UIController> (); // ENEMYとの接触状態を非接触であるfalseへ設定する // UIControllder内にあるEnemyTouch関数から接触状態を取得して代入する enemyTouch = uicontroller.EnemyTouch; } void FixedUpdate () { // 地面に接触しているときだけ操作可能にする if (isGrounded == true) { // 左右のキー入力を取得 float moveparam = Input.GetAxis ("Horizontal"); // 左右方向移動のためオブジェクトに力を加える rb2d.AddForce (Vector2.right * moveparam * 10f); // スペースキー入力でオブジェクトをジャンプさせる if (Input.GetKeyDown (KeyCode.Space)) { rb2d.AddForce (new Vector2 (0, 9.8f), ForceMode2D.Impulse); isGrounded = false; } } } // 何らかのオブジェクト同士が接触したときの処理 void OnCollisionEnter2D (Collision2D collision) { // 空中での連続ジャンプを抑制するため地面との接触を感知するフラグの操作 // 地面とするオブジェクトにタグ(ground)をInspector上から追加しておく if (collision.gameObject.tag == "ground") { isGrounded = true; } // ENEMYに接触したときに動作する関数 //(Inspectorで作成したenemyタグを事前にRED_ENEMYに適応しておく) // 接触したオブジェクトがenemyのtagが付いたオブジェクトだったら if (collision.gameObject.tag == "enemy") { // enemyTouchが非表示を表すfalse状態だったらEnemyTouch関数を呼び出す if (enemyTouch == false) { EnemyTouchSend (); } } } // ENEMYとの接触時の動作を制御する関数 void EnemyTouchSend () { // UIController.csのEnemyTouchを介してenemyTouchの値をtrueに書き換える uicontroller.EnemyTouch = true; } }
【EnemyMoveScript.cs】ENEMYの制御
using System.Collections; using System.Collections.Generic; using UnityEngine; public class EnemyMoveScript : MonoBehaviour { GameObject player_green; private Rigidbody2D rb2d; void Start () { // オブジェクトのRigidbody2Dを取得 rb2d = GetComponent<Rigidbody2D> (); // PLAYERオブジェクトを取得 player_green = GameObject.Find ("PLAYER_GREEN"); } void Update () { // 移動関数の呼び出し EnemyMove (); } // ENEMYの移動関数1フレーム毎にUpdate関数から呼び出される void EnemyMove () { // PLAYERの位置を取得 Vector2 targetPos = player_green.transform.position; // PLAYERのx座標 float x = targetPos.x; // ENEMYは、地面を移動させるので座標は常に0とする float y = 0; // 移動を計算させるための2次元のベクトルを作る Vector2 direction = new Vector2 ( x - transform.position.x, y).normalized; // ENEMYのRigidbody2Dに移動速度を指定する rb2d.velocity = direction * 2; } }
【UIController.cs】テキストオブジェクトなどの制御
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class UIController : MonoBehaviour { // gameoverTextオブジェクトの入れ物 Text gameover_text; // PLAYERとENEMYの接触状態を表すフラグ // get/setメソッドで他のスクリプトから呼び出すためprivateにしておく private bool enemyTouch; void Start () { // UIのテキストを取得する(gameoverTextへ代入する) gameover_text = GameObject.Find ("gameoverText").GetComponent<Text> (); //Debug.Log (gameover_text); // ゲームスタート時はgameoverTextを非表示にしておく gameover_text.enabled = false; // PLAYERとENEMYの接触状態を表すフラグをfalseに初期化 enemyTouch = false; } void Update () { // PLAYERとENEMYが接触したら if (enemyTouch == true) { // ゲームオーバー表示をするための関数を呼び出す。 GameOverMessage (); } } // 他のスクリプトから読み書きするための関数 // 他のスクリプトから呼び出せるようにpublic属性を付ける // true/falseを呼び出し元のスクリプトへ渡すためbool型を付ける public bool EnemyTouch { get { return enemyTouch; } set { enemyTouch = value; } } void GameOverMessage () { gameover_text.enabled = true; } }
ゲームスタート時は、ゲームーオーバー表示は非表示になっている
PLAYERとENEMYが接触すると非表示になっているゲームオーバーテキストが表示される