본문 바로가기
언리얼 엔진/기초

[Unreal Engine5] Game Feature 시스템 기초(2)

by TyT. 2023. 8. 13.
반응형

GitHub: https://github.com/tyt0815

 

tyt0815 - Overview

tyt0815 has 4 repositories available. Follow their code on GitHub.

github.com

Notion: https://www.notion.so/tyt0815/a16514d41cb240f08aa19fe5b4c0ab86?pvs=4 

 

언리얼 엔진

Unreal Engine 5 C++ The Ultimate Game Developer Course

www.notion.so

※노션에 기존에 작성하던 글이 있으니 참고

참고자료

(444) Modular Game Features in UE5: plug ‘n play, the Unreal way - YouTube

이전 글에서 이어집니다.

어빌리티 구현

Game Feature의 활용중 하나로 확장성이 있는 Base Ability Component를 만들고 이 컴포넌트를 상속해 어빌리티를 구현을 해보겠습니다.

헤더파일과 소스코드를 구성해 줍니다.

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "InputAction.h"
#include "Components/ActorComponent.h"
#include "BaseAbilityComponent.generated.h"

class UEnhancedInputComponent;

UCLASS( Blueprintable, ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class NOTITLE_API UBaseAbilityComponent : public UActorComponent
{
	GENERATED_BODY()

public:
	virtual void OnRegister() override;
	virtual void OnUnregister() override;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Ability Component | Input")
	UInputAction* InputAction;

	UFUNCTION(BlueprintImplementableEvent, Category = "Ability Component | Input")
	void OnStarted(const FInputActionInstance& InputInstance);

	UFUNCTION(BlueprintImplementableEvent, Category = "Ability Component | Input")
	void AbilityTick(const FInputActionInstance& InputInstance);

	UFUNCTION(BlueprintImplementableEvent, Category = "Ability Component | Input")
	void OnCancelled(const FInputActionInstance& InputInstance);

	UFUNCTION(BlueprintImplementableEvent, Category = "Ability Component | Input")
	void ActivateAbility(const FInputActionInstance& InputInstance);

	UFUNCTION(BlueprintImplementableEvent, Category = "Ability Component | Input")
	void OnCompleted(const FInputActionInstance& InputInstance);

private:
	uint32 ActionStartedBindingHandle;
	uint32 ActionOngoingBindingHandle;
	uint32 ActionCanceledBindingHandle;
	uint32 ActionTriggeredBindingHandle;
	uint32 ActionCompletedBindingHandle;

	ACharacter* OwningCharacter;
	UEnhancedInputComponent* EnhancedInputComponent;

public:
	UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Ability Component")
	ACharacter* GetOwningCharacter();
};

 

 

// Fill out your copyright notice in the Description page of Project Settings.


#include "Components/BaseAbilityComponent.h"
#include "InputTriggers.h"
#include "InputMappingContext.h"
#include "EnhancedInputComponent.h"
#include "GameFramework/Character.h"
#include "GameFramework/PlayerInput.h"

void UBaseAbilityComponent::OnRegister()
{
	Super::OnRegister();

	OwningCharacter = Cast<ACharacter>(GetOwner());

	if (OwningCharacter)
	{
		EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(OwningCharacter->InputComponent);
		if (EnhancedInputComponent)
		{
			ActionStartedBindingHandle = EnhancedInputComponent->BindAction(InputAction, ETriggerEvent::Started, this, &UBaseAbilityComponent::OnStarted).GetHandle();
			ActionOngoingBindingHandle = EnhancedInputComponent->BindAction(InputAction, ETriggerEvent::Ongoing, this, &UBaseAbilityComponent::AbilityTick).GetHandle();
			ActionCanceledBindingHandle = EnhancedInputComponent->BindAction(InputAction, ETriggerEvent::Canceled, this, &UBaseAbilityComponent::OnCancelled).GetHandle();
			ActionTriggeredBindingHandle = EnhancedInputComponent->BindAction(InputAction, ETriggerEvent::Triggered, this, &UBaseAbilityComponent::ActivateAbility).GetHandle();
			ActionCompletedBindingHandle = EnhancedInputComponent->BindAction(InputAction, ETriggerEvent::Completed, this, &UBaseAbilityComponent::OnCompleted).GetHandle();
		}
	}
}

void UBaseAbilityComponent::OnUnregister()
{
	Super::OnUnregister();

	if (EnhancedInputComponent)
	{
		EnhancedInputComponent->RemoveActionBindingForHandle(ActionStartedBindingHandle);
		EnhancedInputComponent->RemoveActionBindingForHandle(ActionOngoingBindingHandle);
		EnhancedInputComponent->RemoveActionBindingForHandle(ActionCanceledBindingHandle);
		EnhancedInputComponent->RemoveActionBindingForHandle(ActionTriggeredBindingHandle);
		EnhancedInputComponent->RemoveActionBindingForHandle(ActionCompletedBindingHandle);
	}

	OwningCharacter = nullptr;
	EnhancedInputComponent = nullptr;
}

ACharacter* UBaseAbilityComponent::GetOwningCharacter()
{
	return OwningCharacter;
}

주의할점

  • 헤더파일의 UCLASS에 Blueprintable을 안넣어 주면 블루프린트로 상속을 못합니다.
  • 헤더파일을 Include 목록을 잘 봅시다.

컴파일하고 위 클래스를 상속하는 블루프린트를 생성합니다.

잘 동작하는지 확인하기 위해 로그를 띄워서 확인합니다.

헤더파일에서 선언된 EnhancedInputComponent는 초기화 되지 않았습니다. 블루프린트에서 초기화해줄 것 입니다. 먼저 InputAction을 만들어 줍니다. (InputAction이 무엇인지 모른다면 향상된 입력에 대한 사전 지식이 필요합니다.)

Input Mapping Context에 등록해 줍니다. 키는 E로 등록하였습니다.

다시 어빌리티 컴포넌트로  돌아와서 InputAction을 등록해줍니다. 변수가 보이지 않는다면 상속된 변수 보기 옵션을 켜줍니다.

이제 플레이어의 캐릭터에 Game Framework Component Manager를 추가해 줍니다.

 

마지막으로 게임피쳐데이터에 등록해 줍니다. 이전 포스트에서도 강조했지만, 등록할때  Active상태이여선 안됩니다. Registered상태에서 컴포넌트를 등록해 준 후 다시 Active상태로 바꿔줍니다.

모든 설정을 마치고 Active

실행해서 E키를 눌러봅니다.

Log를 확인해 보면 세가지 함수가 호출 된 것을 알 수 있습니다.

  • E키가 눌릴때: Onstarted
  • E키를 누르고 있을때: ActivateAbility
  • E키를 땔때: OnCompleted

AbilityTick과 On Canclled는 호출되지 않았는데, 이에 대한 것 다음 포스트에서 다룹니다.

반응형