Unity 6でのOn-Screen Stickコンポーネントの使い方

(モバイル向け仮想スティックの実装)

はじめに

Unity 6では、新しいInput Systemに対応した On-Screen Stick コンポーネント が提供されています。

これを利用すると、モバイルゲームで一般的な「仮想スティック」を簡単に導入でき、タッチ操作をキャラクター操作へスムーズに結びつけられます。

本記事では、Unity 6に標準で付属する InputSystem_Actions を活用し、On-Screen Stickを使ってキャラクターを移動させる方法を解説します。


1. On-Screen Stickとは?

On-Screen Stickは、UI上に配置してタッチ入力を受け取るための仮想ジョイスティックです。

  • 新Input System専用
  • UI要素(Image)にアタッチして利用
  • Input ActionsのMoveアクションなどにバインド可能

2. Canvasへの配置方法

Unityには「UI → On-Screen Stick」というメニューは存在しません。

Imageを自作し、その子要素にOnScreenStickを追加するのが正しい手順です。

手順

  1. GameObject > UI > Canvas を作成
  2. Canvas の子に Image を作成 → 名前を StickBackground(スティック土台)
  3. StickBackground の子にもう一つ Image を作成 → 名前を StickHandle(スティックつまみ)
  4. StickHandle に OnScreenStick コンポーネントを追加
  5. Control Path を “<Gamepad>/leftStick" に設定

3. Canvas構成図

Scene
├─ EventSystem
└─ Canvas (Screen Space - Overlay)
   └─ StickBackground (Image)
       └─ StickHandle (Image + OnScreenStick)

推奨設定:

  • StickBackground → Anchor: Bottom-Left、Size: 240×240
  • StickHandle → Anchor: Middle-Center、Size: 120×120、Pivot: (0.5, 0.5)

4. デフォルトInputSystem_Actionsを利用する

Unity 6では Assets/InputSystem_Actions.inputactions が自動生成されています。

Player マップの中には以下のアクションが定義済みです:

  • Move(Vector2)
  • Look(Vector2)
  • Fire(Button)
  • Jump(Button)

→ 今回は Moveアクション をOn-Screen Stickに対応させます。


5. PlayerInputとの連携

  1. プレイヤーキャラに PlayerInput コンポーネントを追加
  2. Actions に InputSystem_Actions を指定
  3. Default Map を “Player" に設定
  4. Behavior は2種類のいずれか
  • Send Messages→ OnMove(InputValue value) を自動で呼び出す方式
  • Invoke Unity Events→ Move アクションのPerformedイベントを手動で登録

6. プレイヤー移動サンプルコード

Send Messages方式(最も簡単)

using UnityEngine;
using UnityEngine.InputSystem;

[RequireComponent(typeof(CharacterController))]
public class PlayerMover : MonoBehaviour
{
    [SerializeField] float speed = 5f;
    private CharacterController controller;
    private Vector2 moveInput;

    void Awake()
    {
        controller = GetComponent<CharacterController>();
    }

    // アクション名「Move」と完全一致
    public void OnMove(InputValue value)
    {
        moveInput = value.Get<Vector2>();
    }

    void Update()
    {
        Vector3 move = new Vector3(moveInput.x, 0, moveInput.y);
        controller.Move(move * speed * Time.deltaTime);
    }
}

Unity Events方式(拡張に便利)

using UnityEngine;
using UnityEngine.InputSystem;

[RequireComponent(typeof(CharacterController))]
public class PlayerMover : MonoBehaviour
{
    [SerializeField] float speed = 5f;
    private CharacterController controller;
    private Vector2 moveInput;

    void Awake()
    {
        controller = GetComponent<CharacterController>();
    }

    // Unity Eventsから呼び出される
    public void OnMove(InputAction.CallbackContext ctx)
    {
        moveInput = ctx.ReadValue<Vector2>();
    }

    void Update()
    {
        Vector3 move = new Vector3(moveInput.x, 0, moveInput.y);
        controller.Move(move * speed * Time.deltaTime);
    }
}

7. よくあるハマりどころ

  • MissingMethodException が出る→ Send Messages方式なのに OnMove(InputAction.CallbackContext) を書いている場合。修正するか、Events方式に切り替える。
  • Editorでは動かない→ On-Screen Stickはタッチ専用。実機で確認必須。開発中はキーボードやゲームパッドも併用すると便利。
  • スティックが中央に戻らない→ HandleのRectTransformが中央揃えになっているか確認。

8. まとめ

Unity 6では、標準の InputSystem_Actions とOn-Screen Stickを組み合わせるだけで、すぐに仮想スティック操作を導入できます。

  • CanvasにImageを作成し、HandleにOnScreenStickを追加
  • Control Pathを <Gamepad>/leftStick に設定
  • PlayerInputに InputSystem_Actions を割り当て
  • OnMove(InputValue) で入力を受け取る

