2014年9月24日水曜日

3-4. Unity でユニティちゃんアクションゲームを作る - 敵の生成と武器の追加

ソースはこちらで公開しています。
https://github.com/matsushima-terunao/unity-chan

実際のゲームはこちら
http://ter.dip.jp/blog_unity/unity-chan/build/web/web.html

敵の生成

敵を Prefab 化します。
 Hierarchy 上の bear を Assets に移動
 Hierarchy 上の bear を削除

MainScript

敵を生成を行う処理を追加します。
...
/** プレイヤー */
var player: GameObject;
/** 敵 */
var enemyPrefab: GameObject;
/** 敵 */
var enemies: GameObject[] = new GameObject[10];
...
function Start () {
	player = GameObject.Find("unitychan_dynamic_locomotion");
}

function Update () {
	// 敵生成
	for (var i: int = 0; i < enemies.length; ++ i) {
		if (null == enemies[i]) {
			var position: Vector3 = Vector3(
				player.transform.position.x + 10 * Mathf.Sin(player.transform.eulerAngles.y * Mathf.PI / 180) + 10 * Random.value - 5,
				0,
				player.transform.position.z + 10 * Mathf.Cos(player.transform.eulerAngles.y * Mathf.PI / 180) + 10 * Random.value - 5);
			var angle: Quaternion = Quaternion(0, Vector3.Angle(position, player.transform.position), 0, 1);
			enemies[i] = Instantiate(enemyPrefab, position, angle);
			break;
		}
	}
}
...

武器の追加

武器を追加します。Asset Store の Modern Weapons Pack を利用しました。今までと同様、Assets に Import します。
好きな武器を選んで、プレイヤーの右手(Character1_RightHand)にドロップします。



弾丸の追加

Sphere で弾丸を作成します。敵と同様に Prefab 化します。



UnityChanScript

弾丸を発射する処理を追加します。
...
/** 攻撃時刻 */
var attackTime: float = 0;
/** 弾丸時刻 */
var bulletTime: float = 0;
/** 弾丸 */
var bullets: GameObject[] = new GameObject[2];
/** 弾丸 */
var bulletPrefab: GameObject;
...
function Update () {
	var currentTime: float = Time.time;
	// 攻撃
	if (Input.GetButtonDown ("Fire1")) {
		animator.SetTrigger("Attack");
		transform.Find("Attack").gameObject.SetActive(true);
		attackTime = currentTime;
	}
	// 攻撃終了
	if (Time.time >= attackTime + 1) {
		transform.Find("Attack").gameObject.SetActive(false);
	}
	// 弾丸発射
	MainScript.Log("cou", bullets.length);
	if (currentTime - bulletTime >= 0.1) {
		for (var i: int = 0; i < bullets.length; ++ i) {
			if (null == bullets[i]) {
				bullets[i] = Instantiate(bulletPrefab, transform.position + transform.forward + transform.right * 0.2, transform.rotation);
				bullets[i].rigidbody.velocity = transform.forward * 10;
				Destroy(bullets[i], 1);
				bulletTime = currentTime;
				break;
			}
		}
	}
}
...

EnemyScript

敵が弾丸に当たったときの処理を追加します。
function OnCollisionEnter (collision: Collision) {
	MainScript.Log("enemy", collision.gameObject.name);
	if ("Attack" == collision.gameObject.name) {
		Damage();
	} else if ("Bullet(Clone)" == collision.gameObject.name) {
		Damage();
		Destroy(collision.gameObject);
	}
}

ここまでで再生してみます。
弾丸が敵にヒットして消えれば OK です。



ユニティちゃんライセンス

このアセットは、『ユニティちゃんライセンス』で提供されています。このアセットをご利用される場合は、『キャラクター利用のガイドライン』も併せてご確認ください。


← 3-3. Unity でユニティちゃんアクションゲームを作る - 当たり判定の追加
↑ 一覧

2014年9月16日火曜日

3-3. Unity でユニティちゃんアクションゲームを作る - 当たり判定の追加

ソースはこちらで公開しています。
https://github.com/matsushima-terunao/unity-chan

実際のゲームはこちら
http://ter.dip.jp/blog_unity/unity-chan/build/web/web.html

前準備

視点の変更


引いた状態でプレイヤーに追従する視点に変更します。
Main Camera を unitychan_dynamic_locomotion 配下に移動
Scene 上の視点を調整し、Main Camera を選択した状態で GameObject メニュー -> Align With View
 Inspector タブ -> Third Person Camera (Script) のチェックを外す



