컴퓨터 및 게임 관련 전공인이 아닌 문외한 일반인이 언리얼 엔진을 배우면서 정리한 내용입니다.
그날그날 배웠던 내용을 제가 나중에 보기 위해 정리한 것으로, 지금 당장 보기에 부족한 점이 아주아주 많고 추후에 수정이 될 수도 있습니다.
오탈자 및 잘못 기재된 내용 지적, 부족한 내용 설명은 언제든지 환영입니다.
본글은 언리얼 엔진 5.5.4 버전 영문판을 기준으로 합니다.
----------------------------------------------------------------------------------------------------------------
36일차 학습 내용
- Simple Parelled
- BT 작성 예시
Simple Parelled
이번에는 "Simple Parelled" 를 활용하여 이동하며 공격하는 기능을 추가해보도록 하겠다.
BT에서 우클릭을 하고 'Simple Parelled' 을 검색하면 노드를 생성할 수 있다.
"Simple Parelled" 노드는 좌측에 연결된 노드를 메인으로 실행하면서 우측에 연결된 노드를 서브로 실행하는 것이다.
위 그림같은 경우는 적이 플레이어를 인식하면 공격을 하면서 플레이어에게 접근하도록 하는 것이다.
다만 이대로 게임을 실행하면 적이 공격은 하지만 플레이어를 추적하지 않는 문제가 발생한다.
공격하는 애니메이션은 애니메이션 재생 시간이 짧아 그동안 플레이어에게 추적할 시간을 주지 않기에, 이동하지 않고 공격만 하는 것이다.
그러면 이동하면서 공격을 하도록 다시 BT를 수정해보도록 하겠다.
위 그림과 같이 Move To 노드와 Attack 노드의 위치를 바꿔주면 플레이어를 추적하며 공격하는 것을 확인할 수 있다.
여기서 문제는 적이 쉬지 않고 계속 공격하는 것이다.
자연스럽게 해주기 위해 위 그림과 같이 Sequence를 생성한 후 Attack 노드를 실행한 뒤에 Wait 노드를 실행시켜줘서, 공격에 간격을 줘서 좀 더 자연스럽게 해주었다.
그리고 적의 ABP로 들어가서 "Layered Blend per bone" 노드를 추가하여, 적이 이동하면서 공격할 때 상하체의 움직임을 분리해 좀 더 자연스러운 애니메이션이 나오도록 설정해주었다.
위의 작업까지 해줄 경우 적이 플레이어에게 이동 중에도 자연스럽게 공격을 한다는 것이다.
이것이 의도한 것이라면 수정할 필요가 없지만, 필자는 이동 중에는 공격하지 않고 플레이어와 어느 정도 거리가 가까워졌을 때 공격을 하도록 해주고 싶기에 수정을 해줄 것이다.
여기서 "플레이어와 어느 정도 거리가 가까워졌을 때" 라는 조건이 있기에, Selector 노드에 Service를 삽입해서 이 조건을 추가해줄 것이다.
지난 35일차에서 했던 것과 마찬가지로 'BTService_Blackboard" 를 부모로 하는 BTService를 새로 생성해주고, 플레이어를 인식하고 공격하게 할 것이기에 "BTService_AttackRange" 라고 명명해주었다.
아래와 같이 코드를 입력해준다.
BTService_AttackRange.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "BehaviorTree/Services/BTService_BlackboardBase.h"
#include "BTService_AttackRange.generated.h"
/**
*
*/
UCLASS()
class MYPROJECT_API UBTService_AttackRange : public UBTService_BlackboardBase
{
GENERATED_BODY()
public:
UBTService_AttackRange();
protected:
virtual void TickNode(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds) override;
};
|
cs |
BTService_AttackRange.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
#include "BTService_AttackRange.h"
#include "NormalZombie.h" // 추가
#include "Kismet/GameplayStatics.h" // 추가
#include "GameFramework/CharacterMovementComponent.h" // 추가
#include "ZombieAIController.h" // 추가
UBTService_AttackRange::UBTService_AttackRange()
{
NodeName = TEXT("Attack Range Service");
Interval = 0.5f;
}
void UBTService_AttackRange::TickNode(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds) // Attack Task에 작성한 것 복사
{
APawn* PlayerPawn = UGameplayStatics::GetPlayerPawn(GetWorld(), 0);
AZombieAIController* AIController = Cast<AZombieAIController>(OwnerComp.GetAIOwner());
ANormalZombie* Zombie = Cast<ANormalZombie>(AIController ? AIController->GetPawn() : nullptr);
if (!PlayerPawn || !AIController) return;
const float DistancetoPlayer = FVector::Dist(Zombie->GetActorLocation(), PlayerPawn->GetActorLocation());
UBlackboardComponent* BB = AIController->GetBlackboardComponent();
const float AttackRange = 300.0f; // 공격할 범위 설정
if (DistancetoPlayer <= AttackRange) // 위에서 설정한 공격 범위
{
if (AIController)
{
if (BB)
{
BB->SetValueAsBool(TEXT("AttackState"), true); // CombatState를 AttackState로 변환
BB->SetValueAsVector(TEXT("PlayerActor"), PlayerPawn->GetActorLocation());
}
}
}
else
{
if (AIController)
{
if (BB)
{
BB->SetValueAsBool(TEXT("AttackState"), false);
}
}
}
}
|
cs |
지난 35일차에서 작성했던 "PlayerDetection" BTSevice를 복사해서 가져오고, 일부분만 수정해주면 된다.
cpp 23번째 줄에서 AttackRange를 설정해준 뒤 25번째 줄에서 조건으로 걸어주었고, 31번째와 42번째 줄의 "CombatState" 를 "AttackState" 로 수정해주었다.
그리고 위 그림과 같이 노드들을 연결해주었다.
위 노드에 적힌 주석을 보면 쉽게 이해가 가능하다.
게임을 실행해보면 위 그림과 같이 이동 후에 플레이어와 어느정도 가까워졌을 때 한 번만 공격하는 것을 확인할 수 있다.
BT 작성 예시
위 그림은 간단한 적의 AI의 BT를 대략적으로 짜둔 것이다.
*오늘까지 작성한 코드 정리
BTService_AttackRange.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "BehaviorTree/Services/BTService_BlackboardBase.h"
#include "BTService_AttackRange.generated.h"
/**
*
*/
UCLASS()
class MYPROJECT_API UBTService_AttackRange : public UBTService_BlackboardBase
{
GENERATED_BODY()
public:
UBTService_AttackRange();
protected:
virtual void TickNode(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds) override;
};
|
cs |
BTService_AttackRange.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
#include "BTService_AttackRange.h"
#include "NormalZombie.h" // 추가
#include "Kismet/GameplayStatics.h" // 추가
#include "GameFramework/CharacterMovementComponent.h" // 추가
#include "ZombieAIController.h" // 추가
UBTService_AttackRange::UBTService_AttackRange()
{
NodeName = TEXT("Attack Range Service");
Interval = 0.5f;
}
void UBTService_AttackRange::TickNode(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds) // Attack Task에 작성한 것 복사
{
APawn* PlayerPawn = UGameplayStatics::GetPlayerPawn(GetWorld(), 0);
AZombieAIController* AIController = Cast<AZombieAIController>(OwnerComp.GetAIOwner());
ANormalZombie* Zombie = Cast<ANormalZombie>(AIController ? AIController->GetPawn() : nullptr);
if (!PlayerPawn || !AIController) return;
const float DistancetoPlayer = FVector::Dist(Zombie->GetActorLocation(), PlayerPawn->GetActorLocation());
UBlackboardComponent* BB = AIController->GetBlackboardComponent();
const float AttackRange = 300.0f; // 공격할 범위 설정
if (DistancetoPlayer <= AttackRange) // 위에서 설정한 공격 범위
{
if (AIController)
{
if (BB)
{
BB->SetValueAsBool(TEXT("AttackState"), true); // CombatState를 AttackState로 변환
BB->SetValueAsVector(TEXT("PlayerActor"), PlayerPawn->GetActorLocation());
}
}
}
else
{
if (AIController)
{
if (BB)
{
BB->SetValueAsBool(TEXT("AttackState"), false);
}
}
}
}
|
cs |
'Unreal Engine > GCC Class (5.5.4)' 카테고리의 다른 글
Unreal Engine 5 배워보기 - 38일차 (0) | 2025.05.16 |
---|---|
Unreal Engine 5 배워보기 - 37일차 (0) | 2025.05.15 |
Unreal Engine 5 배워보기 - 35일차 (0) | 2025.05.13 |
Unreal Engine 5 배워보기 - 34일차 (0) | 2025.05.12 |
Unreal Engine 5 배워보기 - 33일차 (0) | 2025.05.09 |