Unity(C#)初心者・入門者向けチュートリアル ひよこのたまご

AndroidやiOS向けアプリを簡単に作れるゲーム開発環境Unity(ユニティ)の使い方を、チュートリアル方式で一緒に学びましょう!

【Unity7】敵キャラクターのAnimator Controllerを設定したい!【2Dローグライク11】

Unity5.0.0f4 Personal(2015年6月)

f:id:hiyotama:20150519220636p:plain

前回の続きです〜


今回は敵キャラクターのアニメーションを管理するアニメーターを完成させたいと思います〜


また、GameManagerスクリプトとEnemyスクリプトに加筆修正を加え、①Playerが動く②Enemyが動く③アイテムを取る④壁を破壊する⑤Enemyからのダメージを受けると、5つのテストを行います〜

【目標】敵キャラクターのアニメーターを設定する



2D Roguelike 11 of 14 : Enemy Animator Controller ...


①Enemy1アニメーターの設定
それではEnemy1のアニメーターの設定をしていきます〜ProjectビューのAnimations>AnimatorControllers>Enemy1を選択し、アニメータービューを開いて下さい〜


f:id:hiyotama:20150602171414p:plain
Enemy1のアニメータービュー


まずはパラメーターを設定します〜画面左のparametersをクリックし、プラスボタンを押してTrigger型の変数を作成します〜名前はenemyAttackにしましょう〜


f:id:hiyotama:20150602171811p:plain
Trigger型の変数作成


続いてMakeTransitionを行い、Enemy1IdleとEnemy1Attackを矢印でお互い結び合って下さい〜


f:id:hiyotama:20150602171955p:plain
右クリック→Make Transitionでお互いを結ぶ


それではまずEnemy1IdleからEnemy1Attackへ伸びている矢印のほうから設定していきましょう〜矢印をクリックし、Inspectorビューを見て下さい〜

Idle状態はループさせるため、Has Exit Timeのチェックを外し、Transition Durationを0に変更します〜最後に、Conditionsにあるプラスボタンを押し、enemyAttackを選択して下さい〜


f:id:hiyotama:20150602172437p:plain
こんな感じに設定


次にEnemy1AttackからEnemy1Idleへ伸びているの矢印をクリックし、Inspectorビューの設定をしていきます〜

1回アニメーションしたらEnemy1Idleへ戻したいため、Has Exit Timeはチェックしたままにし、Exit Timeを1、Transition Durationを0に変更します〜


f:id:hiyotama:20150602172752p:plain
こんな感じ


これでEnemy1のアニメーター設定は終了しましたが、実はもうEnemy2のアニメーター設定も終了しています〜
Enemy2のアニメーターはAnimator Override Controllerで作成したため、Enemy1で設定した内容は自動的に反映されるからです〜


②GameManagerスクリプト加筆修正
まずはGameManagerスクリプトに修正を加えていきます〜以下ソースです〜

using UnityEngine;
using System.Collections;
//********** 開始 **********//
using System.Collections.Generic; //Listを使う時に宣言
//********** 終了 **********//

public class GameManager : MonoBehaviour {
//********** 開始 **********//
	public float turnDelay = .1f; //Enemyの動作時間(0.1秒)
//********** 終了 **********//
	public static GameManager instance = null;
	public BoardManager boardScript;

	public int playerFoodPoints = 100;
	[HideInInspector] public bool playersTurn = true;
	
	private int level = 3;
//********** 開始 **********//
	private List<Enemy> enemies; //Enemyクラスの配列
	private bool enemiesMoving; //Enemyのターン中true
//********** 終了 **********//
	
	void Awake ()
	{
		if (instance == null) {
			instance = this;
		} else if (instance != this) {
			Destroy(gameObject);
		}
		
		DontDestroyOnLoad(gameObject);
//********** 開始 **********//
		//Enemyを格納する配列の作成
		enemies = new List <Enemy>();
//********** 終了 **********//
		boardScript = GetComponent<BoardManager>();
		InitGame();
	}
	
	void InitGame () {
//********** 開始 **********//
		enemies.Clear(); //EnemyのList(配列)を初期化
//********** 終了 **********//
		boardScript.SetupScene(level);
	}

	public void GameOver ()
	{
		enabled = false;
	}
	
//********** 開始 **********//
	void Update ()
	{
		//プレイヤーのターンかEnemyが動いた後ならUpdateしない
		if (playersTurn || enemiesMoving) {
			return;
		}
		
		StartCoroutine(MoveEnemies());
	}
	
	public void AddEnemyToList (Enemy script)
	{
		enemies.Add (script);
	}
	
	//
	IEnumerator MoveEnemies ()
	{
		enemiesMoving = true;
		yield return new WaitForSeconds (turnDelay);
		if (enemies.Count == 0) {
			yield return new WaitForSeconds (turnDelay);
		}
		//Enemyの数だけEnemyスクリプトのMoveEnemyを実行
		for (int i = 0; i < enemies.Count; i++) {
			enemies[i].MoveEnemy();
			yield return new WaitForSeconds(enemies[i].moveTime);
		}
		
		playersTurn = true;
		enemiesMoving = false;
	}
//********** 終了 **********//
}

GameManager.cs


ListでEnemyの配列を作成
C#のList機能を使って、複数のEnemyを格納するenemies配列を作成しています〜

まずはAwakeメソッドでnewを行い配列を作成し、InitGameメソッドで配列の初期化を行っています〜


Updateメソッド
Updateメソッドではまず、playersTurnとenemiesMovingがtrueである場合にreturnを行い、Updateメソッドを終了しています〜

どちらかがfalseであった場合、コルーチンであるMoveEnemiesメソッドを実行し、Enemyを動かしていきます〜

コルーチンについては以下エッセンスをご参照下さい〜

hiyotama.hatenablog.com


MoveEnemiesメソッド
まずはじめにenemiesMovingをtrueにします〜

コルーチンを実行すると何秒間か継続的に実行状態となりますが、その間もUpdateメソッドは何度も実行されます〜
ですので、MoveEnemiesメソッド実行中はUpdateメソッドを実行しなくするため、enemiesMoving=trueの時はUpdateメソッドを終了させる処理をUpdateメソッド先頭に書いていたというわけです〜

次に0.1秒待機し、Enemyの数が0の場合はもう0.1秒待ちます〜

次にfor文を使い、Enemyの数だけ処理をループさせています〜処理の内容は、List配列に格納しておいたEnemyクラスのMoveEnemyメソッドを実行し、EnemyクラスのmoveTIme分だけ待機し、そしてfor文の頭に戻っています〜

Enemyを全て動かしfor文を抜けると、playerTurnをtrueにしPlayerへ順番を譲り、enemiesMovingをfalseにしています〜


AddEnemyToListメソッド
このメソッドでは、List配列にEnemyを格納しています〜このあとEnemyスクリプトのStartメソッドに、AddEnemyToListを呼び出す処理を追記していきます〜


③Enemyスクリプト加筆修正
続いてEnemyスクリプトを修正していきます〜以下ソースです〜

using UnityEngine;
using System.Collections;
public class Enemy : MovingObject {
	
	public int playerDamage;
	
	private Animator animator;
	private Transform target;
	private bool skipMove; 
	

	protected override void Start () {
//********** 開始 **********//
		//GameManagerスクリプトのEnemyの配列に格納
		GameManager.instance.AddEnemyToList(this);
//********** 終了 **********//
		animator = GetComponent<Animator>();
		target = GameObject.FindGameObjectWithTag("Player").transform;
		base.Start();
	}

	protected override void AttemptMove <T> (int xDir, int yDir)
	{
		
		if (skipMove) {
			skipMove = false;
			return;
		}
		
		base.AttemptMove <T> (xDir, yDir);

		skipMove = true;
	}

	public void MoveEnemy ()
	{
		int xDir = 0;
		int yDir = 0;

		if (Mathf.Abs (target.position.x - transform.position.x) < float.Epsilon) {
			yDir = target.position.y > transform.position.y ? 1 : -1;
		} else {
			xDir = target.position.x > transform.position.x ? 1 : -1;
		}
		AttemptMove <Player> (xDir, yDir);
	}
	protected override void OnCantMove <T> (T component)
	{
		Player hitPlayer = component as Player;
//********** 開始 **********//
		animator.SetTrigger("enemyAttack"); //攻撃アニメーション実行
//********** 終了 **********//
		hitPlayer.LoseFood(playerDamage);
	}
}

Enemy.cs


修正は2箇所のみです〜1箇所目はStartメソッドにて、先ほどのAddEnemyToListメソッドを呼び出しています〜引数thisは、このEnemyクラス自体を表しています〜

2箇所目はOnCantMoveメソッドにて、アニメーターで設定したTrigger型のenemyAttackをtrueにし、攻撃アニメーションを行うようにします〜


④テスト
それではテストをしてみましょう〜


f:id:hiyotama:20150602173902p:plain
ゲーム実行


f:id:hiyotama:20150602174017p:plain
プレイヤーを2回動かすとEnemyが動く


f:id:hiyotama:20150602174102p:plain
壁を攻撃し破壊する


f:id:hiyotama:20150602174139p:plain
アイテムを取る


f:id:hiyotama:20150602174324p:plain
Enemyが攻撃し、Playerがダメージを受ける


うまくいきました〜今回はここまでです〜
ありがとうございました〜


【Unity開発7】Unity公式チュートリアル2Dローグライクの導入【2Dローグライク1】

【Unity開発7】アニメーションを作りたい!【2Dローグライク2】

【Unity開発7】Floorやアイテムを作成したい!【2Dローグライク3】

【Unity開発7】床や敵キャラ、アイテム等を自動生成させたい!【2Dローグライク4】

【Unity開発7】BoardManagerを呼び出すGameManagerを作成する【2Dローグライク5】

【Unity開発7】キャラクターを動かすための抽象クラス作成【2Dローグライク6】

【Unity開発7】破壊可能な壁(Wall)を作成したい!【ローグライク7】

【Unity開発7】プレイヤーのアニメーターを設定したい!【ローグライク8】

【Unity開発7】プレイヤー用のスクリプトを設定したい!【ローグライク9】

【Unity開発7】敵キャラクターのスクリプトを作成したい!【2Dローグライク10】

【Unity開発7】敵キャラクターのアニメーターを設定したい!【2Dローグライク11】

【Unity開発7】uGUIでUIの表示とレベル機能を実装したい!【2Dローグライク12】

【Unity開発7】BGMと効果音を付ける【2Dローグライク13】

【Unity開発7】タッチパネルに対応させたい!【2Dローグライク14(Fin)】