Main Camera に MainScript を付ける

/**
 * メインスクリプト。
 *
 * @author 2014/08/30 matsushima
 */

#pragma strict

/** デバッグテキスト */
static var debugTexts:Hashtable = new Hashtable();

function Start () {

}

function Update () {

}

function OnGUI() {
	// デバッグテキスト表示
	var y:int = 0;
	for (var k:Object in debugTexts.Keys) {
		GUI.Label(Rect(0, y * 20, 400, 20), k + ":" + debugTexts[k].ToString());
		++ y;
	}
}

static function Log(key:String, text:Object) {
	// デバッグテキスト表示登録
	debugTexts[key] = text;
	// デバッグテキストログ出力
	print(key + ":" + text);
}

敵キャラに当たり判定を追加

bear を選択し、Inspector タブ -> Add Component で Rigidbody と Capsule Collider を追加します。パラメータを写真の通りに修正します。
また、Tag に Enemy を追加し、bear に設定します。



前回と同様の方法でプレイヤーに Damage アクションを追加します。
State
 Damage
  Motion: DAMAGED00
Parameters
 Damage Trigger
Transition
 Any State -> Damage
  Conditions: Damage
 Damage -> Idle
  Conditions: Exit Time 0.82



UnityChanScript に衝突時のコードを追加します。
function OnCollisionEnter (collision: Collision) {
	MainScript.Log("player", collision.gameObject.name);
	if (collision.gameObject.CompareTag("Enemy")) {
		animator.SetTrigger("Damage");
	}
}
ここまでで再生してきます。プレイヤーが敵と接触時にアクションを起こせば OK です。



攻撃に当たり判定を付ける

ダミーのオブジェクトを作って、攻撃中に衝突したら当たりとします。

オブジェクト作成


 Cube オブジェクトを作成し、名前を Attack とし、unitychan_dynamic_locomotion の子に移動
Position: 0 0.5 1, Scale: 1 1 1
 画面に描画されないように、Mesh Renderer のチェックを外す
 Inspector に Rigidbody を追加し、移動しないように Constraints にチェックを入れる



UnityChanScript


Ctrl を押して1秒間だけ有効にするようにします。
/**
 * ユニティちゃんスクリプト。
 *
 * @author 2014/08/31 matsushima
 */

#pragma strict

/** アニメーター */
var animator: Animator;
/** 攻撃時刻 */
var attackTime: float = 0;

function Start () {
	animator = gameObject.GetComponent(Animator); // アニメーター
	transform.Find("Attack").gameObject.SetActive(false); // 攻撃オブジェクト
}

function Update () {
	// 攻撃
	if (Input.GetButtonDown ("Fire1")) {
		animator.SetTrigger("Attack");
		transform.Find("Attack").gameObject.SetActive(true);
		attackTime = Time.time;
	}
	// 攻撃終了
	if (Time.time >= attackTime + 1) {
		transform.Find("Attack").gameObject.SetActive(false);
	}
}

function OnCollisionEnter (collision: Collision) {
	MainScript.Log("player", collision.gameObject.name);
	// 敵と衝突	
	if (collision.gameObject.CompareTag("Enemy")) {
		animator.SetTrigger("Damage");
	}
}

EnemyScript


攻撃オブジェクトに衝突したときの処理を追加します。
function OnCollisionEnter (collision: Collision) {
	MainScript.Log("enemy", collision.gameObject.name);
	if ("Attack" == collision.gameObject.name) {
		Damage();
	}
}

function Damage() {
	animator.SetTrigger("Damage");
	Destroy(gameObject, 0.5f);
}

この状態で再生してみます。
攻撃が敵にヒットして消えれば OK です。



ユニティちゃんライセンス

このアセットは、『ユニティちゃんライセンス』で提供されています。このアセットをご利用される場合は、『キャラクター利用のガイドライン』も併せてご確認ください。


→ 3-4. Unity でユニティちゃんアクションゲームを作る - 敵の生成と武器の追加
← 3-2. Unity でユニティちゃんアクションゲームを作る - アニメーションの追加
↑ 一覧

3-2. Unity でユニティちゃんアクションゲームを作る - アニメーションの追加

ソースはこちらで公開しています。
https://github.com/matsushima-terunao/unity-chan

実際のゲームはこちら
http://ter.dip.jp/blog_unity/unity-chan/build/web/web.html

