UnityでRPGを作る

##基本コンセプト

**ロールプレイングゲーム**
http://ja.wikipedia.org/wiki/ロールプレイングゲーム

###ゲームコンセプト
* ダンジョンでクリスタルを集める
* 徘徊する敵に接触してはいけない

###設計コンセプト
* 2Dメカニムを使用
* コライダーは使用しないで、座標のマトリクス判定を行なう

##素材
* RPGツクールの素材を使用する
* ひとマス32×32での素材を収集する
* 必要な素材は、プレイヤー、敵、マップの３つ

**プレイヤー**
のんびりまったり：
http://momope8.blog67.fc2.com/blog-entry-237.html

**敵素材**
狐火日記：
http://leerfuchs.blog94.fc2.com/blog-entry-91.html

**マップ素材**
Ｊｅｔｂｌａｃｋ　Ｒｏｏｍｉｎｇ　Ｈｏｕｓｅ：
http://blog.goo.ne.jp/shikkokunotoki3

##プレイヤー、敵テクスチャーの作成
2Dアニメーションを作成するので、SpriteRendererの設定と、SpriteEditorを使用して、画像のトリミングを行なう。

###SpriteRendererの設定

**SpriteRenderer**
http://docs.unity3d.com/ScriptReference/SpriteRenderer.html


