[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
댓글을 사용할 수 없습니다.