ユニティちゃんに攻撃アクションの追加

Animator 修正


既存の Animator に攻撃アクションの State を追加します。
 Hierarchy タブ -> unitychan_dynamic_locomotion を選択
 Animator タブ -> パネル内右クリック -> Create State -> Empty
 Inspector タブ -> New State を Attack に変更
 Motion 右端の○をクリック
 Select Motion ダイアログで Assets タブ -> SLIDE00 をダブルクリック
さらに State 間の遷移(Transition)を作成します。
 Any State で右クリック -> Make Transition -> Attack をクリック
 左下の Parameters 右の + をクリック -> Trigger
 New Trigger を Attack に変更
 先ほど追加した Trasition(矢印) をクリック
 Inspector タブ -> Conditions を Attack に変更
同様に Attack -> Idle への Transition を作成します。Conditions は Exit Time 0.50 にします。
のちに動きを確認したとき、反応が遅ければ、Transition のスライダを左に動かして遷移時間を短くしてみてください。



スクリプト作成


Trigger をセットするスクリプトを作成します。
 Assets 内に Javascript で UnityChanScript を作成
 スクリプトを Hierarchy タブ -> unitychan_dynamic_locomotion にドロップ
 スクリプトを編集
/**
 * ユニティちゃんスクリプト。
 *
 * @author 2014/08/31 matsushima
 */

#pragma strict

var animator: Animator;

function Start () {
	animator = gameObject.GetComponent(Animator);
}

function Update () {
	if (Input.GetButtonDown ("Fire1")) {
		animator.SetTrigger("Attack");
	}
}
元のスクリプト Fire1 のコードをコメントアウトしておきます。
 Main Camera の TirdPersionGamera の 41-50 行目をコメントアウト
		void FixedUpdate ()	// このカメラ切り替えはFixedUpdate()内でないと正常に動かない
		{
/*		
			if (Input.GetButton ("Fire1")) {	// left Ctlr	
				// Change Front Camera
				setCameraPositionFrontView ();
			} else if (Input.GetButton ("Fire2")) {	//Alt	
				// Change Jump Camera
				setCameraPositionJumpView ();
			} else {	
				// return the camera to standard position and direction
				setCameraPositionNormalView ();
			}
*/		}
ついでに画面のテキストも消します。
 unitychan_dynamic_locomotion の FaceUpdate の 18-30 行目の OnGUI() をコメントアウト
 unitychan_dynamic_locomotion の UnityChanControlScriptWithRgidBody の 181-190 行目の OnGUI() をコメントアウト
 unitychan_dynamic_locomotion の RandomWind の 38-42 行目の OnGUI() をコメントアウト

この状態で再生してみます。
左 Ctrl キーでスライディングすれば OK です。



敵キャラにアクションの追加

敵キャラも同様に Animator を修正します。
State
 Idle
  Motion: Assets/TinyMonsterPack/Animations/idle.anim
 Walk
  Motion: Assets/TinyMonsterPack/Animations/walk.anim
 Attack
  Motion: Assets/TinyMonsterPack/Animations/attack.anim
 Damage
  Motion: Assets/TinyMonsterPack/Animations/jump.anim
Parameters
 Damage Trigger
 Attack Trigger
 Speed Float 0.0
Transition
 Idle -> Walk
  Conditions: Speed Greater 0
 Walk -> Idle
  Conditions: Speed Less 0.1
 Any State -> Attack
  Conditions: Attack
 Attack -> Idle
  Conditions: Exit Time 0.90
 Any State -> Damage
  Conditions: Damage
 Damage -> Idle
  Conditions: Exit Time 0.82



さらに EnemyScript という名前でスクリプトを作成し、bear にドロップします。
/**
 * 敵スクリプト。
 *
 * @author 2014/09/01 matsushima
 */

#pragma strict

var animator: Animator;

var STATE_IDLE: int = 0;
var STATE_WALK: int = 1;

var state: int = STATE_IDLE;

var stateTime: float;

var speed: float = 0;

var player: GameObject;

function Start () {
	animator = gameObject.GetComponent(Animator);
	stateTime = Time.time;
	/*for (var o: GameObject in GameObject.FindGameObjectsWithTag("Player")) {
		Debug.Log(o.name);
	}*/
	//player = GameObject.FindGameObjectWithTag("Player");
	player = GameObject.Find("unitychan_dynamic_locomotion");
}

