【Unity2d】斜め移動とグリッド移動の追加

Unity2D

Unity2D ARPG

こんにちは。なおキーヌです。

ブログ毎日更新は338日目になります。

基本的な移動スクリプトは完成したのであとは機能を追加というか元あった機能を付けましょう。

ひとまずは斜め移動の機能を取り戻すために十字移動の関数を改良とグリッド移動の仮実装をします。

斜め移動をするための改良

前までは十字移動中に2つ目に何が押されていたかによって処理を切り分けていました。

今回も基本的には同じ仕組みにしますが、現状Player_Stateの_direction変数で方向をチェックしています。

0~3しか使ってないので他の数値に割り当てれば斜め判定が出来ます。

setDirection関数が今のところ0個目の十字キーしか受け付けてないので、
2つ目の引数を付けるかリストそのものを渡しましょう。

後に拡張するかもしれませんし引数を増やしたくないので私はリストを渡します。

State_ManagerのsetDirectionを改良してください。

  // 向き変数変更
  protected void setDirection(List<KeyCode> arrowDirect) {
    // 押されているキーが2つ以上あるか調べる
    bool flag = arrowDirect.Count > 1;

    switch(arrowDirect[0]) {
      case KeyCode.DownArrow:
        _direction = 0;
        if(flag) {
          switch (arrowDirect[1]) {
            case KeyCode.LeftArrow:
              _direction = 10;
              break;
            case KeyCode.RightArrow:
              _direction = 20;
              break;
          }
        }
        break;
      case KeyCode.UpArrow:
        _direction = 1;
        if(flag) {
          switch (arrowDirect[1]) {
            case KeyCode.LeftArrow:
              _direction = 11;
              break;
            case KeyCode.RightArrow:
              _direction = 21;
              break;
          }
        }
        break;
      case KeyCode.LeftArrow:
        _direction = 2;
        if(flag) {
          switch (arrowDirect[1]) {
            case KeyCode.DownArrow:
              _direction = 12;
              break;
            case KeyCode.UpArrow:
              _direction = 22;
              break;
          }
        }
        break;
      case KeyCode.RightArrow:
        _direction = 3;
        if(flag) {
          switch (arrowDirect[1]) {
            case KeyCode.DownArrow:
              _direction = 13;
              break;
            case KeyCode.UpArrow:
              _direction = 23;
              break;
          }
        }
        break;
      default:
        _direction = -1;
        break;
    }
    Debug.Log(_direction);

  }

連番じゃなく2つ目のキーが押されて居たら2桁目を増やす感じにすれば可読性も高くなります。

2つ目はリストの数が1つより大きい場合にのみ実行します。

そうでないとない所を参照してしまうのでいわゆるエラー対策の一環です。

もうちょっとスリムな書き方出来そうな気がしますが、今の私にはわかりません(笑)

これで斜め押しができるようになっています。

Debug.Logを入れているので確認してみてください。

これで斜め移動の判断ができるようになりました。

後は_directionを元に移動数値の設定をきめます。

Move_PlayerのdotMove関数に書き加えましょう。

    // ドット移動関数
    protected override void dotMove() {
        float vx = 0;
        float vy = 0;

        if (_State.ActState == 1) {
            switch(_State.Direction%10) {
                case 0:
                    vy = -_speed;
                    break;
                case 1:
                    vy = _speed;
                    break;
                case 2:
                    vx = -_speed;
                    break;
                case 3:
                    vx = _speed;
                    break;
                default:
                    break;
            }
            switch(_State.Direction) {
                case 10:
                case 11:
                    vx = -_speed;
                    break;
                case 20:
                case 21:
                    vx = _speed;
                    break;
                case 12:
                case 13:
                    vy = -_speed;
                    break;
                case 22:
                case 23:
                    vy = _speed;
                    break;
            }
        }
        // 実際のドット移動
        _Player.transform.GetComponent<Rigidbody2D>().velocity = new Vector2(vx, vy);
    }

これで移動は元通りになりましたね。

「_State.Direction%10」

これ(10で割った余り)は1桁目を取ることが出来る計算方法なのでとても便利です。

覚えておきましょう!

グリッド移動の実装

お次はグリッド移動です。

今回は一旦特定のキーを押している時だけグリッド移動をするという仕組みにしてみましょう。

基本的1グリッドは16×16ののサイズになります。

なので1度やっていますが16で割った余りが0になったら止まることが出来るわけですね。

Unityでの移動は小数点を含むので、切り捨てとかしてあげないと永久に止まってくれません。

無理矢理切り捨てたりするとカクッって動いてしまうのでそこも気を付けなければいけません。

とりあえずGを押している間はグリッド移動に切り替えるようにしてみます。

