虚幻c++增强输入学习
***/UCLASS()public:自定义输入组件是为了在引擎提供的基础上,添加项目特定的功能和抽象层4.输入绑定首先在角色类里添加数据资源角色初始化时自动调用的虚函数,专门用于给角色添加操作输入绑定给角色添加输入操作是输入触发事件类型,表示"持续触发"的状态。事件类型描述适用场景Started刚开始按下时触发一次跳跃、攻击、交互Triggered持续按下时每帧触发移动、视角转动、持续施法Com
学起来比较迷糊,整理一下

1.使用 GameplayTag
为什么使用GameTag:
玩家可以自定义按键
传统方式
//绑定了空格键
if (InputComponent->WasKeyJustPressed(EKeys::SpaceBar)) {
Jump();
}
增强输入方式(使用Tag)
// 通过Tag识别输入,不与具体键位耦合
BindNativeInputAction(Config, FGameplayTag::RequestGameplayTag("Input.Jump"), ...);
Config就是数据资产,里面的内容可能是这样
{
"InputActions": [
{
"Tag": "Input.Jump",
"Keys": ["SpaceBar", "Gamepad_FaceButton_Bottom"],
"Abilities": "Ability.Jump"
},
{
"Tag": "Input.Attack",
"Keys": ["LeftMouseButton", "Gamepad_RightTrigger"],
"Abilities": "Ability.Attack"
}
]
}
如何创建GameplayTag
创建GameplayTag就不赘述了。
//WarriorGameplayTags.h
#pragma once
#include "NativeGameplayTags.h"
namespace WarriorGameplayTags
{
/** Input Tags **/
WARRIOR_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(InputTag_Move);
WARRIOR_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(InputTag_Look);
}
首先引入NativeGameplayTags.h(需要添加模块),用UE_DECLARE_GAMEPLAY_TAG_EXTERN声明GameplayTag
//WarriorGameplayTags.cpp
#include "WarriorGamePlayTags.h"
namespace WarriorGameplayTags
{
/** Input Tags **/
UE_DEFINE_GAMEPLAY_TAG(InputTag_Move, "InputTag.Move");
UE_DEFINE_GAMEPLAY_TAG(InputTag_Look, "InputTag.Look");
}
在cpp文件UE_DEFINE_GAMEPLAY_TAG定义游戏标签
结果:

2.创建输入数据源
创建DataAsset

//DataAsset_InputConfig.h
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataAsset.h"
#include "GameplayTagContainer.h"
#include "DataAsset_InputConfig.generated.h"
class UInputAction;
class UInputMappingContext;
USTRUCT(BlueprintType)
struct FWarriorInputActionConfig
{
GENERATED_BODY()
public:
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (Categories = "InputTag"))
FGameplayTag InputTag;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
UInputAction* InputAction;
};
/**
*
*/
UCLASS()
class WARRIOR_API UDataAsset_InputConfig : public UDataAsset
{
GENERATED_BODY()
public:
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
UInputMappingContext* DefaultMappingContext;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (TitleProperty = "InputTag"))
TArray<FWarriorInputActionConfig> NativeInputActions;
UInputAction* FindNativeInputActionByTag(const FGameplayTag& InInputTag) const;
};
FWarriorInputActionConfig这个结构体绑定了游戏标签和输入操作(跳跃、移动、攻击等),引入UInputAction需要添加模块
UDataAsset_InputConfig中DefaultMappingContext就是哪个键触发哪个操作,第三人称地图的默认如下

FindNativeInputActionByTag就是通过游戏标签获取输入操作
然后在项目创建这个类并添加第三人称地图默认按键绑定,还有InputAction

IA_Look、IA_Move是Unreal Engine 会自动创建一些常用的默认输入操作

