Version:

第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 组件

  1. 在关卡中创建新实体 Input Map。

  2. Add Input 组件。Local player index 是指向哪个本地玩家将接收输入的值。目前,将其保留为值 “-1” 意味着输入将发送到所有本地玩家控制器。

  3. 目前,没有分配输入绑定。为 Input to event bindings (输入到事件绑定) 属性分配一个。我们可以从 Starting Point Input Gem 中的模板开始。它位于 C:\O3DE\21.11.2\Gems\StartingPointInput\Assets\thirdpersonmovement.inputbindings。

图 17.1.选取第三人称移动输入绑定

  1. Input 组件应分配 thirdpersonmovement Map。

图 17.2.具有第三人称移动绑定的输入组件

  1. 此时,您可以使用 Input to event bindings(输入到事件绑定)旁边最右侧的图标检查绑定,这将打开 Asset Viewer。

图 17.3.资产查看器

  1. 打开 Input Event Groups 并检查 move forward动作。

图 17.4. “Move forward” action

  1. 我们已经得出了前进动作的定义,它被分配了键盘键 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++ 组件中接收输入

  1. 继承自 StartingPointInput::InputEventNotificationBus::MultiHandler。
class ChickenControllerComponent
: public AZ::Component
, public StartingPointInput::InputEventNotificationBus::MultiHandler
  1. 重写 OnPressed 和 OnReleased 虚拟方法。
// AZ::InputEventNotificationBus interface
void OnPressed(float value) override;
void OnReleased(float value) override;  
  1. 定义我们正在寻找的作。
const StartingPointInput::InputEventNotificationId
MoveFwdEventId("move forward");
注意:
“move forward” 的值必须与 Input 组件绑定中相应 Event Name 的值匹配。

图 17.6.Asset Editor 中“forward ”的输入绑定

  1. 在 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);
     }
   }
  1. 将 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