State_ManagerのsetStateに追記します。

  // 押しているキーによってステートを変更
  protected void setState(List<KeyCode> keyList) {
    // とりあえずステートリセット(その場止まり)
    _actState = 0;
    // 移動状態にするかどうか
    if (keyList.Contains(KeyCode.DownArrow) || keyList.Contains(KeyCode.UpArrow) || keyList.Contains(KeyCode.LeftArrow) || keyList.Contains(KeyCode.RightArrow)) {
      _actState = 1;
    }
    // 掴み状態にする(今はグリッド切り替え)
    if (keyList.Contains(KeyCode.G)) {
      _actState = 5;
    }
  }

  // 移動タイプ変更
  protected void setMoveType() {
    switch(_actState) {
      case 5:
        _moveType = 1;
        break;
    }
  }

Gを押された時に優先して状態を5にしておきます。

次に状態が5になったときにグリッド移動に切りえるメソッドを呼びます。

本来はドット移動に戻しますが一旦Gを押したらグリッド移動に切り替えるようにしましょう。

これはState_Playerの方で呼び出します。

  protected override void Update() {
    // 十字キーが一つでも格納されてたら稼働
    if (_cm.PushedArrowKeyList.Count > 0) { setDirection(_cm.PushedArrowKeyList); }
    // ステートをセットする
    setState(_cm.PushedKeyList);
    // 向きとステートを元にアニメーションを設定
    setNowAnim(_animator);
    // 移動タイプ変更
    setMoveType();
  }

次にMove_Playerを改変します。

一旦現状のMove_Playerスクリプトをすべて載せておきます。

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Move_Player : Move_Manager
{
    // プレイヤーオブジェクト
    private GameObject _Player;
    // プレイヤーステートスクリプトの取得
    private State_Player _State;

    private float _speed = 30;

    private bool _isMove = false;



    // 更新処理
    protected override void Start() {
        // プレイヤーオブジェクトの取得
        _Player = GameObject.FindGameObjectsWithTag("Player")[0];
        _State = GameObject.FindGameObjectsWithTag("State_Manager")[0].GetComponent<State_Player>();
    }
    protected override void Update() {
        if (_State.MoveType == 1) {
            gridMove();
        } else {
            dotMove();
        }
    }

    // ドット移動関数
    protected override void dotMove() {
        float vx = 0;
        float vy = 0;

        if (_State.ActState == 1) {
            switch(_State.Direction%10) {
                case 0:
                    vy = -_speed;
                    break;
                case 1:
                    vy = _speed;
                    break;
                case 2:
                    vx = -_speed;
                    break;
                case 3:
                    vx = _speed;
                    break;
                default:
                    break;
            }
            switch(_State.Direction) {
                case 10:
                case 11:
                    vx = -_speed;
                    break;
                case 20:
                case 21:
                    vx = _speed;
                    break;
                case 12:
                case 13:
                    vy = -_speed;
                    break;
                case 22:
                case 23:
                    vy = _speed;
                    break;
            }
        }
        // 実際のドット移動
        _Player.transform.GetComponent<Rigidbody2D>().velocity = new Vector2(vx, vy);
    }

    // グリッド移動関数
    protected override void gridMove() {

        float vx = 0;
        float vy = 0;

        if (_State.ActState == 1 || _isMove) {
            _isMove = true;
            switch(_State.Direction%10) {
                case 0:
                    vy = -_speed;
                    break;
                case 1:
                    vy = _speed;
                    break;
                case 2:
                    vx = -_speed;
                    break;
                case 3:
                    vx = _speed;
                    break;
                default:
                    break;
            }
        }
        // 実際の移動
        _Player.transform.GetComponent<Rigidbody2D>().velocity = new Vector2(vx, vy);

        // 
        if ( Math.Floor(_Player.transform.position.x)%16 == 0 && Math.Floor(_Player.transform.position.y)%16 == 0 ) {
            _isMove = false;
        }

    }

}

gridMove関数を作りましたが、これは欠陥があります。

グリッド移動自体はできますが、現状移動中にも方向転換できてしまうので
結果的に割り切れない状態が続いてしまい動き続けてしまいます。

なので移動中は別のキーを押さないでグリッド移動を試してみてください。

xもyも16で割り切れたらとまるようになっています。

今は移動中かどうかというフラグを設けていますが、実際は_actStateで管理していきます。

_actStateが例えば11の時はキー入力を一切受け付けない等の仕組みにして、
向いてる方向に移動し続け割り切れるまで移動するという風にすればOKです。

グリッド移動は後に改善しましょう。

次回は掴みモードを実装するのでグリッド移動は引きずるところまで一旦封印します。

それでは。