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

 


 

 

 

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를 리턴해준다.


 

 

 


 

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

 


 

 

실행화면