Edited at

UnityでRPGを作る

More than 3 years have passed since last update.


基本コンセプト

ロールプレイングゲーム

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


ゲームコンセプト


  • ダンジョンでクリスタルを集める

  • 徘徊する敵に接触してはいけない


設計コンセプト


  • 2Dメカニムを使用

  • コライダーは使用しないで、座標のマトリクス判定を行なう


素材


  • RPGツクールの素材を使用する

  • ひとマス32×32での素材を収集する

  • 必要な素材は、プレイヤー、敵、マップの3つ

プレイヤー

のんびりまったり:

http://momope8.blog67.fc2.com/blog-entry-237.html

敵素材

狐火日記:

http://leerfuchs.blog94.fc2.com/blog-entry-91.html

マップ素材

Jetblack Rooming House:

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

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

TextureTypeをSpriteに、SpriteModeをMultipleに設定。

設定が完了したら、SpriteEditorでトリミングする。


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

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


メカニムの設定

アニメーションの設定が完了したら、アニメーターの設定を行ないます。

ここでは「メカニム」という、アニメーションコントロールのためのツールを使います。

スクリーンショット 2015-02-14 10.07.31.png

作成したアニメーションを、メカニムの設定画面にドラック&ドロップします。

ひとつの色(敵キャラ)に必要なアニメーションを配置したら、それぞれを右クリックメニューのMakeTransitionで繋いで行きます。

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

左下の「+」ボタンを押下し、「int」のパラメーターを設定します。

右側のテキストBOXにはパラメーター名、左には「0」を入力しましょう。

スクリーンショット_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;
}
}
}