百分百:Unity 的事件驱动输入系统如何为《后院棒球 2026》提供控制功能

这是 Mega Cat Studios 系列博客文章的第二篇,他们分享了他们在Unity的专业知识和针对现实世界商业游戏开发挑战的解决方案。在这篇文章中,Matthew Wojtechko 探讨了如何利用 Unity 的事件驱动输入系统包来提高响应速度并减少低效的轮询。
阅读本系列的第一篇文章:扩展Unity工作流程:从中大型项目中汲取的经验教训
输入通常是我们启动游戏时首先要实现的功能,这是有充分理由的:如果无法移动角色或浏览菜单,其他一切都毫无意义。然而,“先让它运行起来”这种输入代码往往会变成永久性的。最初只是几行简单的轮询代码,但当真正需要可重新绑定控件或本地多人游戏等功能时,代码库可能会悄然崩溃。
在Mega Cat Studios ,我们放弃了逐帧检查(轮询)的方式,转而采用事件驱动的工作流程。无论我们是否正在开发用于惊吓反应的QTE,玩具熊的五夜后宫:坠入深渊或者在Backyard Baseball 2026中进行本地多人游戏,利用Unity 的输入系统包可以保持游戏的响应性和可维护性。
如果在编写输入程序时没有优先考虑以下功能,那么支持这些功能将会变得非常困难:
- 多种输入设备(键盘、控制器、触摸)
- 可重新绑定控件
- 不干扰游戏输入的用户界面导航
- 本地多人游戏
- 时效性游戏
在这篇文章中,我们将逐步介绍如何使用输入系统来解决这些问题。在此过程中,我们将讨论建筑——是什么让我们的项目能够规模化,以及是什么往往会在自身重量下崩溃。
Unity的输入系统已经发展演变。我们也一样。
Unity在 2020 年发布新的输入系统时,它不仅仅是对旧版 Input.GetAxis 和 Input.GetButtonDown 函数的重新设计。这是一种与以往截然不同的输入方式,它是事件驱动的、与设备无关的,并且以玩家意图为中心。以下是我们已经内化的核心概念。
行动
行动是构成事物的基本要素。在《后院棒球2026》中,它看起来大概是这样的:
- 动作图表示输入上下文。
- 游戏过程
- 菜单
- 调试/开发工具
- 行动体现了玩家的意图:
- 摇摆
- 滑动
- 盗垒
- 确认
- 取消
我们的游戏代码是与用户意图对话,而不是与设备对话。或许玩家按下了空格键。或者他们可能按下了PlayStation手柄上的十字键。无论如何,我们的玩家代码只需要关注“挥杆”动作何时执行。这种抽象程度让我们的生活更轻松。
绑定
绑定是具体的设备到动作的映射,使我们能够处理多种控制方案而无需增加额外的复杂性。单个操作可以响应来自多个设备的多个输入。
这样,我们就可以在不大幅修改代码的情况下,支持键盘+鼠标、控制器、触摸和辅助功能设置。我们可以在编辑器中和运行时轻松地重新绑定操作。我们将在后面的章节中对此进行更深入的探讨。
响应能力
传统意见征集依赖于民意调查:
if (Input.GetButtonDown("Swing Bat"))
{
SwingBat();
}
它很简单,但它将输入检测与帧循环联系起来。如果输入按键的按下和释放速度超过帧速率,则可能永远无法看到输入内容。
对于依赖快速反应的游戏,例如格斗、节奏和精准平台跳跃类游戏,不稳定的输入会毁掉游戏体验。即使对于节奏较慢的游戏来说,如果在关键时刻(例如在《后院棒球 2026》中击球手挥出至关重要的一击时)输入错误,也可能造成毁灭性的后果。
输入系统是围绕事件设计的。您只需订阅一次, Unity就会在有输入时通知您。这样可以降低 CPU 开销,简化逻辑,并且不会造成输入丢失的问题。从按钮的按下和释放到轴值的变化,所有操作都会排队,因此输入永远不会丢失。即使帧速率可变或低于帧权重,这些事件也会按顺序处理并可靠地传递给您的回调函数。
成果输入的内容百分百有效。
本地Multiplayer
在本地多人游戏方面,输入系统比传统的输入管理器具有显著优势。
使用 PlayerInput 组件和控制方案:
- 每个玩家都有自己的行动分层。
- 设备可以动态配对。
- 分体式键盘、多个控制器或混合设置“都能正常工作”。
值得注意的是,玩家控制功能是经过精心设计的,彼此隔离。不再出现设备索引问题或玩家之间的输入冲突。对于 Mega Cat 团队来说,在Backyard Baseball 2026中实现沙发合作模式是一个巨大的优势。
如果你的项目有本地多人游戏的可能性,那么从输入系统包入手可以为你节省很多后续的返工工作。

