[UE] Behavior Tree 시작
Behavior Tree를 사용하여 AI System을 만들고 적AI를 구현할 것이다. AIController를 만들어 Enemy의 하위 클래스인 Enemy_AI에 할당할 것이다. Enemy_AI는 Behavior Tree를 가지고 AIBehaviorComponent를 활용하여 AI의 상태를 변경시킨다.
목차
Plugins |
||||
Weapon |
||||
Resource |
||||
Icon128.png weapon_thumbnail_icon.png |
||||
Source |
||||
Weapon | ||||
SWeaponCheckBoxes.h .cpp SWeaponDetailsView.h .cpp SWeaponDoActionData.h .cpp SWeaponEquipmentData.h .cpp SWeaponHitData.h .cpp SWeaponLeftArea.h .cpp Weapon.Build.cs WeaponAssetEditor.h .cpp WeaponAssetFactory.h .cpp WeaponCommand.h .cpp WeaponContextMenu.h .cpp WeaponModule.h .cpp WeaponStyle.h .cpp |
||||
Source | ||
BehaviorTree | ||
CBTService_Melee.h .cpp 생성 | ||
Characters | ||
CAIController.h .cpp 생성 CAnimInstance.h .cpp CEnemy.h .cpp CEnemy_AI.h .cpp CPlayer.h .cpp ICharacter.h .cpp |
||
Components | ||
CAIBehaviorComponent.h .cpp CFeetComponent.h .cpp CMontagesComponent.h .cpp CMovementComponent.h .cpp CStateComponent.h .cpp CStatusComponent.h .cpp CWeaponComponent.h .cpp CZoomComponent.h .cpp |
||
Notifies | ||
CAnimNotifyState_BeginAction.h .cpp CAnimNotifyState_BowString.h .cpp CAnimNotify_CameraShake.h .cpp CAnimNotify_End_Parkour CAnimNotifyState_EndAction.h .cpp CAnimNotify_EndState.h .cpp CAnimNotifyState.h .cpp CAnimNotifyState_CameraAnim.h .cpp CAnimNotifyState_Collision.h .cpp CAnimNotifyState_Combo.h .cpp CAnimNotifyState_Equip.h .cpp CAnimNotifyState_SubAction.h .cpp |
||
Parkour | ||
CParkourComponent.h .cpp | ||
Utilities | ||
CHelper.h CLog.h .cpp |
||
Weapons | ||
CArrow.h .cpp CAura.h .cpp CCamerModifier.h .cpp CGhostTrail.h .cpp CRotate_Object.h .cpp CThornObject.h .cpp CAnimInstance_Bow.h .cpp CAttachment_Bow.h .cpp CDoAction_Around.h .cpp CDoAction_Bow.h .cpp CDoAction_Combo.h .cpp CDoAction_Warp.h .cpp CSubAction_Around.h .cpp CSubAction_Bow.h .cpp CSubAction_Fist.h .cpp CSubAction_Hammer.h .cpp CSubAction_Sword.h .cpp CDoAction_Warp.h .cpp CAttachment.h .cpp CDoAction.h .cpp CEquipment.h .cpp CSubAction.h .cpp CWeaponAsset.h .cpp CWeaponStructures.h .cpp |
||
Global.h CGameMode.h .cpp U2212_06.Build.cs |
||
U2212_06.uproject | ||
Behavior Tree
CAIController 생성
새 C++ 클래스- AIController - CAIController 생성
CAIController.h
#pragma once
#include "CoreMinimal.h"
#include "AIController.h"
#include "CAIController.generated.h"
UCLASS()
class U2212_06_API ACAIController : public AAIController
{
GENERATED_BODY()
private:
UPROPERTY(VisibleAnywhere)
class UAIPerceptionComponent* Perception;
public:
ACAIController();
protected:
virtual void BeginPlay() override;
protected:
void OnPossess(APawn* InPawn) override;
void OnUnPossess() override;
private:
UFUNCTION()
void OnPerceptionUpdated(const TArray<AActor*>& UpdatedActors);
private:
class ACEnemy_AI* Enemy;
class UCAIBehaviorComponent* Behavior;
class UAISenseConfig_Sight* Sight;//시야 감지
};
CAIController.cpp
#include "Characters/CAIController.h"
#include "Global.h"
#include "GameFramework/Character.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "BehaviorTree/BehaviorTree.h"
#include "Characters/CEnemy_AI.h"
#include "Components/CAIBehaviorComponent.h"
#include "Perception/AIPerceptionComponent.h"
#include "Perception/AISenseConfig_Sight.h"
ACAIController::ACAIController()
{
CHelpers::CreateActorComponent<UBlackboardComponent>(this, &Blackboard, "Blackboard");
CHelpers::CreateActorComponent<UAIPerceptionComponent>(this, &Perception, "Perception");
Sight = CreateDefaultSubobject<UAISenseConfig_Sight>("Sight");//CreateDefaultSubobject는 생성자 동적할당, UObject는 런타임 동적할당.
Sight->SightRadius = 600;//시야 반경
Sight->LoseSightRadius = 800;//시야를 잃는 범위
Sight->PeripheralVisionAngleDegrees = 45;//시야각
Sight->SetMaxAge(2);
Sight->DetectionByAffiliation.bDetectEnemies = true;//적들을 감지o
Sight->DetectionByAffiliation.bDetectNeutrals = false;//중립 감지x
Sight->DetectionByAffiliation.bDetectFriendlies = false;//아군 감지x
Perception->ConfigureSense(*Sight);//감지 객체 지정. 시야감지로 지정.
Perception->SetDominantSense(*Sight->GetSenseImplementation());//시야감지를 최우선 감지타입으로 설정.
}
void ACAIController::BeginPlay()
{
Super::BeginPlay();
Perception->OnPerceptionUpdated.AddDynamic(this, &ACAIController::OnPerceptionUpdated);
}
void ACAIController::OnPossess(APawn* InPawn)
{
Super::OnPossess(InPawn);
Enemy = Cast<ACEnemy_AI>(InPawn);//Enemy에 possess되는 Pawn을 넣어준다.
SetGenericTeamId(Enemy->GetTeamID());//TeamID 지정
CheckNull(Enemy->GetBehaviorTree());//Enemy가 BehaviorTree를 가지고 있는지 체크
UseBlackboard(Enemy->GetBehaviorTree()->BlackboardAsset, Blackboard);//Blackboard 사용을 위해 BlackboardData인 BlackboardAsset과 BlackboardComonent인 Blackboard를 할당한다.
Behavior = CHelpers::GetComponent<UCAIBehaviorComponent>(Enemy);//Enemy내의 BehaviorComponent를 가져온다.
Behavior->SetBlackboard(Blackboard);
RunBehaviorTree(Enemy->GetBehaviorTree());//BehaviorTree 실행
}
void ACAIController::OnUnPossess()
{
Super::OnUnPossess();
}
void ACAIController::OnPerceptionUpdated(const TArray<AActor*>& UpdatedActors)
{
TArray<AActor*> actors;//감지되는 객체들
Perception->GetCurrentlyPerceivedActors(nullptr, actors);//Perception 감지
if (actors.Num() > 0)//감지되는 객체가 0 이상이면(=감지된 객체가 있다면)
{
Blackboard->SetValueAsObject("Target", actors[0]);//감지된 actor[0]을 객체로 지정한다.
return;
}
Blackboard->SetValueAsObject("Target", nullptr);//감지가 안 되었다면 nullptr
}
Inheritance Hierarchy
UObjectBase
- UObjectBaseUtility
- UObject
- UAISenseConfig
- UAISenseConfig_Blueprint
- UAISenseConfig_Damage
- UAISenseConfig_Hearing
- UAISenseConfig_Prediction
- UAISenseConfig_Sight
- UAISenseConfig_Team
- UAISenseConfig_Touch
- UAISenseConfig
- UObject
BP_CAIController_Melee 생성
블루프린트 클래스 - CAIController - BP_CAIController_Melee 생성
CAIBehaviorComponent
CAIBehaviorComponent.h
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "CAIBehaviorComponent.generated.h"
UENUM(BlueprintType)
enum class EAIStateType : uint8
{
Wait = 0, Approach, Action, Patrol, Hitted, Avoid, Dead, Max,
};
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FAIStateTypeChanged, EAIStateType, InPrevType, EAIStateType, InNewType);
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class U2212_06_API UCAIBehaviorComponent : public UActorComponent
{
GENERATED_BODY()
private:
UPROPERTY(EditAnywhere, Category = "Key")
FName AIStateTypeKey = "AIState";
UPROPERTY(EditAnywhere, Category = "Key")
FName TargetKey = "Target";
private:
EAIStateType GetType();
public:
bool IsWaitMode();
bool IsApproachMode();
bool IsActionMode();
bool IsPatrolMode();
bool IsHittedMode();
bool IsAvoidMode();
bool IsDeadMode();
public:
UCAIBehaviorComponent();
protected:
virtual void BeginPlay() override;
public:
FORCEINLINE void SetBlackboard(class UBlackboardComponent* InBlackboard) { Blackboard = InBlackboard; }
public:
class ACharacter* GetTarget();
public:
void SetWaitMode();
void SetApproachMode();
void SetActionMode();
void SetPatrolMode();
void SetHittedMode();
void SetAvoidMode();
void SetDeadMode();
private:
void ChangeType(EAIStateType InType);
public:
FAIStateTypeChanged OnAIStateTypeChanged;
private:
class UBlackboardComponent* Blackboard;
};
변경사항 없음
CAIBehaviorComponent.cpp
#include "Components/CAIBehaviorComponent.h"
#include "Global.h"
#include "GameFramework/Character.h"
#include "BehaviorTree/BlackboardComponent.h"
UCAIBehaviorComponent::UCAIBehaviorComponent()
{
}
void UCAIBehaviorComponent::BeginPlay()
{
Super::BeginPlay();
}
EAIStateType UCAIBehaviorComponent::GetType()
{
return (EAIStateType)Blackboard->GetValueAsEnum(AIStateTypeKey);
}
bool UCAIBehaviorComponent::IsWaitMode()
{
return GetType() == EAIStateType::Wait;
}
bool UCAIBehaviorComponent::IsApproachMode()
{
return GetType() == EAIStateType::Approach;
}
bool UCAIBehaviorComponent::IsActionMode()
{
return GetType() == EAIStateType::Action;
}
bool UCAIBehaviorComponent::IsPatrolMode()
{
return GetType() == EAIStateType::Patrol;
}
bool UCAIBehaviorComponent::IsHittedMode()
{
return GetType() == EAIStateType::Hitted;
}
bool UCAIBehaviorComponent::IsAvoidMode()
{
return GetType() == EAIStateType::Avoid;
}
bool UCAIBehaviorComponent::IsDeadMode()
{
return GetType() == EAIStateType::Dead;
}
ACharacter* UCAIBehaviorComponent::GetTarget()
{
//Blackboard 내의 TargetKey를 리턴해준다.
return Cast<ACharacter>(Blackboard->GetValueAsObject(TargetKey));
}
void UCAIBehaviorComponent::SetWaitMode()
{
ChangeType(EAIStateType::Wait);
}
void UCAIBehaviorComponent::SetApproachMode()
{
ChangeType(EAIStateType::Approach);
}
void UCAIBehaviorComponent::SetActionMode()
{
ChangeType(EAIStateType::Action);
}
void UCAIBehaviorComponent::SetPatrolMode()
{
ChangeType(EAIStateType::Patrol);
}
void UCAIBehaviorComponent::SetHittedMode()
{
ChangeType(EAIStateType::Hitted);
}
void UCAIBehaviorComponent::SetAvoidMode()
{
ChangeType(EAIStateType::Avoid);
}
void UCAIBehaviorComponent::SetDeadMode()
{
ChangeType(EAIStateType::Dead);
}
void UCAIBehaviorComponent::ChangeType(EAIStateType InType)
{
EAIStateType prevType = GetType();
Blackboard->SetValueAsEnum(AIStateTypeKey, (uint8)InType);
if (OnAIStateTypeChanged.IsBound())
OnAIStateTypeChanged.Broadcast(prevType, InType);
}
ACharacter* UCAIBehaviorComponent::GetTarget()
- return Cast(Blackboard->GetValueAsObject(TargetKey));
- Blackboard 내의 TargetKey를 리턴해준다.
- Blackboard 내의 TargetKey를 리턴해준다.
CEnemy_AI
CEnemy_AI.h
#pragma once
#include "CoreMinimal.h"
#include "Characters/CEnemy.h"
#include "CEnemy_AI.generated.h"
UCLASS()
class U2212_06_API ACEnemy_AI : public ACEnemy
{
GENERATED_BODY()
private:
UPROPERTY(EditDefaultsOnly, Category = "AI")
class UBehaviorTree* BehaviorTree;
UPROPERTY(EditDefaultsOnly, Category = "AI")
uint8 TeamID = 2;//TeamID를 0~255번까지 지정가능하다. 255번은 중립이다. ID 같으면 아군이고 ID가 다르면 적이다.
private:
UPROPERTY(EditDefaultsOnly, Category = "Label")
float LabelViewAmount = 3000.0f;
#if WITH_EDITOR
private:
UPROPERTY(VisibleDefaultsOnly)
class UWidgetComponent* LabelWidget;
#endif
private:
UPROPERTY(VisibleDefaultsOnly)
class UCWeaponComponent* Weapon;
UPROPERTY(VisibleDefaultsOnly)
class UCAIBehaviorComponent* Behavior;
public:
FORCEINLINE uint8 GetTeamID() { return TeamID; }
FORCEINLINE class UBehaviorTree* GetBehaviorTree() { return BehaviorTree; }
public:
ACEnemy_AI();
protected:
virtual void BeginPlay() override;
public:
virtual void Tick(float DeltaTime) override;
private:
void UpdateLabelRenderScale();
};
변수 추가
- UPROPERTY(EditDefaultsOnly, Category = "AI")
uint8 TeamID = 2;- TeamID를 0~255번까지 지정가능하다. 255번은 중립이다. ID 같으면 아군이고 ID가 다르면 적이다.
인라인 함수 추가
- FORCEINLINE uint8 GetTeamID() { return TeamID; }
- FORCEINLINE class UBehaviorTree* GetBehaviorTree() { return BehaviorTree; }
CEnemy_AI.cpp
#include "Characters/CEnemy_AI.h"
#include "Global.h"
#include "Components/CWeaponComponent.h"
#include "Components/CAIBehaviorComponent.h"
#include "Components/WidgetComponent.h"
#include "Components/CStatusComponent.h"
#include "Widgets/CUserWidget_Label.h"
ACEnemy_AI::ACEnemy_AI()
{
PrimaryActorTick.bCanEverTick = true;
CHelpers::CreateComponent<UWidgetComponent>(this, &LabelWidget, "Label", GetMesh());
CHelpers::CreateActorComponent<UCWeaponComponent>(this, &Weapon, "Weapon");
CHelpers::CreateActorComponent<UCAIBehaviorComponent>(this, &Behavior, "Behavior");
TSubclassOf<UCUserWidget_Label> labelClass;
CHelpers::GetClass<UCUserWidget_Label>(&labelClass, "WidgetBlueprint'/Game/Widgets/WB_Label.WB_Label_C'");
LabelWidget->SetWidgetClass(labelClass);
LabelWidget->SetRelativeLocation(FVector(0, 0, 220));
LabelWidget->SetDrawSize(FVector2D(120, 0));
LabelWidget->SetWidgetSpace(EWidgetSpace::Screen);
}
void ACEnemy_AI::BeginPlay()
{
Super::BeginPlay();
LabelWidget->InitWidget();
UCUserWidget_Label* label = Cast<UCUserWidget_Label>(LabelWidget->GetUserWidgetObject());
label->UpdateHealth(Status->GetHealth(), Status->GetMaxHealth());
label->UpdateName(GetName());
label->UpdateControllerName(GetController()->GetName());
}
void ACEnemy_AI::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
UCUserWidget_Label* label = Cast<UCUserWidget_Label>(LabelWidget->GetUserWidgetObject());
if (!!label)
{
label->UpdateHealth(Status->GetHealth(), Status->GetMaxHealth());
UpdateLabelRenderScale();
}
}
void ACEnemy_AI::UpdateLabelRenderScale()
{
UCUserWidget_Label* label = Cast<UCUserWidget_Label>(LabelWidget->GetUserWidgetObject());
CheckNull(label);
APlayerCameraManager* cameraManager = UGameplayStatics::GetPlayerCameraManager(GetWorld(), 0);
FVector cameraLocation = cameraManager->GetCameraLocation();
FVector targetLocation = GetController()->GetTargetLocation();
float distance = FVector::Distance(cameraLocation, targetLocation);
float sizeRate = 1.0f - (distance / LabelViewAmount);
if (distance > LabelViewAmount)
{
label->SetVisibility(ESlateVisibility::Collapsed);
return;
}
label->SetVisibility(ESlateVisibility::Visible);
label->SetRenderScale(FVector2D(sizeRate, sizeRate));
}
변경사항 없음.
BP_CEnemy_Melee
AI
- Behavior Tree: BT_Melee 할당
Pawn
- AIController Class: BP_CAIController_Melee 할당
Weapon
- Data Assets
- Sword: DA_Sword 할당
Montages
- Data Table
- Data Table: DT_Enemy 할당
BB_Melee 생성
우클릭 - 인공지능 - 블랙보 - BB_Melee 생성
BT_Melee 생성
우클릭 - 인공지능 - 비헤이비어 트리 - BT_Melee 생성
AI
- BehaviorTree
- Blackboard Asset: BB_Melee 할당
CBTService_Melee 생성
새 C++ 클래스 - BTService - CBTService_Melee 생성
CBTService_Melee.h
#pragma once
#include "CoreMinimal.h"
#include "BehaviorTree/BTService.h"
#include "CBTService_Melee.generated.h"
UCLASS()
class U2212_06_API UCBTService_Melee : public UBTService
{
GENERATED_BODY()
private:
UPROPERTY(EditAnywhere, Category = "Action")
float ActionRange = 150;
public:
UCBTService_Melee();
protected:
void TickNode(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds) override;
};
CBTService_Melee.cpp
#include "BehaviorTree/CBTService_Melee.h"
#include "Global.h"
#include "GameFramework/Character.h"
#include "Characters/CAIController.h"
#include "Characters/CEnemy_AI.h"
#include "Components/CStateComponent.h"
#include "Components/CAIBehaviorComponent.h"
UCBTService_Melee::UCBTService_Melee()
{
NodeName = "Melee";
Interval = 0.1f;//호출 간격. 0.1초 마다 호출
RandomDeviation = 0.0f;
}
void UCBTService_Melee::TickNode(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds)
{
Super::TickNode(OwnerComp, NodeMemory, DeltaSeconds);
ACAIController* controller = Cast<ACAIController>(OwnerComp.GetOwner());
ACEnemy_AI* ai = Cast<ACEnemy_AI>(controller->GetPawn());
UCStateComponent* state = CHelpers::GetComponent<UCStateComponent>(ai);
UCAIBehaviorComponent* aiState = CHelpers::GetComponent<UCAIBehaviorComponent>(ai);
if (state->IsHittedMode())
{
aiState->SetHittedMode();
return;
}
ACharacter* target = aiState->GetTarget();
if(target == nullptr)//target이 없다면(=시야 범위 내에 적이 없다면)
{
aiState->SetPatrolMode();//Patrol
return;
}
float distance = ai->GetDistanceTo(target);
if (distance < ActionRange)//공격범위 내로 들어오면
{
aiState->SetActionMode();//공격
return;
}
aiState->SetApproachMode();//공격범위가 아니라면 Approach
}
Build.cs
Build.cs
using UnrealBuildTool;
public class U2212_06 : ModuleRules
{
public U2212_06(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicIncludePaths.Add(ModuleDirectory);
PublicDependencyModuleNames.Add("Core");
PrivateDependencyModuleNames.Add("CoreUObject");
PrivateDependencyModuleNames.Add("Engine");
PrivateDependencyModuleNames.Add("InputCore");
PublicDependencyModuleNames.Add("Niagara");
PublicDependencyModuleNames.Add("AIModule");
PublicDependencyModuleNames.Add("GameplayTasks");
}
}
모듈 추가
- PublicDependencyModuleNames.Add("GameplayTasks");
CPlayer
CPlayer.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "Components/CStateComponent.h"
#include "Characters/ICharacter.h"
#include "Parkour/CParkourComponent.h"
#include "GenericTeamAgentInterface.h"
#include "CPlayer.generated.h"
UCLASS()
class U2212_06_API ACPlayer
: public ACharacter, public IICharacter, public IGenericTeamAgentInterface //다중상속
{
GENERATED_BODY()
private:
UPROPERTY(EditDefaultsOnly, Category = "Team")
uint8 TeamID = 1;
private:
UPROPERTY(VisibleAnywhere)
class USpringArmComponent* SpringArm;
UPROPERTY(VisibleAnywhere)
class UCameraComponent* Camera;
private:
UPROPERTY(VisibleAnywhere)
class UCWeaponComponent* Weapon;
UPROPERTY(VisibleAnywhere)
class UCMontagesComponent* Montages;
UPROPERTY(VisibleAnywhere)
class UCMovementComponent* Movement;
UPROPERTY(VisibleAnywhere)
class UCStateComponent* State;
/** 파쿠르 */
private:
UPROPERTY(VisibleDefaultsOnly)
class USceneComponent* ArrowGroup;//파쿠르를 위한 ArrowGroup
UPROPERTY(VisibleDefaultsOnly)
class UArrowComponent* Arrows[(int32)EParkourArrowType::Max];
UPROPERTY(VisibleDefaultsOnly)
class UCParkourComponent* Parkour;
/** 파쿠르 */
UPROPERTY(VisibleDefaultsOnly)
class UCZoomComponent* Zoom;
public:
ACPlayer();
protected:
virtual void BeginPlay() override;
public:
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
FGenericTeamId GetGenericTeamId() const override { return FGenericTeamId(TeamID); }
private:
UFUNCTION()
void OnStateTypeChanged(EStateType InPrevType, EStateType InNewType);
private:
void OnAvoid();
private:
void BackStep();
public:
void End_BackStep() override;//ICharacter의 함수 오버라이드
public:
void Click_RightButton();
public:
void Landed(const FHitResult& Hit) override;//BP의 OnLanded C++버젼.
private:
void SetZooming(float InValue);
};
헤더 추가
- #include "GenericTeamAgentInterface.h"
다중상속 추가
- public IGenericTeamAgentInterface
변수 추가
- UPROPERTY(EditDefaultsOnly, Category = "Team")
uint8 TeamID = 1;
함수 추가
- FGenericTeamId GetGenericTeamId() const override { return FGenericTeamId(TeamID); }
CPlayer.cpp
#include "Characters/CPlayer.h"
#include "Global.h"
#include "CAnimInstance.h"
#include "GameFramework/SpringArmComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "Camera/CameraComponent.h"
#include "Components/SkeletalMeshComponent.h"
#include "Components/InputComponent.h"
#include "Components/CMontagesComponent.h"
#include "Components/CMovementComponent.h"
#include "Components/CWeaponComponent.h"
#include "Components/CZoomComponent.h"
#include "Components/ArrowComponent.h"
ACPlayer::ACPlayer()
{
CHelpers::CreateComponent<USpringArmComponent>(this, &SpringArm, "SpringArm", GetMesh());
CHelpers::CreateComponent<UCameraComponent>(this, &Camera, "Camera", SpringArm);
CHelpers::CreateActorComponent<UCWeaponComponent>(this, &Weapon, "Weapon");
CHelpers::CreateActorComponent<UCMontagesComponent>(this, &Montages, "Montages");
CHelpers::CreateActorComponent<UCMovementComponent>(this, &Movement, "Movement");
CHelpers::CreateActorComponent<UCStateComponent>(this, &State, "State");
CHelpers::CreateActorComponent<UCParkourComponent>(this, &Parkour, "Parkour");
CHelpers::CreateActorComponent<UCZoomComponent>(this, &Zoom, "Zoom");
GetMesh()->SetRelativeLocation(FVector(0, 0, -90));
GetMesh()->SetRelativeRotation(FRotator(0, -90, 0));
USkeletalMesh* mesh;
CHelpers::GetAsset<USkeletalMesh>(&mesh, "SkeletalMesh'/Game/Character/Mesh/SK_Mannequin.SK_Mannequin'");
GetMesh()->SetSkeletalMesh(mesh);
TSubclassOf<UCAnimInstance> animInstance;
CHelpers::GetClass<UCAnimInstance>(&animInstance, "AnimBlueprint'/Game/ABP_Character.ABP_Character_C'");
GetMesh()->SetAnimClass(animInstance);
SpringArm->SetRelativeLocation(FVector(0, 0, 140));
SpringArm->SetRelativeRotation(FRotator(0, 90, 0));
SpringArm->TargetArmLength = 200;
SpringArm->bDoCollisionTest = false;
SpringArm->bUsePawnControlRotation = true;
SpringArm->bEnableCameraLag = true;
GetCharacterMovement()->RotationRate = FRotator(0, 720, 0);
CHelpers::CreateComponent<USceneComponent>(this, &ArrowGroup, "ArrowGroup", GetCapsuleComponent());//ArrowGroup을 생성하고 GetCapsuleComponent 아래로 붙여준다.
//파쿠르에 활용한 Arrows들을 생성한다.
for (int32 i = 0; i < (int32)EParkourArrowType::Max; i++)
{
FString name = StaticEnum<EParkourArrowType>()->GetNameStringByIndex(i);
CHelpers::CreateComponent<UArrowComponent>(this, &Arrows[i], FName(name), ArrowGroup);
switch ((EParkourArrowType)i)
{
case EParkourArrowType::Center:
Arrows[i]->ArrowColor = FColor::Red;
break;
case EParkourArrowType::Ceil:
Arrows[i]->ArrowColor = FColor::Green;
Arrows[i]->SetRelativeLocation(FVector(0, 0, 100));
break;
case EParkourArrowType::Floor:
Arrows[i]->ArrowColor = FColor::Blue;
Arrows[i]->SetRelativeLocation(FVector(0, 0, -80));
break;
case EParkourArrowType::Left:
Arrows[i]->ArrowColor = FColor::Magenta;
Arrows[i]->SetRelativeLocation(FVector(0, -30, 0));
break;
case EParkourArrowType::Right:
Arrows[i]->ArrowColor = FColor::Magenta;
Arrows[i]->SetRelativeLocation(FVector(0, 30, 0));
break;
case EParkourArrowType::Land:
Arrows[i]->ArrowColor = FColor::Yellow;
Arrows[i]->SetRelativeLocation(FVector(200, 0, 100));
Arrows[i]->SetRelativeRotation(FRotator(-90, 0, 0));
break;
}
}
}
void ACPlayer::BeginPlay()
{
Super::BeginPlay();
Movement->OnRun(); //Movement의 기본을 Run으로 설정
Movement->DisableControlRotation();//Movement의 기본을 DisableControlRotation으로 설정
State->OnStateTypeChanged.AddDynamic(this, &ACPlayer::OnStateTypeChanged);
}
void ACPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
PlayerInputComponent->BindAxis("MoveForward", Movement, &UCMovementComponent::OnMoveForward);
PlayerInputComponent->BindAxis("MoveRight", Movement, &UCMovementComponent::OnMoveRight);
PlayerInputComponent->BindAxis("VerticalLook", Movement, &UCMovementComponent::OnVerticalLook);
PlayerInputComponent->BindAxis("HorizontalLook", Movement, &UCMovementComponent::OnHorizontalLook);
PlayerInputComponent->BindAction("Sprint", EInputEvent::IE_Pressed, Movement, &UCMovementComponent::OnSprint);
PlayerInputComponent->BindAction("Sprint", EInputEvent::IE_Released, Movement, &UCMovementComponent::OnRun);
PlayerInputComponent->BindAction("Avoid", EInputEvent::IE_Pressed, this, &ACPlayer::OnAvoid);
//PlayerInputComponent->BindAxis("Zoom", Zoom, &UCZoomComponent::SetZoomValue);//Value로 연동되게하면 Bow 모드 시 문제가 될 수 있다.
PlayerInputComponent->BindAxis("Zoom", this, &ACPlayer::SetZooming);//Bow 모드가 아닐 때만 사용하려고 SetZooming으로 설정하여 만들었다.
PlayerInputComponent->BindAction("Fist", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SetFistMode);
PlayerInputComponent->BindAction("Sword", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SetSwordMode);
PlayerInputComponent->BindAction("Hammer", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SetHammerMode);
PlayerInputComponent->BindAction("Warp", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SetWarpMode);
PlayerInputComponent->BindAction("Around", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SetAroundMode);
PlayerInputComponent->BindAction("Bow", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SetBowMode);
PlayerInputComponent->BindAction("Action", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::DoAction);
//PlayerInputComponent->BindAction("SubAction", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SubAction_Pressed);
PlayerInputComponent->BindAction("SubAction", EInputEvent::IE_Pressed, this, &ACPlayer::Click_RightButton);
PlayerInputComponent->BindAction("SubAction", EInputEvent::IE_Released, Weapon, &UCWeaponComponent::SubAction_Released);
}
void ACPlayer::OnStateTypeChanged(EStateType InPrevType, EStateType InNewType)
{
switch (InNewType)
{
case EStateType::BackStep: BackStep(); break;
}
}
void ACPlayer::OnAvoid()
{
CheckFalse(State->IsIdleMode());
CheckFalse(Movement->CanMove());
CheckTrue(InputComponent->GetAxisValue("MoveForward") >= 0.0f);//뒷방향을 입력했다면
State->SetBackStepMode();//State을 BackStepMode로 변경한다.
}
void ACPlayer::BackStep()
{
Movement->EnableControlRotation();//정면을 바라본 상태로 뒤로 뛰어야하기 때문에 EnableControlRotation으로 만들어준다.
Montages->PlayBackStepMode();//PlayBackStepMode()를 통해 몽타주 재생.
}
void ACPlayer::End_BackStep()
{
Movement->DisableControlRotation();//Backstep이 끝나면 원래대로 돌려준다.
State->SetIdleMode();//Idle상태로 돌려줌.
}
void ACPlayer::Click_RightButton()
{
if (Weapon->IsUnarmedMode())
{
Parkour->DoParkour();
return;
}
Weapon->SubAction_Pressed();
}
void ACPlayer::Landed(const FHitResult& Hit)
{
Parkour->DoParkour(true);
}
void ACPlayer::SetZooming(float InValue)
{
CheckTrue(Weapon->IsBowMode());//BowMode이면 바로 리턴
Zoom->SetZoomValue(InValue);//BowMode가 아닌 경우 Zoom In&Out 가능.
}
변경사항 없음.
※ 참고사항: GenericTeamAgentInterface.h
실행화면
'⭐ Unreal Engine > UE RPG AI' 카테고리의 다른 글
[UE] Behavior Tree: 무기 장착 Abort (0) | 2023.08.01 |
---|---|
[UE] Behavior Tree: 피격(Hitted) (0) | 2023.07.31 |
[UE] Behavior Tree: 무기 장착 및 공격 (0) | 2023.07.27 |
[UE] Behavior Tree: 무기 장착(Equip) (0) | 2023.07.26 |
[UE] Behavior Tree: 순찰(Patrol) (0) | 2023.07.25 |
댓글
이 글 공유하기
다른 글
-
[UE] Behavior Tree: 피격(Hitted)
[UE] Behavior Tree: 피격(Hitted)
2023.07.31 -
[UE] Behavior Tree: 무기 장착 및 공격
[UE] Behavior Tree: 무기 장착 및 공격
2023.07.27 -
[UE] Behavior Tree: 무기 장착(Equip)
[UE] Behavior Tree: 무기 장착(Equip)
2023.07.26 -
[UE] Behavior Tree: 순찰(Patrol)
[UE] Behavior Tree: 순찰(Patrol)
2023.07.25