练习:一根拇指就能玩
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 部分 —— 相机装置
一个 Cinemachine 相机,用 Third Person Follow:Follow = Knight,LookAt 指向胸口高度的 CameraTarget。
Camera Collision Filter 选你的 Environment 层,遇到墙时相机会自己收进来而不是穿过去。
三个轴的 Damping 都是 0.3 —— 够沉稳,又不至于晃得人头晕。
给大招准备第二个相机,平时 Priority 0,按 R 放招时提到 20,持续 1.5 秒。
两个相机都挂 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。
左下角:On-Screen Stick 绑到 Move。右下角:三个技能键加一个跳跃键。
根面板上加 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);
}怎样算做完
- ✓同一个 build 不加任何代码分支,就能同时响应键盘、插入的手柄和屏幕上的触控。
- ✓在任何机位下按 W,角色都是朝远离相机的方向走。
- ✓角色走到墙里时,相机平滑地收进来,而不是让你看见墙的内侧。
- ✓移动时角色不会再发抖 —— 因为相机逻辑写在 LateUpdate 里。
- ✓每次命中相机只轻微晃一下,0.25 秒内就停下。
- ✓放大招时切到第二个相机,结束后自动混合回来。
- ✓按 Esc 会暂停、释放鼠标,游戏输入也停了 —— 角色不会还在那儿往前走。
- ✓整个项目里再也找不到 Input.GetAxis 或 Input.GetKey。
需要达到的数字
| 指标 | 目标值 | 原因 |
|---|---|---|
| 相机 Damping | 0.2–0.4 s | 低于 0.2 会太生硬,高于 0.5 玩家会跟不上角色。 |
| 震动时长 | ≤ 0.25 s | 再长就像 bug,在手机上还会让人头晕。 |
| 俯仰角限制 | -25° … 65° | 超出这个范围相机会翻到头顶上去。 |
| 触控区域尺寸 | ≥ 44 pt | 再小的话,真机上拇指会一直点空。 |
想再多做点
加一个灵敏度滑条和一个反转 Y 轴开关,并在多次游玩之间保留设置。
识别当前使用的设备,在 Q/E/R 和手柄图标之间切换屏幕上的按键提示。
加一个锁定相机的功能:点鼠标中键把最近的敌人套进取景框(Tab 已经用来切换角色了)。
用 Cinemachine 的扩展,在玩家贴近墙时把相机拉近。