UnityちゃんRunの作成

障害物のあるステージをキャラを操り、最短時間で駆け抜けるゲームを作成しよう。

ステージの作成

1.CreateEmptyからStageを原点に作成する。
2.Stageの中にCubeからStageを構成するパーツを作成する。transformは以下
●cube

●cube(1)

●cube(2)

●cube(3)

●cube(4)

●cube(5)

●cube(6)

3.Stageの各パーツに対して適当に表面材質を設定する。

3.Stageを拡大する。transformを以下のようにする。

ゴールエリアの作成

4.CreateEmptyからGoalを作成する。transformは以下。

5.Goalの子要素としてcube(7)を作成する。transformは以下。

6.cube(7)に適当に表面材質設定する。
7.CubeからGoal判定用のトリガーを作成する。Goalの子要素としてcubeを以下のtransformで配置。

8.isTriggerにチェックを入れトリガーとする。

8.見た目はいらないのでMeshRendererを無効にする
9.こんな感じになればOKだ。Mainとしてシーンをセーブしておこう。

Unityちゃんの配置

10.下のリンクからUnitychanパッケージをダウンロード、インポートする。(すでに持っている人はそれを利用すればよい)
http://unity-chan.com/download/download.php?id=UnityChan&v=1.2.1
11.modelsフォルダに入っているunitychanをシーンに配置し、Playerというタグを付与しよう。

12.transformを設定する。(ステージから浮いているのはゲーム開始時に落ちてくる演出のため)

AnimatorControllerの作成

13.ProjectビューのcreateからAnimatorControllerを作成し、名前をCharAnimとする。
13.Animatorタブを開き,createState->emptyからIdleステートを以下のように作成する。

14.Unitychanにアタッチして実行してみよう。普通の立ちポーズとなれば成功だ。この際、Apply Root Motionのチェックを外す。今回はUnityちゃんの位置の移動に関してはすべてスクリプトで行う。(モーションがもっている移動情報は使わない)。

15.アニメーターにWalkアクションを以下のように追加する。

16.パラメータを追加する。Parameters->+->Floatと選択する。

17.speedと入力する。これでspeedというパラメータを追加できた。

18.IdleからWalkの遷移の条件を以下の設定しよう。

19.同様にWalkからIdleの遷移を以下のように設定する。

20.次にRunのモーションを追加する。

21.WalkからRunの遷移を以下のように設定する。

22.RunからWalkへの遷移は以下。

23.さらにJumpを以下のように追加する。

24.jumpというparameterを追加する。今回はjumpに関してはtriggerを使う。

25.speedとjumpという2つのparameterがあることを確認する。

26.AnyStateから遷移を出すとどのタイミングでもモーションを実行できる。今回はjumpをAnyStateからの遷移にしよう。以下のように設定する。またすぐにジャンプアクションに遷移するようにTransitionDurationを小さく設定する。

27.ジャンプモーションを1回再生したら、Walkに繋げよう。下の図のようにHas Exit Timeにチェックをいれると再生を終えると自動的に遷移する。

CharacterControllerの付与

モーションの設定ができたのでいよいよキャラクターコントローラーを付与して実際にステージ上を移動できるようにしていこう。
18.UnitychanにAddComponent->PhysicsからCharacterControllerを付与する。
19.CharacterControllerを以下のように設定する(登れる最大傾斜45度、登れる段差30cm、コライダーはモデルに合わせる)

コントローラーの作成

20.あとは、モーションの遷移とキャラクターの動きを制御するCharMove.csを作成しunitychanに付与する。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CharMove : MonoBehaviour {
	Animator animator;
	CharacterController cc;

	Vector3 dir = Vector3.zero;
	public float gravity = 20.0f;
	public float speed = 4.0f;
	public float rotSpeed = 300.0f;
	public float jumpPower = 8.0f;

	void Start () {
		animator = GetComponent<Animator> ();
		cc = GetComponent<CharacterController> ();
	}


	void Update () {
		//前進成分を取得(0~1),今回はバックはしない
		float acc = Mathf.Max (Input.GetAxis ("Vertical"), 0f);
		//設置いていたら
		if (cc.isGrounded) {
			//左右キーで回転
			float rot = Input.GetAxis ("Horizontal");
			//前進、回転が入力されていた場合大きい方の値をspeedにセットする(転回のみをするときも動くモーションをする)
			animator.SetFloat ("speed", Mathf.Max (acc, Mathf.Abs (rot)));
			//回転は直接トランスフォームをいじる
			transform.Rotate (0, rot * rotSpeed * Time.deltaTime, 0);

			if (Input.GetButtonDown ("Jump")) {
				//ジャンプモーション開始
				animator.SetTrigger ("jump");
			}
		} 
		//下方向の重力成分
		dir.y -= gravity * Time.deltaTime;

		//CharacterControllerはMoveでキャラを移動させる。
		cc.Move ((transform.forward * acc * speed + dir) * Time.deltaTime);
		//移動した後着していたらy成分を0にする。
		if (cc.isGrounded) {
			dir.y = 0;
		}

	}
	
}



