学习视频:2-8_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1L681zmEGv?spm_id_from=333.788.videopod.sections&vd_source=f5ed15a716a0d2394ab18fcc53eac495&p=12

学起来比较迷糊,整理一下

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);
	}
}

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