【Unity2D】Controllerスクリプトを整えよう

Unity2D

Unity2D ARPG

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

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

キー入力関連のスクリプトファイルを整理しましょう。

現状、キー入力を受け付けてそれに対して配列に押されているキーが保持される仕組みになっています。

基本的にはこの配列を見て処理をするのですが、他のコードを見てみると条件分岐にキー入力を書いてたりしています。

これはあまりよろしくないので調整しましょう。

少し回りくどいですが、コントローラークラスの管理クラス(コントローラーマネージャー)を作ろうと思います。

コントローラースクリプトは基本的に入力されたものに対して状態を変化させるだけのスクリプトです。

コントローラーマネージャーは値の保持と外部から参照してもらうための仕組みだけを持ち、
マネージャーを継承したクラスが値を変更するという感じです。

クラスを継承していないと変更できないようにするためには、protectedのアクセサつけましょう。

こうすることで外部のクラスからは書き替えられないようにする仕組みです。

Controllerクラスのキー処理だけを抜粋

まずはマネージャークラスを作る前にControllerクラスのキー処理だけを抜き出してみましょう。

思いのほかかなりシンプルになると思います。

作業する前にバックアップは取っておきましょう。

アクション系処理に入っているキー入力一旦無視してみます。

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

public class Controller : MonoBehaviour
{

    // キー入力順番配列
    private List<KeyCode> PushedKeyList = new List<KeyCode>();
    private List<KeyCode> PushedArrowKeyList = new List<KeyCode>();

    // 毎フレーム更新
    void Update()
    {
      // キー入力監視
      KeyCheck();
    }

    // キーのリスト入れ替え関数
    private void KeyAddRemove(KeyCode keycode) {
        if (Input.GetKey(keycode)) {
            // Linqの機能:リストに指定物が中身になければリストに加える
            if (!(PushedArrowKeyList.Contains(keycode))) {
                // あれば削除
                PushedKeyList.Add(keycode);
                // 方向キーのみ
                PushedArrowKeyList.Add(keycode);
            }
        } else {
            // Linqの機能:リストに指定物が中身にあればリストにから外す
            if (PushedArrowKeyList.Contains(keycode)) {
                // あれば削除
                PushedKeyList.Remove(keycode);
                // 方向キーのみ
                PushedArrowKeyList.Remove(keycode);
            }
        }
    }



    // キーチェック関数
    private void KeyCheck() {
        // 十字(上下左右)
        KeyAddRemove(KeyCode.LeftArrow);
        KeyAddRemove(KeyCode.RightArrow);
        KeyAddRemove(KeyCode.UpArrow);
        KeyAddRemove(KeyCode.DownArrow);

        // 掴み(G)
        KeyAddRemove(KeyCode.G);
        // 防御(S)
        KeyAddRemove(KeyCode.S);
        // 回避(D)
        KeyAddRemove(KeyCode.D);
    }
}

だいぶスッキリしました。

そしてキー配列に格納する関数「KeyAddRemove」は親クラスで用意したListを操作するために書き替えます。

Controller_Managerスクリプトの作成

書き替える前にGameStateスクリプトを作って継承出来るか試してみましょう。

以下の「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() {
    }

    // 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);
    }

}

変数について

List型の配列をコチラに持ってきました。

アクセサをprotectedにしているのでこのクラスを継承すればアクセス可能になります。

Update関数について

これもprotectedが付いてますね。

後はvirtual。

これは子クラスが上書きしてもいいですよという感じの宣言です。

子クラスで書き替えてもいいですが、親のUpdateも呼んでから子も独自の処理が実行できます。

ここではListの中身を表示する関数を呼び出しています。

普通にDebug.Logでは型情報しかみられないので仕方なしです。

ShowListContentsInTheDebugLog関数について

これがListの中身を表示してくれる関数です。

UnityでListの中身をDebug.Logに表示する
https://qiita.com/shiratori1221/items/2e35dd53fcbcab42d6d9

コチラの記事を参考にさせてコピペさせてもらいました。

Controller_Playerスクリプトの作成

Controllerスクリプトの名前を変更しましょう。

名前を変更したら一応クラス名も併せて変更します。

以下のようになりました。

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

public class Controller_Player : Controller_Manager
{
    // 毎フレーム更新
    protected override void Update()
    {
        // キーの中身を表示
        ShowListContentsInTheDebugLog(PushedKeyList);
        // キー入力監視
        KeyCheck();
    }

    // キーのリスト入れ替え関数
    private void KeyAddRemove(KeyCode keycode) {
        if (Input.GetKey(keycode)) {
            // Linqの機能:リストに指定物が中身になければリストに加える
            if (!(PushedArrowKeyList.Contains(keycode))) {
                // あれば削除
                PushedKeyList.Add(keycode);
                // 方向キーのみ
                PushedArrowKeyList.Add(keycode);
            }
        } else {
            // Linqの機能:リストに指定物が中身にあればリストにから外す
            if (PushedArrowKeyList.Contains(keycode)) {
                // あれば削除
                PushedKeyList.Remove(keycode);
                // 方向キーのみ
                PushedArrowKeyList.Remove(keycode);
            }
        }
    }


    // キーチェック関数
    private void KeyCheck() {
        // 十字(上下左右)
        KeyAddRemove(KeyCode.LeftArrow);
        KeyAddRemove(KeyCode.RightArrow);
        KeyAddRemove(KeyCode.UpArrow);
        KeyAddRemove(KeyCode.DownArrow);

        // 掴み(G)
        KeyAddRemove(KeyCode.G);
        // 防御(S)
        KeyAddRemove(KeyCode.S);
        // 回避(D)
        KeyAddRemove(KeyCode.D);
    }
}

クラスの継承

Controller_Player : Controller_Manager

という風にコロンで区切って親クラスの名前を書くだけです。

Unityではスクリプトファイルを作ると「MonoBehaviour」を継承している感じになっています。

protected override void Update()について

親ではvirtualにしましたが、子ではoverrideにします。

こうすることで上書きをするという仕組みになっています。

本来は親のメソッドも読んでやらないといけないのですが、Unityではそれをしなくても大丈夫そうでした。

むしろそれをやると親のupdateと自分のupdate両方読んじゃうので、
親側は抽象化(virtual)にしておいて中身は空で子でupdateを実装しましょう。

Unityはコンポーネント志向なのであまりこういう継承でのやり方は向いてないみたいです。

なのでクラスの継承は極力少なくしていきましょう。

Updateの中身はキーリストのデバッグ表示とキー入力受付だけです。

そしてこの2つのスクリプトを空のオブジェクトを作ってアタッチしましょう。

私は空のゲームマネージャーというクラスを作ってその下にコントローラーマネージャーというオブジェクトを作ってそこに2つとも貼り付けました。

なのでプレイヤーオブジェクトのスクリプトからControllerを外しています。

問題なくキー入力が出来てたらOKです。

次回はアクション処理を整理していきましょう。

それでは。