22.Jumpをダブルクリックしてモーション編集画面に入り、Eventsを開く。

23.再生しながら地面から離れるタイミングを探し、そこにEventを挿入する。今回はOnJumpStartというイベントを発生させた。
(下部にあるApplyボタンを押すのを忘れない)

24.後は、CharMove.csにこのイベント発生時の処理を追記するだけだ。一番下にメソッドを追記する。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CharMove : MonoBehaviour {
	Animator animator;
	CharacterController cc;

	Vector3 dir = Vector3.zero;
	public float gravity = 20.0f;
	public float speed = 4.0f;
	public float rotSpeed = 300.0f;
	public float jumpPower = 8.0f;

	void Start () {
		animator = GetComponent<Animator> ();
		cc = GetComponent<CharacterController> ();
	}


	void Update () {
		//前進成分を取得(0~1),今回はバックはしない
		float acc = Mathf.Max (Input.GetAxis ("Vertical"), 0f);
		//設置いていたら
		if (cc.isGrounded) {
			//左右キーで回転
			float rot = Input.GetAxis ("Horizontal");
			//前進、回転が入力されていた場合大きい方の値をspeedにセットする(転回のみをするときも動くモーションをする)
			animator.SetFloat ("speed", Mathf.Max (acc, Mathf.Abs (rot)));
			//回転は直接トランスフォームをいじる
			transform.Rotate (0, rot * rotSpeed * Time.deltaTime, 0);

			if (Input.GetButtonDown ("Jump")) {
				//ジャンプモーション開始
				animator.SetTrigger ("jump");
			}
		} 
		//下方向の重力成分
		dir.y -= gravity * Time.deltaTime;

		//CharacterControllerはMoveでキャラを移動させる。
		cc.Move ((transform.forward * acc * speed + dir) * Time.deltaTime);
		//移動した後着していたらy成分を0にする。
		if (cc.isGrounded) {
			dir.y = 0;
		}

	}
	//ジャンプモーションで地面から足が離れたときに呼ばれるイベント
	public void OnJumpStart () {
		//足が離れたらトランスフォームを上方に移動する。
		dir.y = jumpPower;
	}

}

カメラの設定

25.以下のようなCameraController.csを作成しカメラに付与する。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraController : MonoBehaviour {
	public Transform player;

	void LateUpdate () {
		transform.position = player.position + (-player.forward * 3.0f) + (player.up * 1.0f);
		transform.LookAt (player.position+Vector3.up);
	}
}

26.インスペクターからPlayerにunitychanを登録する。

27.ここまでで一回実行してみよう。ステージを自由自在に駆け回れれば成功だ。

UIの設置

28.経過時間を表示するUIを作成しよう。今回はuGUIを使って描画していく。ヒエラルキーのcreateからUI->Textを選択する。

29.Textを配置すると親要素としてCanvasが生成される。

30.実行端末の画面の大きさが変わってもうまく調整してくれるようにCanvasのCanvas Scalerを以下のように設定する。

31.Canvasの子要素Textを選択し、まずは実際の表示に近い文字列を入力する。

32.画面右下に表示されるようTextのRectTransformを以下のように設定する。

33.画面を見ながらfontサイズを調整する。今回は40とした。

GoalManagerの作成

34.時間の表示やゴール判定などを行うGoalManager.csを以下のように作成する。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;

public class GoalManager : MonoBehaviour {
	bool isGoal;
	public Text timeText;
	float goalTime;

	void Start () {
		timeText.text = "Time:00:000";
	}
	

	void Update () {
		if(!isGoal){
			//ゴールいていなかったら時間を加算していく。
			goalTime += Time.deltaTime;

		}else{
			//ゴールしたら2秒後にGoTopメソッドを実行する。
			Invoke ("GoTop", 2.0f);

		}
		//文字を更新する。
		timeText.text="Time:"+goalTime.ToString("00.000");
	}
	//プレイヤーがゴールした時の処理
	void OnTriggerEnter(Collider coll){
		if(coll.gameObject.tag=="Player"){
			//ゴールフラグをtrue
			isGoal = true;
			//GetXXXXXの第2引数はキーが無かった時のデフォルト値
			if(PlayerPrefs.GetFloat("goalTime",9999.0f)>goalTime){
				//記録更新したらファイルに書き込む
				PlayerPrefs.SetFloat ("goalTime", goalTime);
			}

		}

	}
	//ゴールいたときに行う処理
	void GoTop(){
		//シーン番号0に遷移(シーンが一つしかないときは現在のシーン)
		SceneManager.LoadScene (0);
	}
}

