【Unity2d】移動処理スクリプトの生成:前編

Unity2D

Unity2D ARPG

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

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

長くなったので前編中編後編に分けました。

前編は作っているうちに問題が発生したのでそれの書き残しで、
後編でそれを解決するといった流れになっています。

アクション系のスクリプト第一弾は移動処理スクリプトを作っていきましょう。

移動処理スクリプトは基本的に常に稼働している状態にしておいて、
監視している配列にオブジェクトが入ったらその情報を元に移動を行うといった感じにします。

移動処理を作るにあたって、情報保持をするステートスクリプトも一緒に作っていきます。

コントローラースクリプト⇔ステートスクリプト⇔移動処理スクリプト

といった感じでステートを介して管理していくつもりです。

移動処理スクリプトの設計

設計というとよく聞こえますが、こんな感じに作っていくぜ!的なものです。

まずはコントローラーと同じように移動用のマネージャークラスを作っておきます。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Move_Manager : MonoBehaviour
{
    // 移動タイプ変数
    protected int MoveType = 0;

    // ドット移動関数
    protected virtual void dotMove() {
    }

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

    // 更新処理
    protected virtual void Update() {}

}

移動処理は不定期に発動しそうなので、一括管理は取得処理も増えそうなのであまり軽くなさそうです。

最初は一元管理でオブジェクトリストをまとめて、ループで回してオブジェクトが持つ情報を参照して
移動させようかなと思ったのですが毎回スクリプト参照をしなければいけなくなったので没。

それなら移動マネージャーで基本的な移動処理を作っておき、
マネージャーを継承した移動スクリプトを移動するオブジェクトにだけアタッチして
各々で状態を保持できるうよにして更新処理を動かせばいいんじゃないかなと思いました。

それなら毎回取得するという処理は発生せずにキャラクターを動かすことができます。

一応子クラスで処理を増やしたいとなった場合にvirtualを付けておきましょう。

子クラスを作ってプレイヤーにアタッチしよう

キー入力をしてキャラクターを動かせるように、早速子クラスを作っていきましょう。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Move_Base : MonoBehaviour
{
    // ドット移動関数
    protected override void dotMove() {

    }

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

    }

    // 更新処理
    protected virtual void Update() {
      if (MoveType == 1) {
        // ドット移動
        dotMove();
      } else if (MoveType == 2) {
        gridMove();
      }
    }

}

こんな感じで移動タイプを切り替えることによって処理を切りかえます。

プレイヤーで言うと、方向キーを押している間はMoveTypeが1になっている状態なので
キー状態を参照して移動させるといった感じです。

掴んで動かしたときはMoveTypeが2になります。

プレイヤーの状態を保持するステートスクリプトを作ろう

プレイヤーの現在入力されている状態を元に色々変化させるステートスクリプトを作ります。

大きく分けて

  • ゲームステート
  • プレイヤーステート
  • エネミーステート
  • エリア内オブジェクトステート

になります。

ゲームステートスクリプトを作り、他のそれぞれは親を継承します。

プレイヤーからゲームステートにアクセスできますが、
プレイヤーからエネミーやエリア内オブジェクトにアクセスすることは子同士できません。

もしやりたい場合は親を介しての操作になります。

移動をするために、ステートスクリプトがキー配列を参照し
現状どうするのかのステータスを保持しておきます。

例えばキー配列に右キーが最初に見つかった場合、進行方向変数を30にします。

そしてその後上下どちらかのキーが同時に押されている場合は31か32にするといった感じですね。

基本的に進行方向の後ろキーは認識しないようにしておきます。

これらの処理は今まで作ってきたスクリプトで殆どやっているのであとは少し改良するだけです。

とりあえずステート管理スクリプトを作ります。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class State_Manager : MonoBehaviour
{
  // 向き
  protected int direction = 0;
  // 移動タイプ
  protected int moveType = 0;
  // アニメーション状態
  protected int nowAnim = 0;

  protected virtual void Start() {}

  protected virtual void Update() {}
}

親クラスはオブジェクトに共通するステートを持たせておきます。

一旦思いつくのはこれぐらいですがそのうち足していきます。

そしてこれを継承したプレイヤー用ステートスクリプトを作りましょう。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class State_Player : State_Manager
{
  // キー状態リスト
  protected List<KeyCode> _PushedKeyList;

  protected override void Start() {
      // コントローラーマネージャーのキーリストを取得
      _PushedKeyList = GameObject.FindGameObjectsWithTag("Controller_Manager").GetComponent<Controller_Manager>().PushedKeyList();
  }

  protected override void Update() {
      // テストで0個目の要素を表示
      Debug.Log(_PushedKeyList[0]);
  }
}

これでキーマネージャーのリストを取得します。

キーマネージャーから取得するためにはゲッターを作ってやらなければならないので、
Controller_Managerを改良します。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;

public class Controller_Manager : MonoBehaviour
{
    // キー入力順番配列
    protected List<KeyCode> _PushedKeyList = new List<KeyCode>();
    protected List<KeyCode> _PushedArrowKeyList = new List<KeyCode>();

    protected virtual void Update() {
    }

    // _PushedKeyList用Getter
    public List<KeyCode> PushedKeyList{
        get{ return this._PushedKeyList; }  //取得用
    }    

    // Listの中身出力
    public void ShowListContentsInTheDebugLog<T>(List<T> list)
    {
        string log = "";

        foreach(var content in list.Select((val, idx) => new {val, idx}))
        {
            if (content.idx == list.Count - 1)
                log += content.val.ToString();
            else
                log += content.val.ToString() + ", ";
        }
        Debug.Log(log);
    }
}

ゲッターやセッターは変数名を同じ感じにしたいので、
変数の方はローカルという目印で先頭に「_」を付けて、ゲッターはアンダースコアがない名称にしました。

これでこのスクリプトを取得してゲッタ―を呼び出せばリストを参照できるようになるというわけです。

ここで問題が発生

ゲームステートからコントローラーのリストを参照出来てるか試したのですが、
なぜかController_Managerのリストの中身が空のまま。

もしやと思って子クラスであるController_Playerの方に切り替えたら取れていました。

この時点で思い出したのですが、C#のクラス変数はstaticを付けないとダメだということです。

付けてない場合はインスタンス変数になるので、実際に格納している子クラスのインスタンス変数になってしまっており親から取れない状態になっていました。

次回はクラス変数を活用してマネージャースクリプトからちゃんとリストを取得して
それを元に移動スクリプトを動かすように作り替えていきます。

それでは。