有时,即使使用输入系统,开发人员仍然会继续使用轮询。直接输入 Keyboard.current.spaceKey.isPressed 而无需担心任何其他设置,这本身就具有一定的吸引力。对于某些项目来说,这可能没问题,但请记住,如果您要进行长期构建,订阅输入操作回调是更好的方法。
规模化结构

读取输入很简单。真正的挑战在于创建一种架构,使输入能够适应不同的菜单、游戏模式和游戏系统。
以下是我们已在多款已发售游戏中采用的模式:
- 分离输入上下文:大多数项目至少都能从以下方面受益:
- 游戏地图——玩家移动、战斗、互动
- UI 地图 – 导航、确认/取消、滚动
- 调试映射——仅供开发人员使用的快捷方式,例如控制台切换或时间缩放。
这为什么重要?避免输入泄漏。如果不区分上下文,就很难避免极端情况,例如,按下空格键既会确认菜单,又会让玩家跳跃。动作映射允许我们在游戏状态改变时显式地启用和禁用整个输入上下文。它使得输入泄漏几乎不再是一个问题。
- 中央输入管理器:虽然输入系统支持每个对象的 InputActionReferences,但大型项目会受益于单一的、权威的输入管理器。一个好的输入管理器通常具备以下特点:
- 启用和禁用操作地图
- 订阅输入回调
- 处理设备变更
- 作为输入和游戏逻辑之间的边界
举个简单的例子:
public class GameInputManager : MonoBehaviour
{
public PlayerInput playerInput;
public PlayerController player;
private void OnEnable()
{
playerInput.actions["Jump"].performed += OnJump;
playerInput.actions["Shoot"].performed += OnShoot;
}
private void OnDisable()
{
playerInput.actions["Jump"].performed -= OnJump;
playerInput.actions["Shoot"].performed -= OnShoot;
}
private void OnJump(InputAction.CallbackContext context)
{
Player.Jump();
}
private void OnShoot(InputAction.CallbackContext context)
{
Player.Shoot();
}
}
在我们的许多代码库中,我们有一个用于游戏输入的自定义类,其中包含一些函数,允许您通过提供一个字符串键来注册和取消注册回调。我们还添加了一个优先级系统,允许我们在特定情况下停止监听某些输入,例如上面提到的输入上下文。使用此管理器连接玩家输入如下所示:
InputManager.Register(“Swing”, Priority.Character, SwingBat);
受输入控制的游戏对象与控制它们的输入逻辑是解耦的。这样一来,后续的重构成本就会降低,同时也能简化开发人员使用的代码。
拥抱重新绑定
可重新绑定按键不再是奢侈品了。人们期望它们能够满足无障碍访问、设备多样性和基本用户体验方面的需求。
Mega Cat Studios 的许多员工都使用旧版输入管理器实现了重新绑定,所以我们知道这曾经有多么痛苦(这可能是我们胡须里长出不少白发的原因)。幸运的是,输入系统软件包几乎免费地为我们提供了这一功能。
InputActionRebindingExtensions.PerformInteractiveRebinding() 完成了大部分工作;我们只需要将其连接到游戏代码中即可。我们通常使用两个脚本来实现这一点,将前端和后端的功能分开:
- RebindsManager
- 处理当前操作,因此一次只能重新绑定一个操作。
- 重新绑定期间禁用回调
- 包含输入操作引用
- RebindActionUI
- 处理启动和结束操作的交互
- 每个重新映射输入的 UI 面板都附加了此功能
“最初,我们没有这方面的管理程序,所以 UI 脚本独自处理了交互和重新绑定操作,” 《后院棒球 2026》的开发人员 Sofia Nacional 说。“这种方法无法扩展,导致可以同时进行多个活动的重新绑定操作。”
后端输入的合理组织,也让玩家在前端拥有更大的自定义自由度。以输入上下文为例。在棒球比赛中,球员的动作分为不同的阶段:击球、投球、守备和跑垒。所以,在我们的游戏中,玩家可以将按钮绑定到“挥棒”和“盗垒”两个动作,因为这两个动作永远不会在同一场景中发生。输入上下文可以轻松允许正确的重复绑定,同时防止导致触发多个输入操作的问题绑定。
输入是一个系统
团队犯的最大错误是将输入视为实现细节而不是核心游戏系统。输入会影响一切:游戏体验、用户界面可用性和长期可维护性。如果你正在制作原型或发布一些小产品,那么你或许可以勉强使用隐藏在 MonoBehaviours 中的零散轮询。但如果你的游戏需要扩展,你就需要一些强大的功能。
作为电子游戏开发者,我们为玩家服务;我们的职责是为他们提供完成游戏所需的工具!通过采用事件驱动架构,我们不仅优化了代码,还保护了游戏免受影响玩家操控的漏洞的侵害,并为他们提供了最佳的游戏体验。
