おっさんプログラマのUnity奮闘記

元WEB系プログラマのUnity奮闘記

おっさんのUnity入門 2Dオブジェクトの敵キャラクターを動かす(オブジェクトの自動追尾)

f:id:gomunpass:20180218120150j:plain
前回のシーンに敵キャラクターENEMYを追加してPLAYERを追尾する動作を実装してみます。

【追加するオブジェクト】
  • RED_ENEMY(スプライトをSceneへドラッグして作成)
【RED_ENEMYの設定】

f:id:gomunpass:20180218155739j:plain
このあと実装する「ゲームオーバー表示動作」で必要となる各オブジェクト識別のためのtagを追加します
Tag のプルダウンから<Add Tag ...>をクリック
f:id:gomunpass:20180218155748j:plain
「+」をクリックして「enemy」と入力します。
f:id:gomunpass:20180218155654j:plain
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;
	}

}


f:id:gomunpass:20180218120205j:plain

地面を水平移動しながらPLAYERへ近づいてくる動作ができました。

【参考にさせていただいた記事】

qiita.com



f:id:gomunpass:20180218151058j:plain

続いてENEMYと接触したときにゲームオーバー表示するように改良してみます。

【追加するオブジェクト】
  • CanvasWrapper(空のオブジェクト Hierarchy > Create > Create Empty)
  • gameoverText(Textオブジェクト Hierarchy > Create > UI > Text)
【CanvasWrapperの設定】

f:id:gomunpass:20180218151116j:plain


Canvasの設定】

f:id:gomunpass:20180218151131j:plain
Canvas / Render Mode<Screne Space - Camera>
Canvas / Render Camera<Main Camera(Camera)> 右端の〇ボタンから選択する
Canvas / Order in Layer <1>

【gameoverTextの設定】

f:id:gomunpass:20180218151148j:plain
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;
	}
}


f:id:gomunpass:20180218151201j:plain
ゲームスタート時は、ゲームーオーバー表示は非表示になっている


f:id:gomunpass:20180218151212j:plain
PLAYERとENEMYが接触すると非表示になっているゲームオーバーテキストが表示される