function Update () {
	var timeNow: float = Time.time;
	switch (state) {
	case STATE_IDLE:
		if (timeNow - stateTime >= 5) {
			state = STATE_WALK;
			stateTime = timeNow;
		} else {
			speed = Mathf.Max(0, speed - Time.deltaTime);
		}
		break;
	case STATE_WALK:
		if (timeNow - stateTime >= 5) {
			state = STATE_IDLE;
			stateTime = timeNow;
		} else {
			speed = Mathf.Min(1, speed + Time.deltaTime);
		}
		break;
	}
	// 攻撃
	var distance: Vector3 = player.transform.position - transform.position;
	if (distance.magnitude <= 1.0f) {
		animator.SetTrigger("Attack");
	}
	// 移動
	animator.SetFloat("Speed", speed);
	if (speed > 0) {
		var direction: float = Mathf.Atan2(distance.x, distance.z);
		// プレイヤー方向に回転
		transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.Euler(0, direction * 180 / Mathf.PI, 0), Time.deltaTime);
		// プレイヤー方向に移動
		transform.position.x += Mathf.Sin(direction) * Time.deltaTime * speed;
		transform.position.z += Mathf.Cos(direction) * Time.deltaTime * speed;
	}
}
この状態で再生してみます。
敵が近づいてきて攻撃してくれば OK です。



ユニティちゃんライセンス

このアセットは、『ユニティちゃんライセンス』で提供されています。このアセットをご利用される場合は、『キャラクター利用のガイドライン』も併せてご確認ください。


→ 3-3. Unity でユニティちゃんアクションゲームを作る - 当たり判定の追加
← 3-1. Unity でユニティちゃんアクションゲームを作る - キャラクターの配置
↑ 一覧

2014年9月14日日曜日

3-1. Unity でユニティちゃんアクションゲームを作る - キャラクターの配置

ソースはこちらで公開しています。
https://github.com/matsushima-terunao/unity-chan

実際のゲームはこちら
http://ter.dip.jp/blog_unity/unity-chan/build/web/web.html

キャラクターの配置

データのインポート

まずプロジェクトを作成します。プロジェクトは unity-chan という名前で作成し、unity-chan.unity という名前でシーンを保存しておきます。
ユニティちゃんのサイト
http://unity-chan.com/
からユニティちゃん データをダウンロードします。
 Project タブ -> Assets -> Import Package -> Custom Package...
 Import Package ... ダイアログでダウンロードした UnityChan.unitypackage ファイルを選択して開くをクリック
 Importing package ダイアログで Import をクリック

キャラクターの配置

インポートが終わったらキャラクターをシーンにコピーします。
 Assets -> UnityChan -> Scenes -> Locomotion を開く
 Hierarchy タブの Main Camera と unitychan_dynamic_locomotion と Directional light for UnityChan を選択して右クリック -> Copy
 再度 Assets -> unity-chan を開く
 Hierarchy パネル内の Main Camera を削除
 Hierarchy パネル内で右クリック -> Paste
これでキャラクターとライトが Scene 内に追加されます。

地面の作成

さらに地面を作成します。
 Hierarchy タブ -> Create -> Terrain
 Inspector タブ -> Position -> X: -500, Z: -500
 その下の筆ボタンをクリック -> Edit Textures... -> Add Texture... -> Texture -> Select でテクスチャを選択

ここまで終わったところで再生してみます。方向キーで移動できれば OK です。




敵キャラクターの配置

敵キャラクターとして Asset Store の Tiny Monster Pack を利用します。
 Window メニュー -> Asset Store
 右上の検索ボックスから tiny monster pack で検索
 Tiny Monster Pack #1 をクリック
 Import をクリック
 Importing package ダイアログで Import をクリック
 Project タブ -> Assets -> TinyMonsterPack -> Scenes -> Test を開く
 Hierarchy タブ -> bear 右クリック -> Copy
 再度 Assets -> unity-chan を開く
 Hierarchy パネル内で右クリック -> Paste
これで敵キャラクターが Scene 内に追加されます。



ユニティちゃんライセンス

このアセットは、『ユニティちゃんライセンス』で提供されています。このアセットをご利用される場合は、『キャラクター利用のガイドライン』も併せてご確認ください。


→ 3-2. Unity でユニティちゃんアクションゲームを作る - アニメーションの追加
← 2-3. Unity で砲台ゲームを作る - 改良
↑ 一覧