本文内容
第17章 用户输入
第17章 用户输入
介绍
注意:本章的源代码可以在 GitHub 上找到: https://github.com/AMZN-Olex/O3DEBookCode2111/tree/ch17_input
游戏中的常见元素之一是玩家控制的角色。本书的这一部分将构建一个玩家控制的鸡,我们在第 14 章 启用 NvCloth Gem 中添加。但在我们开始移动我们的鸡之前,我将向您展示如何在 O3DE 中捕获玩家的输入。
Starting Point Input Gem
O3DE 附带一个 Gem,用于设置输入映射的基本 - 起点输入。它包含在默认项目模板中,因此我们已经在 MyProject\Code\enabled_gems.cmake 中启用了它。
set(ENABLED_GEMS
...
StartingPointInput
...
)
添加输入映射
Starting Point Input Gem 为我们提供了 Input 组件,用于将 Input 值映射到游戏作。
注意:有关输入组件的官方文档,请在此处找到: https://www.o3de.org/docs/user-guide/interactivity/input/using-player-input/
例 17.1.空 Input 组件
在关卡中创建新实体 Input Map。
Add Input 组件。Local player index 是指向哪个本地玩家将接收输入的值。目前,将其保留为值 “-1” 意味着输入将发送到所有本地玩家控制器。
目前,没有分配输入绑定。为 Input to event bindings (输入到事件绑定) 属性分配一个。我们可以从 Starting Point Input Gem 中的模板开始。它位于 C:\O3DE\21.11.2\Gems\StartingPointInput\Assets\thirdpersonmovement.inputbindings。
图 17.1.选取第三人称移动输入绑定
- Input 组件应分配 thirdpersonmovement Map。
图 17.2.具有第三人称移动绑定的输入组件
- 此时,您可以使用 Input to event bindings(输入到事件绑定)旁边最右侧的图标检查绑定,这将打开 Asset Viewer。
图 17.3.资产查看器
- 打开 Input Event Groups 并检查 move forward动作。
图 17.4. “Move forward” action
- 我们已经得出了前进动作的定义,它被分配了键盘键 W。
现在,我们已经清楚地了解了如何从给定输入触发作,让我们看看如何在 C++ 组件中捕获它。
图 17.5.捕获输入的设计
针对 Starting Point Input Gem 进行链接
我们将使用 Starting Point Input Gem 公有接口之一 InputEventNotificationBus 来创建新组件 ChickenControllerComponent。为了能够访问包含 ebus 的头文件,我们需要链接到静态库 StartingPointInput.Static。
例 17.2. 修改 MyGem\Code\CMakeLists.txt
ly_add_target(
NAME MyGem.Static STATIC
...
BUILD_DEPENDENCIES
PUBLIC
Gem::StartingPointInput.Static
...
)
在 C++ 组件中接收输入
- 继承自 StartingPointInput::InputEventNotificationBus::MultiHandler。
class ChickenControllerComponent
: public AZ::Component
, public StartingPointInput::InputEventNotificationBus::MultiHandler
- 重写 OnPressed 和 OnReleased 虚拟方法。
// AZ::InputEventNotificationBus interface
void OnPressed(float value) override;
void OnReleased(float value) override;
- 定义我们正在寻找的作。
const StartingPointInput::InputEventNotificationId
MoveFwdEventId("move forward");
注意:“move forward” 的值必须与 Input 组件绑定中相应 Event Name 的值匹配。
图 17.6.Asset Editor 中“forward ”的输入绑定
- 在 OnPressed 和 OnRelease 方法中接收事件。
void ChickenControllerComponent::OnPressed(float value)
{
const InputEventNotificationId* inputId =
InputEventNotificationBus::GetCurrentBusId();
if (inputId == nullptr)
{
return;
}
if (*inputId == MoveFwdEventId)
{
AZ_Printf("Chicken", "forward axis %f", value);
}
}
- 将 ChickenControllerComponent 添加到关卡中的Chicken_Actor实体。
通过这些更改,您可以按 W 和 S 来触发移动输入作
例 17.3.接收输入
(Chicken) - forward axis -1.000000
(Chicken) - forward axis -0.000000
(Chicken) - forward axis -1.000000
(Chicken) - forward axis -0.000000
(Chicken) - forward axis 1.000000
(Chicken) - forward axis 0.000000
注意:负值来自按下 S 键,该键通过发送具有负值的向前移动来映射到向后移动。
图 17.7.带有 Chicken Controller 组件的 Chicken Actor
源代码
注意:本章的源代码可以在 GitHub 上找到: https://github.com/AMZN-Olex/O3DEBookCode2111/tree/ch17_input
本章添加了一个新组件 ChickenControllerComponent。
例 17.4. ChickenControllerComponent.h
#pragma once
#include <AzCore/Component/Component.h>
#include <StartingPointInput/InputEventNotificationBus.h>
namespace MyGem
{
const StartingPointInput::InputEventNotificationId
MoveFwdEventId("move forward");
class ChickenControllerComponent
:
public AZ::Component
,
public StartingPointInput::
InputEventNotificationBus::MultiHandler
{
public:
AZ_COMPONENT(ChickenControllerComponent,
"{fe639d60-75c0-4e16-aa1a-0d44dbe6d339}");
static void Reflect(AZ::ReflectContext* context);
// AZ::Component interface implementation
void Activate() override;
void Deactivate() override;
// AZ::InputEventNotificationBus interface
void OnPressed(float value) override;
void OnReleased(float value) override;
};
} // namespace MyGem
例 17.5. ChickenControllerComponent.cpp
#include <ChickenControllerComponent.h>
#include <AzCore/Serialization/EditContext.h>
namespace MyGem
{
using namespace StartingPointInput;
void ChickenControllerComponent::Reflect(AZ::ReflectContext* rc)
{
}
if (auto sc = azrtti_cast<AZ::SerializeContext*>(rc))
{
sc->Class<ChickenControllerComponent, AZ::Component>()
->Version(1);
if (AZ::EditContext* ec = sc->GetEditContext())
{
using namespace AZ::Edit;
ec->Class<ChickenControllerComponent>(
"Chicken Controller",
"[Player controlled chicken]")
->ClassElement(ClassElements::EditorData, "")
->Attribute(
Attributes::AppearsInAddComponentMenu,
AZ_CRC("Game"));
}
}
void ChickenControllerComponent::Activate()
{
InputEventNotificationBus::
MultiHandler::BusConnect(MoveFwdEventId);
}
void ChickenControllerComponent::Deactivate()
{
InputEventNotificationBus::MultiHandler::BusDisconnect();
}
void ChickenControllerComponent::OnPressed(float value)
{
const InputEventNotificationId* inputId =
InputEventNotificationBus::GetCurrentBusId();
if (inputId == nullptr)
{
return;
}
if (*inputId == MoveFwdEventId)
{
AZ_Printf("Chicken", "forward axis %f", value);
}
}
void ChickenControllerComponent::OnReleased(float value)
{
const InputEventNotificationId* inputId =
InputEventNotificationBus::GetCurrentBusId();
if (inputId == nullptr)
{
return;
}
if (*inputId == MoveFwdEventId)
{
AZ_Printf("Chicken", "forward axis %f", value);
}
}
} // namespace MyGem