子ノ刻ラボラトリィ

子ノ刻[23:00-01:00]に右脳系ディベロッパが時々お送りするAndroidアプリ開発日誌。主にUnity。最近LINEスタンプ。時々雑記。

ロックマン的なものでUnity2Dを勉強 その6

こんばんは! しんがです。

前回に引き続き、ロックマン的なものでUnity2Dのお勉強。

今回はキャラクターの移動をやってみよー。
AddForceではなく、transform.localPositionを直接いじるタイプを。

今回やろうとしていること
  • 状態と連動したキャラクターの移動

ひとまず今回の移動は、「走る」のところだけ。
ジャンプとかのY軸方向は次あたりに。
移動はtransform.localPositionを編集して実現していきます。

状態と連動したキャラクターの移動

前回のアクションメソッドで移動量を設定するという簡略的なやりかた。

using UnityEngine;
using System.Collections.Generic;
using System.Reflection.Emit;

// 状態列挙体
public enum State : int {
    Idle=0, // 立ち
    Run,    // 走り
    Jump,   // ジャンプ
    Dmage,  // ダメージ
    Thiun   // ティウン
};

// アクション関数格納用デリゲート
public delegate int Action();

/// <summary>
/// Numbersクラス
/// キャラクターのベースとなるクラス。
/// 基本のアクションを実装する。
/// </summary>
public class Numbers : MonoBehaviour {

    // 状態マップ
	public Dictionary<int, Action> actMap = new Dictionary<int, Action>();
  
    // 状態
	public int NowState {get; set; }

    // 向き 左:-1 / 右:+1 ← NEW!!
    public int Dir { get; set; }

    // 走り速度           ← NEW!!
    public float RunAcc;
    // 走りブレーキ       ← NEW!!
    public float RunDec;

    // 移動量             ← NEW!!
    public float MoveVecX { get; set; }
    public float MoveVecY { get; set; }


	// Use this for initialization
    void Start () {
        // 状態をマップを作成
        actMap.Add((int)State.Idle, this.idle);
        actMap.Add((int)State.Run,  this.run);
        actMap.Add((int)State.Jump, this.jump);
    }
	
	// Update is called once per frame
    void Update () {
	// 状態マップから次の状態を取得
        this.NowState = (int)actMap[this.NowState]();

        // Animatorコンポーネントの「NowState」プロパティに現在の状態を渡す
        GetComponent<Animator>().SetInteger("NowState", this.NowState);

        // 移動量を位置に反映  ← NEW!!
        transform.localPosition += new Vector3(this.MoveVecX * this.Dir, this.MoveVecY, 0);

        Debug.Log("NowState:" + this.NowState);

        // おまけ 速度調節
        if (Input.GetKey("up"))
        {
            this.RunAcc = this.RunAcc + 0.01f;
            this.RunDec = this.RunDec + 0.01f;
        }
        if (Input.GetKey("down") && this.RunDec > 0)
        {
            this.RunAcc = this.RunAcc - 0.01f;
            this.RunDec = this.RunDec - 0.01f;
        }
	}

    /// <summary>
    /// 状態:立ち
    /// </summary>
    /// <returns></returns>
	private int idle(){
        // L/Rが押されたら走り状態に遷移
        if (Input.GetKey("left") || Input.GetKey("right"))
        {
            return (int)State.Run;
        }
        // スペースが押された瞬間ジャンプ状態に遷移
        if (Input.GetKeyDown("space"))
        {
            return (int)State.Jump;
        }

        // 速度は減速し、0に収束する  ← NEW!!
        if ((this.MoveVecX -= this.RunDec) < 0.05f)
        {
            this.MoveVecX = 0.0f;
        }
        // 何もなければ立ち状態を継続
		return (int)State.Idle;
	}

	private int run(){
        // スペースが押された瞬間ジャンプ状態に遷移
        if (Input.GetKeyDown("space"))
        {
            return (int)State.Jump;
        }
        // L/Rが押されているならば走り状態を継続
        if (Input.GetKey("left"))
        {
            // 向きを左に                ← NEW!!
            this.Dir = -1;
            // 移動量を増加              ← NEW!!
            this.MoveVecX = this.RunAcc;
            // 向きによって画像を反転    ← NEW!!
            transform.localScale = new Vector3(this.Dir, 1, 1);
            return (int)State.Run;
        }
        if(Input.GetKey("right")){
            // 向きを左に                ← NEW!!
            this.Dir = 1;
            // 移動量を増加              ← NEW!!
            this.MoveVecX = this.RunAcc;
            // 向きによって画像を反転    ← NEW!!
            transform.localScale = new Vector3(this.Dir, 1, 1);
            return (int)State.Run;
        }


        // 何も押されていなければ立ち状態に遷移
        return (int)State.Idle;
	}

	private int jump(){
        
        // スペースが押されているならばジャンプ状態を継続
        if (Input.GetKey("space"))
        {
            return (int)State.Jump;
        }
        // 何も押されてなければ
        return (int)State.Idle;
	}
}

さて、ざっくりと説明

追加した変数は以下の通り。

// 向き 左:-1 / 右:+1 ← NEW!!
public int Dir { get; set; }

// 走り速度           ← NEW!!
public float RunAcc;
// 走りブレーキ       ← NEW!!
public float RunDec;

// 移動量             ← NEW!!
public float MoveVecX { get; set; }
public float MoveVecY { get; set; }

そして、右向きでも左向きでも走り状態の時は、「移動量(X)」は「走り速度」にする。
左右で違うのは向きを-1にするか1にするかが違う。
なので、もうチョイ効率的な書き方はある。

if (Input.GetKey("left"))
{
    // 向きを左に                ← NEW!!
    this.Dir = -1;
    
    // 移動量を増加              ← NEW!!
    this.MoveVecX = this.RunAcc;

    // 向きによって画像を反転    ← NEW!!
    transform.localScale = new Vector3(this.Dir, 1, 1);

    return (int)State.Run;
}

最後に、Update()で「移動量」をtransform.localPositionに加える。
その際、「移動量(X)」に「向き」をかけてあげれば、左向きならマイナス、右向き方向に移動するようになります。

// 移動量を位置に反映  ← NEW!!
transform.localPosition += new Vector3(this.MoveVecX * this.Dir, this.MoveVecY, 0);

また、立ち状態の時は、X方向の移動量が0になるような処理も加えました。
いうなれば、ブレーキ。

// 速度は減速し、0に収束する  ← NEW!!
if ((this.MoveVecX -= this.RunDec) < 0.05f)
{
    this.MoveVecX = 0.0f;
}

そして、今回のサンプル

左右キーで移動。
上下で速度増減。

速くし過ぎると、勢い余って壁を突き抜けて返ってこなくなるので注意(笑)

Y軸方向はなにもやっていないので、不自然。
次回以降何とかする予定です。


それでは夜も更けてきたので、今回はこのあたりで。
おやすみなさい。