simplestarの技術ブログ

目的を書いて、思想と試行、結果と考察、そして具体的な手段を記録します。

Unity:CubeWalkゲームにてCtrl キーを押すとカーソルが現れる

まえがき

Unity で三人称視点でキャラクターを動かすアセットを利用しています。
assetstore.unity.com
このアセットをアクティブにするとマウスカーソルが消えてしまいます。

f:id:simplestar_tech:20190923120414p:plain
キャラクターがロードされるとマウスカーソルが消える(ロックされる)

変えたいこととしては、Ctrl キーを押した時にマウスカーソルが現れ、カメラの回転が固定される
また、できればそのカーソルはゲーム内であればカスタマイズされたカーソルであってほしい
Ctrl キーをもう一度押したらカーソルは消え、カメラの回転が有効になる
カーソルがアクティブになっていることは、そのロジックを司るコンポーネントからイベントで知ることができる

今の所、上記の機能は一つも実現できていないので、記事の最後にこれらが実現されたことをもって完了としたいと思います。

新しいコンポーネント

ゲームのロジックを司るコンポーネントになります。

シーン内でアクティブとなっているゲームのロジックはすべてヒエラルキーの GameManager オブジェクトの下にぶら下がっており
大枠で
PlayFab
World
Character
に分類されています。

ゲーム開始直後に PlayFab のユーザーとしてログインするのが PlayFab の処理
Cube の世界がプレイヤーを中心に広がっていく現象を司るのが World の処理
VRoidHub からキャラクターデータを作成して、プレイヤーを動作させることができるのが Character の処理
に分類されます。

ゲームに関するユーザー入力、モードの切り替わりなどは新しく Game の処理として
GameInputMode としてコンポーネントを切ってみます

ボタン押下の取得

Unity におけるキー押下の取得は InputSystem に移行します。
Input System 1.0.0 を Package Manager 経由でインストールしていくつかサンプルを確認します。
一番直感的なのは InputAction をフィールドに、インスペクタでボタン配置を指定するやり方

次の通り、Left Ctrl キーを押したことを検知するハンドラ登録をして、インスペクタで Ctrl であることを明示します。

時間は経っていますが、おおむね半年前と使い方は変わっていない模様
simplestar-tech.hatenablog.com

using UnityEngine;
using UnityEngine.InputSystem;

public class GameInputMode : MonoBehaviour
{
    public InputAction miningAction;

    private void Awake()
    {
        miningAction.performed +=
            ctx =>
            {
                this.miningMode = !this.miningMode;
                Debug.Log($"this.miningMode = {this.miningMode}");
            };
    }

    public void OnEnable()
    {
        miningAction.Enable();
    }

    public void OnDisable()
    {
        miningAction.Disable();
    }

    void Start()
    {
        
    }

    void Update()
    {
        
    }

    bool miningMode = false;
}

インスペクタでは + ボタンを押して Binding を選び Keyboard の Left Ctrl を選びます。
動作は問題ない

カーソルのロックの犯人探しとロック解除

三人称視点でキャラクターを動かすアセットがどこで何をしているのか確認してみます。

以下の通り VRM キャラクターに割り当たる vThirdPersonInput を見つけ出して、ロック関数を呼ぶと良い模様

var vInput = vrmCharacters.GetComponentInChildren<vThirdPersonInput>();
// カーソル再表示とカーソルロック解除
vInput.ShowCursor(vInput.lockInput);
vInput.LockCursor(vInput.lockInput);

ボタン押下時にためしたところ期待通り…動きました。

カメラ回転の停止

カメラの制御は CinemachineFreeLook の Axis Control にまかせているので、ここで Mouse Y, Mouse X を指定しているのでカメラが回転します。

一時的に Input Axis Name を空にすることで動かなくなるはずです。
ランタイムで切り替えられるかだけ確認します。

    /// <summary>
    /// Free Look カメラのロック
    /// </summary>
    /// <param name="lockFreeLook">ロックするときは true </param>
    void LockFreeLook(bool lockFreeLook)
    {
        var axisNameX = "";
        var axisNameY = "";
        if (lockFreeLook)
        {
            this.cinemachineFreeLook.m_XAxis.m_InputAxisValue = 0;
            this.cinemachineFreeLook.m_YAxis.m_InputAxisValue = 0;
        }
        else
        { 
            if (null != Gamepad.current)
            {
                axisNameX = "RightAnalogHorizontal";
                axisNameY = "RightAnalogVertical";
            }
            else
            {
                axisNameX = "Mouse X";
                axisNameY = "Mouse Y";
            }
        }
        this.cinemachineFreeLook.m_XAxis.m_InputAxisName = axisNameX;
        this.cinemachineFreeLook.m_YAxis.m_InputAxisName = axisNameY;
    }

問題なくカメラ制御を切り替えることができました。

カーソルをゲーム用に置き換える

これにはCursor.SetCursorを使います。情報ソースはこちら
kan-kikuchi.hatenablog.com

動きます。
テストに使うカーソルとして、こちらのフリーアセットを使ってみました。
assetstore.unity.com

カーソルのサイズを変更したいので Texture2D を任意のサイズにリサイズします。
リサイズには
TextureScale - Unify Community Wiki
のクラスを利用できました。

最終的に落ち着いたカーソル置換のコードがこちら

    void SetCursorImage(Texture2D cursorTexture)
    {
        // TextureScale.Bilinear(cursorTexture, 16, 16);
        Vector2 hotspot = new Vector2(0.293f, 0.078f) * 64;
        // カーソルの画像を Texture に設定
        Cursor.SetCursor(cursorTexture, hotspot, CursorMode.ForceSoftware);
    }

入力モード切り替えのイベント

UnityAction を受け付けるようにします。

    internal UnityAction<bool> OnChangeInputMode;

    public InputAction miningAction;

    private void Awake()
    {
        miningAction.performed +=
            ctx =>
            {
                this.miningMode = !this.miningMode;
                this.LockUnlockCursor(this.miningMode);
                this.LockFreeLook(this.miningMode);
                this.OnChangeInputMode?.Invoke(this.miningMode);
            };
    }

これで外部から入力がどのように切り替わったか確認、処理できるようになります。
カーソル変更はその先にしたいので、このコンポーネントからカーソルは引き剥がしたほうが良さそう

まとめ

Ctrl キーを押した時にマウスカーソルが現れ、カメラの回転が固定される
そのカーソルはゲーム内であればカスタマイズされたカーソルとなった
Ctrl キーをもう一度押したらカーソルは消え、カメラの回転が有効になる
カーソルがアクティブになっていることをイベントで知ることができる

まえがきでやりたいと思ったことは、実現できました。