ロックマン的なものでUnity2Dを勉強 その7
こんばんは! しんがです。
前回に引き続き、ロックマン的なものでUnity2Dのお勉強。
今回もキャラクターの移動をやってみます。
前回はX方向だったので、今回はY方向(ジャンプとか)を。
今回やろうとしていること
- ジャンプ処理の実装
コメントでご指摘いただいたのですが、
前回のソースだと、入力からキャラが動き出すまで1フレーム遅れますね…
入力判定 + 状態遷移で1フレーム。
遷移後の行動は次のフレームから始まる。
入力判定 + 状態判定のメソッド
走りやジャンプなど実際のアクションの実装(移動量の増減とか)は、
判定のメソッドと分けてFixedUpdate内で実装(実行)した方がいいのかな…
イメージ
Update(){ // アクション判定 NowState = ActionState()[nowState]; } FixedUpdate(){ // アクション実装 ActionImpl()[nowState]; } idleState(){ // idle状態での状態遷移判定 } idleImpl() { // idle状態の移動量実装(減速とか)}
もしくは、遷移すると同時に初速を与えてしまうか。
ひとまず、基本的な動作ができてから考えよ;
ジャンプ処理
ソース、ごちゃごちゃしてきた…
using UnityEngine; using System.Collections.Generic; using System.Reflection.Emit; // 状態列挙体 public enum State : int { Idle=0, // 立ち Run, // 走り Jump, // ジャンプ Dmage, // ダメージ Thiun // ティウン }; /// <summary> /// Numbersクラス /// キャラクターのベースとなるクラス。 /// 基本のアクションを実装する。 /// </summary> public class Numbers : MonoBehaviour { // アクション関数格納用デリゲート public delegate int Action(); public LayerMask MapLayer; // 状態マップ public Dictionary<int, Action> actMap = new Dictionary<int, Action>(); // 状態 public int NowState {get; set; } // 向き 左:-1 / 右:+1 public int Dir { get; set; } // 空中フラグ private bool isAir { get; set; } // 走り速度 public float RunAcc; // 走りブレーキ public float RunDec; // ジャンプ/落下速度 public float JumpAcc; public float FallAcc; // 移動量 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); // 初期値で向きをセット this.Dir = 1; } // Update is called once per frame void Update () { // 前処理 // 空中判定 this.isAir = !Physics2D.Linecast( transform.position + transform.up * 0.1f, transform.position, MapLayer ); // 空中だったら、空中状態にセット if (this.isAir) { this.NowState = (int)State.Jump; } // 状態マップから次の状態を取得 this.NowState = (int)actMap[this.NowState](); // Animatorコンポーネントの「NowState」プロパティに現在の状態を渡す GetComponent<Animator>().SetInteger("NowState", this.NowState); // 後処理 // 向きによって画像を反転 transform.localScale = new Vector3(this.Dir, 1, 1); // 空中だったら重力の影響を与える(落下速度を与える) if (this.isAir) { this.MoveVecY -= this.FallAcc; } // 移動量を位置に反映 transform.localPosition += new Vector3(this.MoveVecX * this.Dir, this.MoveVecY, 0); Debug.Log("NowState:" + this.NowState + "/ isAir:"+this.isAir); } /// <summary> /// 状態:立ち /// </summary> /// <returns></returns> private int idle(){ // L/Rが押されたら走り状態に遷移 if (Input.GetKey("left")) { this.Dir = -1; return (int)State.Run; } if(Input.GetKey("right")) { this.Dir = 1; return (int)State.Run; } // スペースが押された瞬間ジャンプ状態に遷移 if (Input.GetKeyDown("space")) { // ジャンプの初速をセット this.MoveVecY = this.JumpAcc; return (int)State.Jump; } // 速度は減速し、0に収束する if ((this.MoveVecX -= this.RunDec) < 0.05f) { this.MoveVecX = 0.0f; } // 何もなければ立ち状態を継続 return (int)State.Idle; } /// <summary> /// 状態:走り /// </summary> /// <returns></returns> private int run(){ // スペースが押された瞬間ジャンプ状態に遷移 if (Input.GetKeyDown("space")) { // ジャンプの初速をセット this.MoveVecY = this.JumpAcc; return (int)State.Jump; } // L/Rが押されていないならば立ち状態に遷移 if (Input.GetKeyUp("left") || Input.GetKeyUp("right")) { return (int)State.Idle; } // 上記以外は、移動量(X)をセットし、走り状態を継続 this.MoveVecX = this.RunAcc; return (int)State.Run; } /// <summary> /// 状態:ジャンプ /// </summary> /// <returns></returns> private int jump(){ // 空中での移動判定(L /Rキー) if (Input.GetKey("left")) { this.Dir = -1; this.MoveVecX = this.RunAcc; } else if (Input.GetKey("right")) { this.Dir = 1; this.MoveVecX = this.RunAcc; } else { // どちらも押されてなかったら移動速度(X)を0にする this.MoveVecX = 0; } // スペースが離された if (Input.GetKeyUp("space")) { // かつ、上昇中の場合 if (this.MoveVecY > 0) { // ジャンプ加速度を0にする。(落下しはじめる) this.MoveVecY = 0; } } if(this.isAir){ // 空中の場合、ジャンプ状態を継続 return (int)State.Jump; } else { // 地面の場合、落下速度を0にして立ち状態に遷移 this.MoveVecY = 0; return (int)State.Idle; } } }
ジャンプの肝を抜き出す。
// 空中フラグ private bool isAir { get; set; } // ジャンプ/落下速度 public float JumpAcc; public float FallAcc; // 空中判定 this.isAir = !Physics2D.Linecast( transform.position + transform.up * 0.1f, transform.position, MapLayer ); if (this.isAir) { this.NowState = (int)State.Jump; } // (1)スペースが押された瞬間ジャンプ状態に遷移 if (Input.GetKeyDown("space")) { // ジャンプの初速をセット this.MoveVecY = this.JumpAcc; return (int)State.Jump; } // (2)空中だったら重力の影響を与える(落下速度を与える) if (this.isAir) { this.MoveVecY -= this.FallAcc; } else { // (3)地面の場合、落下速度を0にして立ち状態に遷移 this.MoveVecY = 0; return (int)State.Idle; }
空中判定は、こちらのブログが詳しいです。
[Unity]Unity4.3の2Dツールを使ってみる -Physics2Dスクリプト編その1- | クスールブログ
ジャンプ処理のイメージ図
- ジャンプに遷移した瞬間に、移動量Yに初速(JumpAcc)をセット
- 空中にいる間は、移動量Yに落下速度(FallAcc)を与え続ける
- 着地したら、移動量Yを0にしておく
移動量Yは初速でバーンと増加、その後、落下速度の影響でじわじわと減少する。
物理演算とかしなくても、わりと自然な放物線を描きます。
あたり判定とかガタガタだけど、ひとまず…
サンプル
なかなか、考えなくちゃいけないことが多いなぁ…
あと、こちらを参考に今回からソースをリポジトリに登録するようにしました。
http://terasur.blog.fc2.com/blog-entry-171.html
ソース管理もできたし今回はこの辺りで。おやすみさい。