3.自定义输入组件
//UWarriorInputComponent.h
#pragma once
#include "CoreMinimal.h"
#include "EnhancedInputComponent.h"
#include "DataAssets/Input/DataAsset_InputConfig.h"
#include "WarriorInputComponent.generated.h"
/**
*
*/
UCLASS()
class WARRIOR_API UWarriorInputComponent : public UEnhancedInputComponent
{
GENERATED_BODY()
public:
template<class UserObject, typename CallbackFunc>
void BindNativeInputAction(const UDataAsset_InputConfig* InInputConfig, const FGameplayTag& InInputTag, ETriggerEvent TriggerEvent, UserObject* ContextObject, CallbackFunc Func);
};
template<class UserObject, typename CallbackFunc>
inline void UWarriorInputComponent::BindNativeInputAction(const UDataAsset_InputConfig* InInputConfig, const FGameplayTag& InInputTag, ETriggerEvent TriggerEvent, UserObject* ContextObject, CallbackFunc Func)
{
checkf(InInputConfig, TEXT("Input config data asset is null,can not proceed with binding"));
if (UInputAction* FoundAction = InInputConfig->FindNativeInputActionByTag(InInputTag))
{
BindAction(FoundAction, TriggerEvent, ContextObject, Func);
}
}
自定义输入组件是为了在引擎提供的 UEnhancedInputComponent 基础上,添加项目特定的功能和抽象层
4.输入绑定
首先在角色类里添加数据资源
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "CharacterData", meta = (AllowPrivateAccess = "true"))
UDataAsset_InputConfig* InputConfigDataAsset;
角色初始化时自动调用的虚函数,专门用于给角色添加操作输入绑定
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
给角色添加输入操作
void AWarriorHeroCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
checkf(InputConfigDataAsset, TEXT("Forgot to assign a valid data asset as input config"));
ULocalPlayer* LocalPlayer = GetController<APlayerController>()->GetLocalPlayer();
UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(LocalPlayer);
check(Subsystem);
Subsystem->AddMappingContext(InputConfigDataAsset->DefaultMappingContext, 0);
UWarriorInputComponent* WarriorInputComponent = CastChecked<UWarriorInputComponent>(PlayerInputComponent);
WarriorInputComponent->BindNativeInputAction(InputConfigDataAsset, WarriorGameplayTags::InputTag_Move, ETriggerEvent::Triggered, this, &ThisClass::Input_Move);
WarriorInputComponent->BindNativeInputAction(InputConfigDataAsset, WarriorGameplayTags::InputTag_Look, ETriggerEvent::Triggered, this, &ThisClass::Input_Look);
}
ETriggerEvent::Triggered 是输入触发事件类型,表示"持续触发"的状态。
各种触发事件类型:
| 事件类型 | 描述 | 适用场景 |
|---|---|---|
Started |
刚开始按下时触发一次 | 跳跃、攻击、交互 |
Triggered |
持续按下时每帧触发 | 移动、视角转动、持续施法 |
Completed |
释放按键时触发一次 | 结束动作、取消技能 |
Canceled |
输入被取消时触发 | 被打断、强制取消 |
最后完成移动和视角处理函数
void AWarriorHeroCharacter::Input_Move(const FInputActionValue& InputActionValue)
{
const FVector2D MovementVector = InputActionValue.Get<FVector2D>();
const FRotator MovementRotation(0.f, Controller->GetControlRotation().Yaw, 0.f);
if (MovementVector.Y != 0.f)
{
const FVector ForwardDirection = MovementRotation.RotateVector(FVector::ForwardVector);
AddMovementInput(ForwardDirection, MovementVector.Y);
}
if (MovementVector.X != 0.f)
{
const FVector RightDirection = MovementRotation.RotateVector(FVector::RightVector);
AddMovementInput(RightDirection, MovementVector.X);
}
}
void AWarriorHeroCharacter::Input_Look(const FInputActionValue& InputActionValue)
{
const FVector2D LookAxisVector = InputActionValue.Get<FVector2D>();
if (LookAxisVector.X != 0.f)
{
AddControllerYawInput(LookAxisVector.X);
}
if (LookAxisVector.Y != 0.f)
{
AddControllerPitchInput(LookAxisVector.Y);
}
}
更多推荐
所有评论(0)