****
![Untitled_-_TCA_RPG_-_iPhone__iPod_Touch_and_iPad-3.png](https://qiita-image-store.s3.amazonaws.com/0/50702/954f07eb-8241-3df9-95de-7036db84bd03.png "Untitled_-_TCA_RPG_-_iPhone__iPod_Touch_and_iPad-3.png")

タイリングされたプレイヤーの画像を選択し、インスペクターで設定。
TextureTypeをSpriteに、SpriteModeをMultipleに設定。

設定が完了したら、SpriteEditorでトリミングする。
****
![Untitled_-_TCA_RPG_-_iPhone__iPod_Touch_and_iPad-5.png](https://qiita-image-store.s3.amazonaws.com/0/50702/d1c99f1c-c896-8358-4793-b6273c28d5c3.png "Untitled_-_TCA_RPG_-_iPhone__iPod_Touch_and_iPad-5.png")

SpriteEditorを展開したら、左上のSliceボタンを押下し、トリミングサイズの設定を行なう。
RPGツクールの素材は、大体32×32で納められている。
更新完了したらSliceボタンを押下し、右上のApplyボタンを押下する。
***
##アニメーションの作成
Unityの便利な機能を使用して、パラパラアニメーションを作成する。

対象のテクスチャーを選択し、ヒエラルキーにドラック＆ドロップする。
このタイルは、正面、後ろ、右、左の4つの方向があるので、それぞれのアニメーションでまとめて作成する。

基本的に、一番若いSpriteNameがオブジェクト名、アニメーター名になり、アニメーションのファイル名を適宜設定するような仕様になっている。

現在のUnityでは、アニメーションファイルと一緒に、アニメーターファイルが生成されるが、実際に使うアニメーターファイルはひとつだけなので、不要なものは削除してしまって問題ない。ひとつ作ってしまえば、コピーしてアニメーションを差し替えるのみで対応が出来る。

![Untitled_-_TCA_RPG_-_iPhone__iPod_Touch_and_iPad-12.png](https://qiita-image-store.s3.amazonaws.com/0/50702/89ba69b6-5003-fcad-0979-2eae3a7bce2d.png "Untitled_-_TCA_RPG_-_iPhone__iPod_Touch_and_iPad-12.png")

今回は敵キャラを4色分作りました。

##メカニムの設定
アニメーションの設定が完了したら、アニメーターの設定を行ないます。
ここでは「メカニム」という、アニメーションコントロールのためのツールを使います。

![スクリーンショット 2015-02-14 10.07.31.png](https://qiita-image-store.s3.amazonaws.com/0/50702/53621ec5-b484-f533-cf54-98cafffd2d98.png "スクリーンショット 2015-02-14 10.07.31.png")


作成したアニメーションを、メカニムの設定画面にドラック＆ドロップします。
ひとつの色(敵キャラ)に必要なアニメーションを配置したら、それぞれを右クリックメニューのMakeTransitionで繋いで行きます。

完了したら、アニメーション切り替えのためのパラメーターを設定します。

左下の「＋」ボタンを押下し、「int」のパラメーターを設定します。
右側のテキストBOXにはパラメーター名、左には「０」を入力しましょう。

![スクリーンショット_2015-02-14_10_55_03-2.png](https://qiita-image-store.s3.amazonaws.com/0/50702/87cb4ce9-52b3-e992-fd89-ba71da8c4b70.png "スクリーンショット_2015-02-14_10_55_03-2.png")


##アニメーションコントローラの作成


```PlayerController.cs
using UnityEngine;
using System.Collections;

[RequireComponent(typeof(Animator))]

public class PlayerController : MonoBehaviour {
	private Animator m_player;
	public int m_playerState = 0;
	private SpriteRenderer m_idlestate;

	public Sprite F;
	public Sprite B;
	public Sprite R;
	public Sprite L;

	private Vector3 m_playerPosition = new Vector3(0, 0, 0);


	// Use this for initialization
	void Start () {
		m_player = GetComponent<Animator>();
		m_idlestate = GetComponent<SpriteRenderer>();
	
	}
	
	// Update is called once per frame
	void Update () {

		if (Input.GetKey(KeyCode.DownArrow)){
			m_player.speed = 1;
			m_player.SetInteger("Walk", 0);	
		}

		if (Input.GetKey(KeyCode.UpArrow)){
			m_player.speed = 1;
			m_player.SetInteger("Walk", 1);
		}

		if (Input.GetKey(KeyCode.RightArrow)){
			m_player.speed = 1;
			m_player.SetInteger("Walk", 3);
		}

		if (Input.GetKey(KeyCode.LeftArrow)){
			m_player.speed = 1;
			m_player.SetInteger("Walk", 2);
		}

		if (Input.GetKeyUp(KeyCode.DownArrow)){
			m_player.speed = 0;
		}


		if (Input.GetKeyUp(KeyCode.UpArrow)){
			m_player.speed = 0;
		}


		if (Input.GetKeyUp(KeyCode.RightArrow)){
			m_player.speed = 0;
		}


		if (Input.GetKeyUp(KeyCode.LeftArrow)){
			m_player.speed = 0;
		}
	}

}

```

##Mapの作成
フィールド(マップ)を作成するために、マップチップの準備と、MapLoaderの作成を行ないます。


###MapLoader
・ヒエラルキーに空のゲームオブジェクトを配置します
・MapLoader.csを追加(生成)します
・インスペクターに▷Floorが表示されているので、sizeに使用するチップの数を入力し、追加されたGameObject追加欄にプレハブをD&Dします。



```Map.cs
using UnityEngine;
using System.Collections;

public class MapLoader : MonoBehaviour {

	public float m_chipsize = 0.16f;
	public GameObject[] m_floor1;
	private int m_map =0;

	[SerializeField]
	private GameObject m_player = null;
	Controller m_controller = null;

	private float x = 0;
	private float y = 0;

	public int[] m_ngchip = new int[]{10, 12, 13}; 


	public int[][] m_mapArray2 = new int[][]{
		new int[] { 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7},
		new int[] { 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 8},
		new int[] { 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 8},
		new int[] { 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 8},
		new int[] { 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,13, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5},
		new int[] { 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,13, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5},
		new int[] { 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,13, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5},
		new int[] { 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,13, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5},
		new int[] { 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,13, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5},
		new int[] { 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,13, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5},
		new int[] { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,10,12,12,12,12,12,12, 5, 5, 5, 5, 5, 5},
		new int[] { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,13 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5},
		new int[] { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,13 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5},
		new int[] { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,13 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5},
		new int[] { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,13 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5},
		new int[] { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,13 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5},
		new int[] { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,13 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5},
		new int[] { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,13 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5},
		new int[] { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,13 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5},
		new int[] { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,13 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5},
		new int[] { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,13 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5},
		new int[] { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,13 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5},
		new int[] { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,13 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5},
		new int[] { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,13 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5},
		new int[] { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,13 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5},
		new int[] { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,13 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5},
		new int[] { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,13 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5},
		new int[] { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,13 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5},
		new int[] { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,13 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5},
		new int[] { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,13 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5 ,5},
	};

	void Awake (){
		m_controller = m_player.GetComponent<Controller>();
		m_controller.MapchipNG(m_ngchip);
	}

	// Use this for initialization
	void Start () {

		foreach (int[] array in m_mapArray2)
		{
			foreach (int s in array)
			{
				Instantiate(m_floor1[s], new Vector3(x, y, 0), Quaternion.identity);
				x = x + 1;
			}
			x = 0;
			y = y + 1;
		}

	}
	
	// Update is called once per frame
	void Update () {
	
	}
}

```


##コントローラーを作成する
```controller.cs
using UnityEngine;
using System.Collections;

public class CharactourController : MonoBehaviour {

	public GameObject m_map;
	public MapLoader m_map01;
    Transform m_position;

    public int[] m_ngmap_p = new int[]{0,0,0};

    enum Move { on, off }

    Move m_move = Move.off;

    // Use this for initialization
    void Start ()
    {
        m_map = GameObject.Find ("Map");
        m_map01 = m_map.GetComponent<MapLoader> ();
        m_position = GetComponent<Transform> ();

    }

    // Update is called once per frame
    void Update ()
    {
        if (Input.GetKey (KeyCode.UpArrow))
            StartCoroutine (MovePlayer ("u", 1));
        if (Input.GetKey (KeyCode.DownArrow))
            StartCoroutine (MovePlayer ("d", -1));
        if (Input.GetKey (KeyCode.RightArrow))
            StartCoroutine (MovePlayer ("r", 1));
        if (Input.GetKey (KeyCode.LeftArrow))
            StartCoroutine (MovePlayer ("l", -1));
    }

    bool MapCollider( int x, int y ){

        Debug.Log("NextPosi;" + x + "," + y + "\n" + m_map01.m_mapArray[y][x]);

        foreach (int s in m_ngmap_p) if(m_map01.m_mapArray[y][x] == s) return false;
        return true;

    }

    public void MapchipNG(int[] ngchip){

        int i = 0;

        foreach (int s in ngchip){
            m_ngmap_p[i] = s;
            i++;
        }
    }

    private IEnumerator MovePlayer (string s, int i)
    {

        float m = 0.1f; ///　移動速度

        float x = this.transform.localPosition.x;
        float y = this.transform.localPosition.y;
        float z = this.transform.localPosition.z;

        float my = y;
        float mx = x;

        if (m_move == Move.off) {
            m_move = Move.on;

            switch (s) {
            case "u":
                Debug.Log ("Move UP");

                if (MapCollider((int)x, (int)y+1)) {
                    for (int f = 0; f <= 10; f++) {
                    	m_position.localPosition = new Vector3 (x, my, z);
                        if(f == 10) m_position.localPosition = new Vector3 (x, y, z);
                        my = my + m;

                        yield return new WaitForSeconds (0.01f);
                    }
                }
                break;

            case "d":
                Debug.Log ("Move DOWN");

                if (MapCollider((int)x, (int)y-1)) {
                	for (int f = 0; f <= 10; f++) {
                        m_position.localPosition = new Vector3 (x, my, z);
                        my = my - m;

                        yield return new WaitForSeconds (0.01f);
                    }
                }
                break;

            case "r":
                Debug.Log ("Move Right");

                if (MapCollider((int) x + 1, (int)y)) {
                    for (int f = 0; f <= 10; f++) {
                        m_position.localPosition = new Vector3 (mx, y, z);
                        mx = mx + m;

                        yield return new WaitForSeconds (0.01f);
                    }
                }
                break;

            case "l":
                Debug.Log ("Move Left");
                if (MapCollider((int)x - 1, (int)y)){
                for (int f = 0; f <= 10; f++) {
                        m_position.localPosition = new Vector3 (mx, y, z);
                        mx = mx - m;

                        yield return new WaitForSeconds (0.01f);
                    }
                }
                break;

            default:

                break;
            }

            m_position.localPosition = new Vector3 ( (float)System.Math.Round(mx, 0), (float)System.Math.Round(my, 0), z);
            Debug.Log( m_position.localPosition );

            yield return new WaitForSeconds (0.2f);
            m_move = Move.off;
        }
    }
}


```