読者です 読者をやめる 読者になる 読者になる

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

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

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

Unity 2D ローグライク チュートリアル

いつもひよこのたまごをご利用下さいましてありがとうございます!
おかげ様でチュートリアル数も10ゲーム目となりました!
チュートリアル一覧は
こちら からどうぞ!


スポンサーリンク

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)】