35.ヒエラルキーにあるGoalオブジェクトの子要素Cube(8)(トリガーになっているパーツ)に先程のスクリプトをアタッチし、パブリックフィールドTimeTextにCanvasオブジェクの子要素Textをアタッチする。

35.BuildSettingsからMainシーンを登録する。

36.実行してみよう。ゲームが始まるとカウントが始まり、ゴールすると2秒後にまたはじめから開始することがわかる。

タイトルシーンの作成

37.ファイルメニューから新規シーンを作成し、名前をTitleとする。
38.カメラを選択し、Clear FlagsをSolid Colorにして、背景色に適当な色を指定する。

38.modelsフォルダに入っているunitychanをシーンに配置する。

39.unitychanのtransformを以下のように設定する。

40.カメラの位置を以下のように調整する。

41.こんな感じになればOKだ。

42.プロジェクトビューからcreate->Animator ControllerとしてTitleAnimを作成する。
43.今回は以下のように走るだけのものにしたが、色々こってみるのもいいだろう。

44.unitychanのAnimatorに登録する。(Apply Root Motionもチェックを外しておく)

Canvasの設置

45.まずはタイトルを設置しよう。ヒエラルキーにあるcreateからUI->Textを選択する。
46.画面上部にセンタリングされてタイトルが表示されるように以下のように設定する。

47.BestTimeを表示する。まずはヒエラルキーにあるCanvasを右クリックしてTextを追加する。

48.画面中央やや下に表示されるよう以下のように設定する。

48.TitleScore.csを以下のように作成し、BestTime用のTextにアタッチする。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class TitleScore : MonoBehaviour {
	
	void Start () {
		GetComponent<Text>().text = "BestTime:" + PlayerPrefs.GetFloat ("goalTime", 9999.99f).ToString("00.000");
	}

}

49.スタートボタンを配置しよう。ヒエラルキーにあるCanvasを右クリックして、Buttonを選択する。

50.ボタンの位置を以下のように設定する。

51.ヒエラルキーにあるButton要素の子要素になっているTextを選択して[Start]と入力する。センタリングも設定しておく。

ボタンを押した時の処理

52.新規スクリプトからStartButton.csを作成し、以下のように記述する。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class StartButton : MonoBehaviour {

	public void StartBtClick(){
		SceneManager.LoadScene (1);
	}
}

53.ヒエラルキーにあるButtonにアタッチする。
54.ヒエラルキーにあるButton要素を選択し、OnClick属性にメソッドを登録する。(この要素自体をDDで登録する)

シーンの登録

これでTitle,Mainという2つのシーンができた。これを登録しよう。
55.ファイルメニューからBuild Settingsを開く。
56.2つのシーンをドラッグして登録しよう。一番上においたシーンからゲームがスタートするのでTitleを上に置く。右にシーン番号が付与されていることも確認する。なお、シーンを選択してdeleteキーを押すと削除できる。

57.実行してみよう。まずは最速ラップを出すとそれがタイトル画面に表示される点などを確認しておこう。

キャラ落下時の処理追加

58.今のままだと、キャラがステージから落下した場合継続不可能になってしまう。これを修正しよう。まずMainシーンを選択し、Cubeを作成し名前をOutAreaとする。transformは以下。

59.トリガーにするためにIsTriggerにチェックをいれ、不要なMeshRendererやMeshFilterはRemoveしてしまおう。

60.OutAreaController.csを以下のように作成し、OutAreaにアタッチする。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class OutAreaController : MonoBehaviour {

	void OnTriggerEnter(Collider coll){
		if(coll.gameObject.tag=="Player"){
			SceneManager.LoadScene (1);

		}
	}
}

61.実行し、コース外に飛び出してみよう。再びMainシーンの最初から始まるはずだ。

シーン遷移時に画面が暗くなる問題

(以下のバグはUnityのバージョンアップで修正されているようだ。もし旧バージョンのUnityを使っていて画面遷移時に暗くなったら対応を行えば良い)
62.タイトルシーンからMainシーンに遷移した際、画面が暗くなることがある。これを修正しよう。Mainシーンを選択して、WindowメニューからLightingを選択する。

63.Lightmapsタブを選択し、Autoのチェックを外しBuildボタンを押す。これで遷移しても暗くなることがなくなる。

完成

以上で完成だ。コースにギミックを追加したり、モーションを増やしたりしてさらにおもしろくしてみよう。