FName vs FString
FName
FName 은 콘텐츠 브라우저에서 애셋 이름을 지을 때, 스켈레탈 메시에서 본에 접근할 때 등등에 사용된다.
FName 은 문자열을 하나하나 비교하지 않고, 주어진 문자열을 해싱한 테이블에 저장한 후, index 로 값을 비교한다.
이 때문에 키로 FName 에 접근하는 속도가 빠르며, 스트링에서 FName 으로의 변환도 해시 테이블을 사용하므로 상대적으로 빠르다.
FName 은 대소문자를 구분하지 않고, 변경도 불가능하다. 조작할 수 없다.
void AMonster_Base::BeginPlay()
{
Super::BeginPlay();
// 데이터 입력
// 몬스터 데이터 테이블을 가져온다.
UDataTable* DataTable = LoadObject<UDataTable>(nullptr, TEXT("/Script/Engine.DataTable'/Game/BlueprintClass/Monster/Table/DT_Monster.DT_Monster'"));
if (IsValid(DataTable))
{
const UEnum* MonEnum = FindObject<UEnum>(ANY_PACKAGE, TEXT("EMON_TYPE")); // EMON_TYPE 의 enum 정보를 가져온다.
// FName 으로 가져오기, Enum 타입 이름으로 나옴
FName name = MonEnum->GetNameByValue((int64)m_MonType);
}
GetCapsuleComponent()->OnComponentHit.AddDynamic(this, &AMonster_Base::OnHit);
GetCapsuleComponent()->OnComponentBeginOverlap.AddDynamic(this, &AMonster_Base::BeginOverlap);
GetCapsuleComponent()->OnComponentEndOverlap.AddDynamic(this, &AMonster_Base::EndOverlap);
}
FString
FString 은 조작이 가능한 유일한 스트링 클래스이다.
// FString 생성
FString TestFString = FString(TEXT("TestFString"));
// 뷰포트에 출력
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Blue, TestFString);
// 출력 로그에 출력
UE_LOG(MyClass, Log, TEXT("This is %s"), *TestFString);
// Printf 함수도 있다
FString::Printf(TEXT("I am %s and I am at %.2f", *GetName(), GetActorLocation().X);
Printf 함수나 UE_LOG 에 인자로 전달할 경우, FString 을 넘길 때 %s 로 받게되면 * 를 붙여 주소를 넘겨 주어야 한다.
이는 %s 가 TCHAR* 포인터 타입을 받기 때문이다.
즉, TCHAR 타입 배열의 첫번째 원소의 주소를 받는 것인데, 이는 C 에서도 문자열을 넘길 때 char * 을 받으면서 첫번째 원소의 주소를 읽는 것과 동일하다고 생각하면 된다.
FString 은 실제로 TArray<TCHAR> 을 문자열 데이터로 저장하는 Wrapper 클래스라고 생각해도 무방하다.
void AMonster_Base::BeginPlay()
{
Super::BeginPlay();
// 데이터 입력
// 몬스터 데이터 테이블을 가져온다.
UDataTable* DataTable = LoadObject<UDataTable>(nullptr, TEXT("/Script/Engine.DataTable'/Game/BlueprintClass/Monster/Table/DT_Monster.DT_Monster'"));
if (IsValid(DataTable))
{
const UEnum* MonEnum = FindObject<UEnum>(ANY_PACKAGE, TEXT("EMON_TYPE")); // EMON_TYPE 의 enum 정보를 가져온다.
// FString 으로 가져오기, Enum 풀네임으로 나옴
FString fString = MonEnum->GetNameStringByValue((int64)m_MonType);
}
GetCapsuleComponent()->OnComponentHit.AddDynamic(this, &AMonster_Base::OnHit);
GetCapsuleComponent()->OnComponentBeginOverlap.AddDynamic(this, &AMonster_Base::BeginOverlap);
GetCapsuleComponent()->OnComponentEndOverlap.AddDynamic(this, &AMonster_Base::EndOverlap);
}
https://docs.unrealengine.com/5.1/ko/string-handling-in-unreal-engine/
스트링 처리
UE4 에서 사용가능한 스트링 클래스에 대한 개요와 FName, FText, FString 에 대한 참고 안내서입니다.
docs.unrealengine.com
선생님이 알려주신 방법!
lass UNREAL_3TH_API AMonster_Base : public ACharacter
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Info", meta = (RowType = "MonInfo"))
FDataTableRowHandle m_MonTableRow;
}
meta = (RowType = "MonInfo") 의 의미 ( 사용법 : meta = (RowType=”MyRowName”) )
-> to filter DataTable Assets by their row using the metadata.
pInfo = m_MonTableRow.DataTable->FindRow<FMonInfo>(m_MonTableRow.RowName, TEXT(""));
FindRow를 통해 해당 행의 이름에 해당하는 데이터들을 가져온다.
(행 하나가 우리가 작성한 구조체 단위)
* FDataTableRowHandle
- DataTable/CurveTable - 데이터를 담는 표에 대한 콘텐츠 레퍼런스다.
- RowName - 데이터를 구하고자 하는 행의 첫 열 이름이다.
- 템플릿 함수 호출에 구조체를 지정할 수 있다.
https://docs.unrealengine.com/5.1/ko/data-driven-gameplay-elements-in-unreal-engine/
데이터 주도형 게임플레이 요소
외부 저장 데이터를 사용하여 게임플레이 요소를 구동시키는 법입니다.
docs.unrealengine.com
BeginPlay 보다 앞선 함수 OnConstruction
UCLASS()
class UNREAL_3TH_API AMonster_Base : public ACharacter
{
GENERATED_BODY()
protected:
// 에디터 상에서 속성, 위치값이 변경될 때 호출되는 함수
// begin play 보다 먼저 호출돼서 게임 시작하지 않아도 값 변경이 가능하다
virtual void OnConstruction(const FTransform& transform) override;
}
위의 BeginPlay 에서 진행한 몬스터 enum 찾기를 OnConstruction 에서 진행
void AMonster_Base::OnConstruction(const FTransform& transform)
{
// 데이터 테이블 안에서 몬스터 타입에 맞는 행 정보를 가져와서
FMonInfo* pInfo = nullptr;
if (IsValid(m_MonTableRow.DataTable) && !m_MonTableRow.RowName.IsNone())
{
pInfo = m_MonTableRow.DataTable->FindRow<FMonInfo>(m_MonTableRow.RowName, TEXT(""));
// 몬스터의 m_Info 값을 넣어준다.
if (nullptr != pInfo)
m_Info = *pInfo;
}
}
기능 추가
- 수류탄 던졌을 때 카메라 진동
CameraShakeBase 상속받아서 BPC_ShakeDefault 생성
void AGranade::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
m_AccTime += DeltaTime;
if (m_LifeTime < m_AccTime)
{
// 폭발할 때, 카메라 쉐이크 호출
// 게임플레이 도중 클래스 찾아오는것
TSubclassOf<UCameraShakeBase> pShakeClass = LoadClass<UCameraShakeBase>(nullptr, TEXT("/Script/Engine.Blueprint'/Game/BlueprintClass/Effect/BPC_ShakeDefault.BPC_ShakeDefault_C'"));
if (IsValid(pShakeClass))
{
// 주체 : 컨트롤러
GetWorld()->GetFirstPlayerController()->ClientStartCameraShake(pShakeClass);
}
}
}
몬스터 인공지능
행동트리 이용한 AIController 제작
레벨에 배치된 애들은 다 Actor 에서 파생
Actor 에서 파생된 애들 중에 Pawn을 상속 받은 애들이 있다 -> Character
Character를 상속받은 BPC_Character
Pawn 의 주요기능 -> Controller에 빙의할 수 있다.
캐릭터는 Controller 를 상속받은 PlayerController 빙의하고 있다
몬스터는 Controller 를 상속받은 AIController 가 빙의할 것이다.
PlayerController vs AIController
PlayerController 는 Input Component 를 갖고 있어서 특정 키가 발생했을 때 일어날 동작을 바인딩해서 걸어놓을 수 있다.
ex)
void ACharacter_Base::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
UEnhancedInputComponent* InputCom = Cast<UEnhancedInputComponent>(PlayerInputComponent);
if (nullptr == InputCom)
return;
if (!InputActionSetting.IsNull())
{
UIADataAsset* pDA = InputActionSetting.LoadSynchronous();
for (int32 i = 0; i < pDA->IADataArr.Num(); ++i)
{
if (pDA->IADataArr[i].Action.IsNull())
continue;
switch (pDA->IADataArr[i].Type)
{
case EInputActionType::MOVE:
InputCom->BindAction(pDA->IADataArr[i].Action.LoadSynchronous(), ETriggerEvent::Triggered, this, &ACharacter_Base::Move);
break;
case EInputActionType::ROTATION:
InputCom->BindAction(pDA->IADataArr[i].Action.LoadSynchronous(), ETriggerEvent::Triggered, this, &ACharacter_Base::Rotation);
break;
case EInputActionType::JUMP:
InputCom->BindAction(pDA->IADataArr[i].Action.LoadSynchronous(), ETriggerEvent::Triggered, this, &ACharacter_Base::Jump);
break;
case EInputActionType::SPRINT_TOGGLE:
InputCom->BindAction(pDA->IADataArr[i].Action.LoadSynchronous(), ETriggerEvent::Triggered, this, &ACharacter_Base::SprintToggle);
break;
case EInputActionType::ATTACK:
InputCom->BindAction(pDA->IADataArr[i].Action.LoadSynchronous(), ETriggerEvent::Triggered, this, &ACharacter_Base::Attack);
break;
case EInputActionType::FIRE:
InputCom->BindAction(pDA->IADataArr[i].Action.LoadSynchronous(), ETriggerEvent::Triggered, this, &ACharacter_Base::Fire);
break;
case EInputActionType::RELOAD:
InputCom->BindAction(pDA->IADataArr[i].Action.LoadSynchronous(), ETriggerEvent::Triggered, this, &ACharacter_Base::Reload);
break;
}
}
}
}
AIController 는 자동으로 스스로 판단해서 움직일 수 있어야 한다.
Input Component 가 아닌 Behavior Tree Component 행동트리컴포넌트 를 갖고 있다.
state machine 을 좀 더 개선한 버전이다.
Behavior Tree 를 따라하다보면 저장해야하는데 그 때 사용하는 메모리 공간이 블랙 보드 이다.
Behavior Tree 와 Black Board 를 사용하려면 모듈 추가를 해야 한다.
프로젝트명.build.cs
추가한 것 :
"AIModule" "GamePlayTasks" "NavigationSystem"
* 추가를 하고 비쥬얼스튜디오를 끈 후, 다시 generate visual studio 를 해주어야 추가한 모듈이 적용이 된다.
public class Unreal_3th : ModuleRules
{
public Unreal_3th(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(new string[] {
"Core"
, "CoreUObject"
, "Engine"
, "InputCore"
, "EnhancedInput"
, "Niagara"
, "AIModule"
, "GamePlayTasks"
, "NavigationSystem"
});
PrivateDependencyModuleNames.AddRange(new string[] { });
}
1. AIController 를 상속받은 AIController_Default.h / AIController_Default.cpp 생성
#include "CoreMinimal.h"
#include "AIController.h"
#include "AIController_Default.generated.h"
UCLASS()
class UNREAL_3TH_API AAIController_Default : public AAIController
{
GENERATED_BODY()
public:
virtual void OnPossess(APawn* _Owner) override;
virtual void OnUnPossess() override;
};
#include "AIController_Default.h"
void AAIController_Default::OnPossess(APawn* _Owner)
{
Super::OnPossess(_Owner);
// 빙의 대상(몬스터) 로 부터, 사용할 행동트리를 가져온다.
}
void AAIController_Default::OnUnPossess()
{
Super::OnUnPossess();
}
2. 블루프린트 Behavior Tree / BlackBoard 생성
인공지능 -> 비헤이비어트리
인공지능 -> 블랙보드
Behavior Tree
Selector
- 데코레이터
노드를
- 서비스
일정 시간마다 수행 (주기적으로 해야하는 작업)
Sequence
'언리얼 5' 카테고리의 다른 글
230915 몬스터 AI - Trace, Attack ( 스스로 ) (0) | 2023.09.15 |
---|---|
230914 몬스터 AI - Move (0) | 2023.09.15 |
230912 무기 구현 / 몬스터 AI (0) | 2023.09.12 |
230911 싱글톤 / Trace / 사운드 / 수류탄 투사체 제작 (0) | 2023.09.11 |
230907 투사체 수정 / 카메라가 바라보는 방향으로 spine_01 뼈 회전 / 충돌 설정 / 몬스터 생성 (0) | 2023.09.11 |