練習課題:指 1 本で遊べる
Assets/
Scenes/
Arena.unity
Scripts/
Settings/
everything from tab 01–03
すでにあるものこのレッスンで追加
Arena に、キーボード・ゲームパッド・タッチの三つを単一の action map で動かす操作リグを備えましょう。壁を突き抜けない三人称カメラも一緒に設定します。手ブレがなく、攻撃が当たったときだけ小さく振動し、必殺技では見栄えの良いアングルへ切り替わります。
再利用するもの
三台の設備、ひとつの action map、ひとつのカメラリグ。
パート 1 — ひとつの action map ですべてをまかなう
一つの action に対して、三台の設備分のバインディングをまとめて付けます。if (touch) … else if (keyboard) … を書きそうになったら、そこで手を止めてください。action map はまさにそれを防ぐためにあります。
Map: Gameplay
Move Value / Vector2
├─ 2D Vector Composite W A S D
├─ Gamepad <Gamepad>/leftStick
└─ On-Screen Stick (bound from the UI prefab)
Look Value / Vector2
├─ Pointer delta <Mouse>/delta
├─ Gamepad <Gamepad>/rightStick
└─ Touch drag (right half of the screen)
Jump Button
├─ <Keyboard>/space ├─ <Gamepad>/buttonSouth └─ On-Screen Button
Skill1 / Skill2 / Skill3 Button
├─ Q E R ├─ West / North / buttonEast └─ On-Screen Buttons
Pause Button
├─ <Keyboard>/escape └─ <Gamepad>/start
Map: UI ← enabled only while paused
Navigate · Submit · Cancelusing UnityEngine;
using UnityEngine.InputSystem;
public class InputRouter : MonoBehaviour
{
private PlayerControls controls;
public Vector2 Move { get; private set; }
public Vector2 Look { get; private set; }
public bool JumpQueued { get; private set; }
[SerializeField] private SkillCaster caster;
void Awake()
{
controls = new PlayerControls();
var g = controls.Gameplay;
g.Move.performed += c => Move = c.ReadValue<Vector2>();
g.Move.canceled += _ => Move = Vector2.zero;
g.Look.performed += c => Look = c.ReadValue<Vector2>();
g.Look.canceled += _ => Look = Vector2.zero;
g.Jump.performed += _ => JumpQueued = true;
g.Skill1.performed += _ => caster.TryCast(0);
g.Skill2.performed += _ => caster.TryCast(1);
g.Skill3.performed += _ => caster.TryCast(2);
g.Pause.performed += _ => TogglePause();
}
void OnEnable() => controls.Enable();
void OnDisable() => controls.Disable();
void LateUpdate() => JumpQueued = false;
void TogglePause()
{
bool paused = Time.timeScale > 0f;
Time.timeScale = paused ? 0f : 1f;
// swap which map is live
if (paused) { controls.Gameplay.Disable(); controls.UI.Enable(); }
else { controls.UI.Disable(); controls.Gameplay.Enable(); }
Cursor.lockState = paused ? CursorLockMode.None : CursorLockMode.Locked;
Cursor.visible = paused;
}
}パート 2 — カメラリグを組み立てる
Third Person Follow の Cinemachine カメラ。Follow = Knight、LookAt は胸の高さに置いた CameraTarget にします。
Camera Collision Filter に Environment レイヤーを指定すれば、壁の手前でカメラが引き寄せられ、突き抜けません。
Damping は三軸とも 0.3。重みは感じられますが、酔うほどではありません。
必殺技用に二台目のカメラ。普段は Priority 0、R を発動したときだけ 1.5 秒 20 へ引き上げます。
二台のカメラに Impulse Listener、プレイヤーに Impulse Source を置き、攻撃を当てるたびに発生させます。
using System.Collections;
using UnityEngine;
using Unity.Cinemachine;
public class CameraDirector : MonoBehaviour
{
[SerializeField] private CinemachineCamera gameplayCam;
[SerializeField] private CinemachineCamera ultimateCam;
[SerializeField] private CinemachineImpulseSource impulse;
/// call from SkillCaster when a hit lands
public void Shake(float strength = 0.35f) => impulse.GenerateImpulseWithForce(strength);
/// call when the ultimate starts
public void PlayUltimateShot(float seconds = 1.5f) => StartCoroutine(Cut(seconds));
IEnumerator Cut(float seconds)
{
ultimateCam.Priority = 20;
yield return new WaitForSeconds(seconds);
ultimateCam.Priority = 0;
}
}パート 3 — タッチ操作のレイヤー
Canvas は Scale With Screen Size、基準解像度 1080 × 1920、Match 0.5 に設定します。
左下に Move へバインドした On-Screen Stick、右下にスキルボタン三つとジャンプボタンを置きます。
ルートパネルに SafeAreaFitter を付け、すべての操作要素は中央ではなく角へアンカーします。
タッチ用 Canvas はデスクトップでは丸ごと無効化します。Awake で Application.isMobilePlatform を確認してください。
void Awake()
{
bool mobile = Application.isMobilePlatform;
#if UNITY_EDITOR
mobile = forceTouchInEditor; // a bool you tick to test on desktop
#endif
touchCanvas.SetActive(mobile);
}できたことになる条件
- ✓同じビルドが、コードに分岐を一つも足さずにキーボード・接続したゲームパッド・画面のタッチ操作のすべてに反応します。
- ✓どのカメラアングルでも W は必ずカメラから遠ざかる方向へ歩きます。
- ✓キャラを壁に近づけると、カメラは壁の内侧を見せる代わりに滑らかに手前へ寄ります。
- ✓移動中にキャラが震えることはありません。カメラ処理は LateUpdate にあるからです。
- ✓攻撃が当たるたびにカメラがわずかに揺れ、0.25 秒以内に収まります。
- ✓必殺技では二台目のカメラへ切り替わり、終わったあとは自動でブレンドで戻ります。
- ✓Esc で一時停止してカーソルが解放され、ゲームへの入力も止まります。キャラが歩き続けることはありません。
- ✓プロジェクトの中に Input.GetAxis も Input.GetKey も一行残っていません。
狙うべき数値
| 項目 | 目標値 | 理由 |
|---|---|---|
| カメラの Damping | 0.2–0.4 s | 0.2 未満だと飛び、0.5 を超えるとプレイヤーがキャラを見失います。 |
| 振動の長さ | ≤ 0.25 s | 長いとバグに見え、モバイルでは酔いの原因になります。 |
| Pitch の制限 | -25° … 65° | 範囲を外れると、カメラが頭の上までひっくり返ります。 |
| タッチ領域のサイズ | ≥ 44 pt | これより小さいと、実機では親指で何度も外します。 |
もっとやりたい人へ
感度スライダーと Y 軸反転のトグルを追加し、設定をプレイをまたいで保持するようにします。
操作中のデバイスを検知し、画面のキーヒントを Q/E/R とゲームパッドのアイコンで切り替えます。
カメラのロックオンを追加。マウスの中ボタンで最も近い敵を画面に収めます(Tab はすでにキャラ切り替えに使っています)。
Cinemachine の拡張を使い、プレイヤーが壁に近づいたらカメラをズームインさせます。