🏛️
私の技術ノート:【UnrealEngine】DataAssetを使って汎用性の良い入力システムを作る
今回のやること
DataAssetを使ってタグとインプットアクションを紐づけすることにより、汎用性を高くし、入力システムを扱いやすくなり、ヒューマンエラー等防止にもつながります。
必要なクラス
- DataAssetクラス
- EnhancedInputComponentクラス (バインドさせるため)
- ゲームプレイタグクラス (紐づけするタグ作成)
- Characterクラス (入力受け付けるキャラ)
DataAssetクラス
UDataAsset_InputConfig.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataAsset.h"
#include "GameplayTagContainer.h"
#include "DataAsset_InputConfig.generated.h"
class UInputAction;
class UInputMappingContext;
//** タグとインプットアクションを紐づけするための構造体 **//
USTRUCT(BlueprintType)
struct FMyActionInputData
{
GENERATED_USTRUCT_BODY()
public:
//タグの定義
UPROPERTY(EditDefaultsOnly, meta = (Categories = "InputTag"))
FGameplayTag InputTag;
//インプットアクションの定義
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
TObjectPtr<UInputAction> InputAction;
};
/**
*
*/
UCLASS()
class MYACTION_API UDataAsset_InputConfig : public UDataAsset
{
GENERATED_BODY()
public:
//マッピングコンテキストの定義
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
TObjectPtr<UInputMappingContext> IMC_Default;
//インプットデータ構造体を配列で定義 (複数個設定可能)
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (TitleProperty = "InputTag"))
TArray<FMyActionInputData> NativeInputDatas;
//タグ名からインプットアクションを取得する関数
UInputAction* GetInputActionByTag(const FGameplayTag& TagName) const;
};
UDataAsset_InputConfig.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "DataAssets/DataAsset_InputConfig.h"
/// <summary>
/// 指定したタグのInputActionを返す
/// </summary>
/// <param name="TagName"></param>
/// <returns></returns>
UInputAction* UDataAsset_InputConfig::GetInputActionByTag(const FGameplayTag& TagName) const
{
for (const FMyActionInputData& InputData : NativeInputDatas)
{
if (InputData.InputTag == TagName && InputData.InputAction)
{
return InputData.InputAction;
}
}
return nullptr;
}
EnhancedInputComponentクラス
UMyActionInputComponent.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "EnhancedInputComponent.h"
#include "DataAssets/DataAsset_InputConfig.h"
#include "MyActionGameplayTags.h"
#include "MyActionInputComponent.generated.h"
/**
*
*/
UCLASS()
class MYACTION_API UMyActionInputComponent : public UEnhancedInputComponent
{
GENERATED_BODY()
public:
//バインドさせる関数を自作
template<class UserObject, typename CallbackFunc>
void BindNativeInputAction(const UDataAsset_InputConfig* DA_InputConfig, const FGameplayTag& TagName, ETriggerEvent TriggerEvent, UserObject* ContextObject, CallbackFunc Func);
};
template<class UserObject, typename CallbackFunc>
inline void UMyActionInputComponent::BindNativeInputAction(const UDataAsset_InputConfig* DA_InputConfig, const FGameplayTag& TagName, ETriggerEvent TriggerEvent, UserObject* ContextObject, CallbackFunc Func)
{
checkf(DA_InputConfig, TEXT("Not found Data asset 'DA_InputConfig' "));
BindAction(DA_InputConfig->GetInputActionByTag(TagName), TriggerEvent, ContextObject, Func);
}
ゲームプレイタグクラス
MyActionGameplayTags.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "NativeGameplayTags.h"
namespace MyActionGameplayTags
{
//** Input tags **//
MYACTION_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(InputTag_Move);
MYACTION_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(InputTag_Look);
}
MyActionGameplayTags.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "MyActionGameplayTags.h"
namespace MyActionGameplayTags
{
//** Input tags **//
UE_DEFINE_GAMEPLAY_TAG(InputTag_Move, "InputTag.Move");
UE_DEFINE_GAMEPLAY_TAG(InputTag_Look, "InputTag.Look");
}
Characterクラス
AMyActionHeroCharacter.h
//キャラクタークラスのヘッダーに以下を追加
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "DataAsset", meta = (AllowPrivateAccess = true))
TObjectPtr<UDataAsset_InputConfig> DA_InputConfig;
AMyActionHeroCharacter.cpp
void AMyActionHeroCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
//** LocalPlayerの取得 **//
ULocalPlayer* LocalPlayer = GetController<APlayerController>()->GetLocalPlayer();
check(LocalPlayer);
//** EnhancedInputLocalSubSystemの取得 **//
UEnhancedInputLocalPlayerSubsystem* SubSystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(LocalPlayer);
check(SubSystem);
//** SubSystemからマッピングコンテキストを追加 **//
SubSystem->AddMappingContext(DA_InputConfig->IMC_Default, 0);
//** MyActionInputComponentの取得 **//
UMyActionInputComponent* MyInputComponent = CastChecked<UMyActionInputComponent>(PlayerInputComponent);
//** InputComponentからバインド **//
MyInputComponent->BindNativeInputAction(DA_InputConfig, MyActionGameplayTags::InputTag_Move, ETriggerEvent::Triggered, this, &ThisClass::Input_Move);
MyInputComponent->BindNativeInputAction(DA_InputConfig, MyActionGameplayTags::InputTag_Look, ETriggerEvent::Triggered, this, &ThisClass::Input_Look);
}
Discussion