これで、モバイルゲームの基本操作UIが完成です。


了解です。ご指定の記事(Unity 6でのOn-Screen Stick解説)に、最小追加で「ジャンプボタン」を組み込む手順を追補します。記事本文の構成・前提(InputSystem_Actions と Send Messages 方式)に揃えています。  


追補:On-Screen Buttonでジャンプを追加する(最小構成)

1) UIにジャンプボタンを追加

Canvas 構成に JumpButton を1つ足します。

(Stick は左下、JumpButton は右下推奨)

Scene
├─ EventSystem
└─ Canvas (Screen Space - Overlay)
   ├─ StickBackground (Image)
   │  └─ StickHandle (Image + OnScreenStick)
   └─ JumpButton (Image + OnScreenButton)   ← 追加

RectTransform例

  • JumpButton:Anchor = Bottom-Right, Pivot = (0.5,0.5), Pos = (-140, 140), Size = 160×160

JumpButton のコンポーネント

  • Image:Raycast Target ✓
  • OnScreenButton:Control Path = “<Gamepad>/buttonSouth"

メモ:On-Screen Button は Control Path とアクション側バインドの一致が必須。この後で Jump アクションに buttonSouth が割り当たっているか確認します。  


2) InputSystem_Actions(既定アセット)の確認

Assets/InputSystem_Actions.inputactions の Player マップに Jump(Button) があり、Gamepad/buttonSouth がバインドされていることを確認。もし無ければ追加してください。  


3) PlayerInput(Send Messages 方式のまま)

記事と同様に Behavior = Send Messages を前提にします。

(Default Map=Player、Control Scheme に Touchscreen を含めるのも従来どおり)  


4) スクリプトにジャンプ処理を追加(差分だけ)

記事の PlayerMover をそのまま拡張します。Send Messages 方式なので、メソッド名は OnJump、引数は InputValue です(アクション名と完全一致)。  

// 追補分:Articleの PlayerMover に最小追加
using UnityEngine;
using UnityEngine.InputSystem;

[RequireComponent(typeof(CharacterController))]
public class PlayerMover : MonoBehaviour
{
    [SerializeField] float speed = 5f;

    // 追加: ジャンプ関連
    [Header("Jump / Gravity")]
    [SerializeField] float jumpHeight = 1.6f;
    [SerializeField] float gravity = -9.81f;
    [SerializeField] float groundedStick = -2f; // 接地保持用の微小押し付け

    CharacterController controller;
    Vector2 moveInput;
    float verticalVelocity;

    void Awake() => controller = GetComponent<CharacterController>();

    // 既存(記事通り)
    public void OnMove(InputValue value)
    {
        moveInput = value.Get<Vector2>();
    }

    // 追加(Send Messages 用): Jump アクションと名前完全一致
    public void OnJump(InputValue value)
    {
        // ボタンが押された瞬間(isPressed)で、接地時のみ初速付与
        if (value.isPressed && IsGrounded())
        {
            // v = sqrt(2gh)(gは負)
            verticalVelocity = Mathf.Sqrt(2f * -gravity * jumpHeight);
        }
    }

    void Update()
    {
        // 水平方向移動
        Vector3 planar = new Vector3(moveInput.x, 0f, moveInput.y);
        controller.Move(planar * speed * Time.deltaTime);

        // 重力と接地維持
        if (IsGrounded() && verticalVelocity < 0f)
            verticalVelocity = groundedStick;

        verticalVelocity += gravity * Time.deltaTime;
        controller.Move(new Vector3(0f, verticalVelocity, 0f) * Time.deltaTime);
    }

    bool IsGrounded()
    {
        // 簡易:CharacterController の isGrounded
        return controller.isGrounded;
    }
}

重要ポイント

  • OnJump(InputValue) にしたのは Send Messages 仕様に合わせるため(CallbackContext ではない)。
  • PlayerInput と PlayerMover は 同一GameObject に置くのが安全(Send Messages は同一オブジェクトに送る)。
  • 実機でタッチ確認(Editor マウスでは On-Screen 系は原則反応しません)。  

5) つまずき対処(超要約)

  • 反応しない:JumpButton の Control Path と Jump アクションの バインド(buttonSouth)が揃っているか。
  • MissingMethodException:Behavior=Send Messages なのに OnJump(InputAction.CallbackContext) など シグネチャ不一致
  • 位置ズレ:JumpButton を 右下アンカー固定、Canvas は Scale With Screen Size。  

これで、シンプルなジャンプボタンが追加できます。

訪問数 40 回, 今日の訪問数 40回

Input System,Unity

Posted by hidepon