초보 코린이의 성장 일지

UE4 Behavior, AI Equip 본문

언리얼

UE4 Behavior, AI Equip

코오린이 2023. 7. 26. 16:50

Enemy가 이제 무기를 뽑도록 만들어 볼 것이다.

 

#pragma once

#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "CWeaponComponent.generated.h"

// 무기 타입
UENUM(BlueprintType)
enum class EWeaponType : uint8
{
	Fist, Sword, Hammer, Warp, Around, Bow, Max,
};
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FWeaponTypeChanged, EWeaponType, InPrevType, EWeaponType, InNewType);

UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent))
class U2212_06_API UCWeaponComponent : public UActorComponent
{
	GENERATED_BODY()
    
public:
	FORCEINLINE EWeaponType GetWeaponType() { return Type; }

};

1. WeaponComponent에서 Type를 사용할 수 있도록 InLine함수로 넘겨준다.


1. 새 Task 클래스를 생성해준다.

#pragma once

#include "CoreMinimal.h"
#include "BehaviorTree/BTTaskNode.h"
#include "Components/CWeaponComponent.h"
#include "CBTTaskNode_Equip.generated.h"

UCLASS()
class U2212_06_API UCBTTaskNode_Equip : public UBTTaskNode
{
	GENERATED_BODY()

private:
	UPROPERTY(EditAnywhere, Category = "Type")
		EWeaponType Type; // 장착시킬 무기 타입

public:
	UCBTTaskNode_Equip();

protected:
	virtual EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;
	// 무기를 장착하는건 Tick에서 하게된다.
	virtual void TickTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds) override;

};
#include "BehaviorTree/CBTTaskNode_Equip.h"
#include "Global.h"
#include "Characters/CEnemy_AI.h"
#include "Characters/CAIController.h"
#include "Components/CStateComponent.h"
#include "Components/CStatusComponent.h"
#include "Weapons/CEquipment.h"

UCBTTaskNode_Equip::UCBTTaskNode_Equip()
{
	NodeName = "Equip";

	bNotifyTick = true;
}

EBTNodeResult::Type UCBTTaskNode_Equip::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
	Super::ExecuteTask(OwnerComp, NodeMemory);

	ACAIController* controller = Cast<ACAIController>(OwnerComp.GetOwner());
	ACEnemy_AI* ai = Cast<ACEnemy_AI>(controller->GetPawn());

	UCWeaponComponent* weapon = CHelpers::GetComponent<UCWeaponComponent>(ai);
	CheckNullResult(weapon, EBTNodeResult::Failed); // 무기가 없다면 실행 x

	// 현재 장착하고있는 무기와, 장착할 무기가 같다면 이미 성공이므로,
	if (Type == weapon->GetWeaponType()) 
		return EBTNodeResult::Succeeded;

	switch (Type)
	{
		case EWeaponType::Sword: weapon->SetSwordMode(); break;
	}

	return EBTNodeResult::InProgress; // 조건이 성공했다면, 대기

}

void UCBTTaskNode_Equip::TickTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds)
{
	Super::TickTask(OwnerComp, NodeMemory, DeltaSeconds);

	ACAIController* controller = Cast<ACAIController>(OwnerComp.GetOwner());
	ACEnemy_AI* ai = Cast<ACEnemy_AI>(controller->GetPawn());

	UCWeaponComponent* weapon = CHelpers::GetComponent<UCWeaponComponent>(ai);
	const bool* bEquipped = weapon->GetEquipment()->GetEquipped(); // 장착이 완료 되었는지,

	UCStateComponent* state = CHelpers::GetComponent<UCStateComponent>(ai);
	if (state->IsIdleMode() && *bEquipped) // 무기 장착이 아닌 상태, 장착이 완료되었다면,
	{
		// 끝내기
		FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);

		return;
	}

}

1. StateComponent에서 무기를 장착 중인지 아닌지를 체크해준다.

2. Equip에 대해 Equipment에서 bool 체크값을 가져와서 Equip 상태인지 체크를 해주고, 완료 상태가 아니라면 조건 체크 후 장착을 완료 시키고 Task를 끝낸다.


1. Task Equip를 추가해준다.


여기서 문제가 하나 발생한다 지난 블로그 글에서도 언급했지만, Behavior에서 Task도 같이 영향을 받는 객체들이 공유를 한다고 말했었다. 언리얼에서는 Asset도 전부 공유하게 된다. 이때 같은 에셋을 사용하고 있거나 동작을 사용하는 Player까지 영향을 같이 받게 된다. 이걸 해결하려면 WeaponAsset에서 생성할 자료형들을 설정해주고 있는데, 지금은 자료형을 가지고 생성하는 과정의 구조가 하나에 몰려져있어 이 하나를 가지고 공유하며 사용하고 있기 때문에 이 원인이 발생한 것이다. 그래서 아래에서 생성하게 될 자료형들을 나눠져서 생성해 줘야 이 문제를 해결할 수 있게 된다. 

 

다음에 해결해 보도록 하겠다.

'언리얼' 카테고리의 다른 글

UE4 Behavior, AI Hitted  (0) 2023.07.31
UE4 Behavior, AI Action  (2) 2023.07.27
UE4 Behavior Tree, Patrol  (0) 2023.07.25
UE4 Behavior Tree  (0) 2023.07.24
UE4 Feet IK, Behavior, HealBar  (0) 2023.07.21
Comments