[UE] Behavior Tree: 무기 장착 Abort

Behavior Tree의 UCBTTaskNode 내에 AbortTask를 추가할 것이다. Task의 성공과 실패 외에도 Abort가 걸리는 상황을 추가하여 Behavior Tree 실행 중 Task가 빨리 또는 느리게 실행되어 문제가 되는 상황을 방지할 것이다. 일종의 예외처리도 가능하여 Abort는 대부분의 경우 Behavior Tree에 필수적으로 사용된다.
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 CBTTaskNode_Action.h .cpp CBTTaskNode_Equip.h .cpp CBTTaskNode_Hitted.h .cpp CBTTaskNode_Patrol.h .cpp CBTTaskNode_Speed.h .cpp CPatrol.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.h .cpp 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 CWeaponData.h .cpp CWeaponStructures.h .cpp |
||
Global.h CGameMode.h .cpp U2212_06.Build.cs |
||
U2212_06.uproject | ||
무기 장착 Abort
CEquipment
CEquipment.h
더보기
#pragma once #include "CoreMinimal.h" #include "UObject/NoExportTypes.h" #include "Weapons/CWeaponStructures.h" #include "CEquipment.generated.h" //직렬화하여 BP에서 사용가능하도록 DYNAMIC, 여러함수를 받을 수 있도록 MULTICAST 사용. DECLARE_DYNAMIC_MULTICAST_DELEGATE(FEquipmentEquip); DECLARE_DYNAMIC_MULTICAST_DELEGATE(FEquipmentBeginEquip); DECLARE_DYNAMIC_MULTICAST_DELEGATE(FEquipmentUnequip); UCLASS() class U2212_06_API UCEquipment : public UObject { GENERATED_BODY() public: //실시간으로 bEquipped로 가져온다. 주소로 가져온다. FORCEINLINE bool GetBeginEquip() { return bBeginEquip; } FORCEINLINE const bool* GetEquipped() { return &bEquipped; } public: void BeginPlay(class ACharacter* InOwner, const FEquipmentData& InData); public: UFUNCTION(BlueprintNativeEvent)//필요시 BP에서 재정의하기 위해 BlueprintNativeEvent사용. void Equip(); void Equip_Implementation(); UFUNCTION(BlueprintNativeEvent) void Begin_Equip(); void Begin_Equip_Implementation(); UFUNCTION(BlueprintNativeEvent) void End_Equip(); void End_Equip_Implementation(); UFUNCTION(BlueprintNativeEvent) void Unequip(); void Unequip_Implementation(); public: FEquipmentEquip OnEquipmentEquip;//DECLARE_DYNAMIC_MULTICAST_DELEGATE 하였다. FEquipmentBeginEquip OnEquipmentBeginEquip;//DECLARE_DYNAMIC_MULTICAST_DELEGATE 하였다. FEquipmentUnequip OnEquipmentUnequip;//DECLARE_DYNAMIC_MULTICAST_DELEGATE 하였다. private: class ACharacter* OwnerCharacter; FEquipmentData Data; private: class UCMovementComponent* Movement; class UCStateComponent* State; private: bool bBeginEquip;//Equip이 시작되었는가 확인 bool bEquipped; //Equip이 완료되었는지 확인 };
인라인 함수
- FORCEINLINE bool GetBeginEquip() { return bBeginEquip; }
CEquipment.cpp
더보기
#include "Weapons/CEquipment.h" #include "Global.h" #include "GameFramework/Character.h" #include "Components/CMovementComponent.h" #include "Components/CStateComponent.h" #include "CEquipment.h" void UCEquipment::BeginPlay(ACharacter* InOwner, const FEquipmentData& InData) { OwnerCharacter = InOwner; Data = InData; Movement = CHelpers::GetComponent<UCMovementComponent>(InOwner); State = CHelpers::GetComponent<UCStateComponent>(InOwner); } void UCEquipment::Equip_Implementation() { State->SetEquipMode(); if (OnEquipmentEquip.IsBound())//활 장착 확인? OnEquipmentEquip.Broadcast(); if (Data.bCanMove == false) Movement->Stop(); if (Data.bUseControlRotation) Movement->EnableControlRotation(); if (!!Data.Montage) { OwnerCharacter->PlayAnimMontage(Data.Montage, Data.PlayRate); } else { Begin_Equip(); End_Equip(); } } void UCEquipment::Begin_Equip_Implementation() { bBeginEquip = true; if (OnEquipmentBeginEquip.IsBound()) OnEquipmentBeginEquip.Broadcast(); } void UCEquipment::End_Equip_Implementation() { bBeginEquip = false; bEquipped = true; Movement->Move(); State->SetIdleMode(); } void UCEquipment::Unequip_Implementation() { bEquipped = false; Movement->DisableControlRotation(); if (OnEquipmentUnequip.IsBound()) OnEquipmentUnequip.Broadcast(); }
변경사항 없음
CBTTaskNode_Equip
CBTTaskNode_Equip.h
더보기
#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: EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override; void TickTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds) override; EBTNodeResult::Type AbortTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override; };
테스크 추가
- EBTNodeResult::Type AbortTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;
CBTTaskNode_Equip.cpp
더보기
#include "BehaviorTree/CBTTaskNode_Equip.h" #include "Global.h" #include "Characters/CEnemy_AI.h" #include "Characters/CAIController.h" #include "Components/CStateComponent.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);//weapon이 없다면 EBTNodeResult::Failed 리턴 if (Type == weapon->GetWeaponType())//장착될 무기 == 현재 장착된 무기 return EBTNodeResult::Succeeded;//새로 장착시킬 필요 없으니 바로 Succeeded를 리턴 switch (Type) { case EWeaponType::Sword: weapon->SetSwordMode(); break;//Sword 장착 } return EBTNodeResult::InProgress;//장착 동작이 나올 수 있도록 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);//weapon을 가져온다. const bool* bEquipped = weapon->GetEquipment()->GetEquipped(); UCStateComponent* state = CHelpers::GetComponent<UCStateComponent>(ai); if(state->IsIdleMode() && *bEquipped) { FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded); return; } } EBTNodeResult::Type UCBTTaskNode_Equip::AbortTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) { Super::AbortTask(OwnerComp, NodeMemory); ACAIController* controller = Cast<ACAIController>(OwnerComp.GetOwner()); ACEnemy_AI* ai = Cast<ACEnemy_AI>(controller->GetPawn()); UCWeaponComponent* weapon = CHelpers::GetComponent<UCWeaponComponent>(ai); if (weapon == nullptr)//무기가 없다면 { FinishLatentAbort(OwnerComp);//중단으로 끝낸다. return EBTNodeResult::Failed;//실패 리턴 } bool bBeginEquip = weapon->GetEquipment()->GetBeginEquip();//GetBeginEquip()으로 CEquipment의 bBeginEquip를 넣어준다. bBeginEquip=true면 Equip이 시작되었다는 의미다. if (bBeginEquip == false) weapon->GetEquipment()->Begin_Equip(); weapon->GetEquipment()->End_Equip(); return EBTNodeResult::Aborted;//Aborted는 취소 마감, 위(Root)로 올라감. Succeeded는 성공종료. }
테스크 정의
- EBTNodeResult::Type UCBTTaskNode_Equip::AbortTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
- if (weapon == nullptr) {
FinishLatentAbort(OwnerComp);
return EBTNodeResult::Failed;
} - bool bBeginEquip = weapon->GetEquipment()->GetBeginEquip();
- GetBeginEquip()으로 CEquipment의 bBeginEquip를 넣어준다. bBeginEquip=true면 Equip이 시작되었다는 의미다.
- if (bBeginEquip == false)
weapon->GetEquipment()->Begin_Equip(); - weapon->GetEquipment()->End_Equip();
- return EBTNodeResult::Aborted;
- Aborted는 취소 마감, 위(Root)로 올라감. Succeeded는 성공종료.
- if (weapon == nullptr) {
실행화면

활 조준 Zoom In 시 튕기는 오류해결
CPlayer
FPS처럼 Zoom이 일어나는 경우, 1인칭 시점 카메라를 추가해서 만들고 Zoom 시에 카메라 전환을 하여 1인칭 전용 카메라를 사용해준다.
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 OnRightButton(); void OffRightButton(); public: void Landed(const FHitResult& Hit) override;//BP의 OnLanded C++버젼. private: void SetZooming(float InValue); };
함수 수정 및 추가
- 변경 전:
- void Click_RightButton();
- 변경 후:
- void OnRightButton();
- void OffRightButton();
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, this, &ACPlayer::OnRightButton); PlayerInputComponent->BindAction("SubAction", EInputEvent::IE_Released, this, &ACPlayer::OffRightButton); } 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::OnRightButton() { if (Weapon->IsUnarmedMode()) { Parkour->DoParkour(); return; } if (Weapon->IsBowMode()) { //BowMode(활 장착)일 때 우클릭을 누르고 있을때 Zoom기능을 꺼준다. Zoom->SetComponentTickEnabled(false); } Weapon->SubAction_Pressed(); } void ACPlayer::OffRightButton() { if (Weapon->IsBowMode()) { //BowMode(활 장착)일 때 우클릭을 떼면 Zoom기능을 꺼준다. Zoom->SetComponentTickEnabled(true); } Weapon->SubAction_Released(); } 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 가능. }
함수 수정 및 추가
- void ACPlayer::OnRightButton()
- if (Weapon->IsBowMode()) { Zoom->SetComponentTickEnabled(false); }
- Weapon->SubAction_Pressed();
- void ACPlayer::OffRightButton()
- if (Weapon->IsBowMode()) { Zoom->SetComponentTickEnabled(true); }
- Weapon->SubAction_Released();
'⭐ Unreal Engine > UE RPG AI' 카테고리의 다른 글
[UE] Behavior Tree: 활 조준 및 발사하기 (0) | 2023.08.08 |
---|---|
[UE] Behavior Tree: 활 Enemy 생성, Player 바라보기 (0) | 2023.08.07 |
[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: 활 조준 및 발사하기
[UE] Behavior Tree: 활 조준 및 발사하기
2023.08.08 -
[UE] Behavior Tree: 활 Enemy 생성, Player 바라보기
[UE] Behavior Tree: 활 Enemy 생성, Player 바라보기
2023.08.07 -
[UE] Behavior Tree: 피격(Hitted)
[UE] Behavior Tree: 피격(Hitted)
2023.07.31 -
[UE] Behavior Tree: 무기 장착 및 공격
[UE] Behavior Tree: 무기 장착 및 공격
2023.07.27
댓글을 사용할 수 없습니다.