매크로
프로젝트 상대 경로 추가
check vs ensure
Isvalid
CDO
StaticClass vs GetClass
UCLASS() : 클래스 매크로USTRUCT() : 구조체 매크로UENUM() : 열거형 매크로UCLASS() // 클래스 매크로
class PROJECTNAME_API UMyObject : public UObject
{
GENERATED_BODY()
};
PROJECTNAME_API : 다른 모듈에서 해당 객체에 접근하게 해주는 키워드// 프로젝트명.Build.cs
using UnrealBuildTool;
public class ShooterX : ModuleRules
{
public ShooterX(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(new string[]
{
"Core", "CoreUObject", "Engine", "InputCore", "EnhancedInput"
}
);
PrivateDependencyModuleNames.AddRange(new string[] {});
PublicIncludePaths.AddRange(new string[] { "ShooterX" });
}
}
PublicIncludePaths.AddRange(~) : 모듈의 퍼블릭 헤더 파일을 찾을 때 참고하는 경로에 "~" 폴더를 추가
모듈 컴파일러에게 "~" 폴더 안에 있는 헤더 파일들을 포함 경로로 참조하라고 알려줌
해당 모듈이 존재하는 디렉토리 내에서 "~"를 찾기 때문에 이를 고려하여 폴더 이름을 설정해야함
check(GameInstance != nullptr)
인자로 전달한 조건식이 거짓일 경우 프로그램을 중단시킴
디버깅 중이라면 중단점을 걸고, 릴리즈(shipping)빌드에선 게임이 꺼짐
checkf(GameInstance != nullptr, TEXT(”GameInstance is invalid.”))
그래서 보통 checkf를 사용하여 추가적인 디버깅 정보를 출력함
게임을 멈출정도로 중요한거여서 유효성 검사 필요할 때 사용
ensure(nullptr != GameInstance)
조건식이 거짓이더라고 프로그램을 계속 동작시킴
대신, 해당 위치까지의 콜스택을 출력해서 디버깅에 도움을 주고, 경고 메시지를 남김
릴리즈에서도 게임이 꺼지지 않음
ensureMsgf(nullptr != GameInstance, TEXT(”GameInstance is inalid.”))
런타임 중에 UObject 개체의 포인터가 유효한지 검사 할때 쓰는 함수
nullptr로만 확인하기에는 언리얼의 경우 GC 대상이거나 Pending Kill같은 경우가 있어 IsValid(~)을 사용하는 것이 안전
유효하다면 true를 반환
Native C++의 객체 생성자를 이용하여 객체를 초기화해도, 에디터에서 수정도 가능하고, 블루프린트에서 override되기도 하므로 초기화가 많이 일어남
따라서 CDO를 이용하여 클래스가 정의한 속성의 초기값을 한 번만 세팅해 두고, 객체 인스턴스가 생성될 때마다 CDO의 값을 복사하여 빠르게 초기화함
매번 동일한 초기화 코드를 돌리는 대신, 미리 만들어둔 CDO를 복사하므로 메모리 사용과 속도면에서 유리
먼저 CDO를 이용하여 초기화하고, 그 뒤에 생성자가 호출되어 남은 작업을 처리하므로 생성자도 가벼워짐
에디터에서 속성을 바꾸면 CDO에도 반영되며, 인스턴스 생성 시에도 적용됨
언리얼 엔진이 초기화되면 엔진 구동에 필요한 모듈이 순차적으로 로딩됨
해당 모듈에 작성된 언리얼 클래스들도 함께 로드되면서 클래스마다 CDO가 생성

엔진 초기화 이후 모든 CDO는 만들어지고 메모리에 로드됨
이 CDO를 GetDefault()를 이용하여 가져올 수 있음
CDO는 엔진이 종료될 때까지 메모리에 상주
USXGameInstance::USXGameInstance()
{
Name = TEXT("CDO"); // CDO에서의 이름
}
void USXGameInstance::Init()
{
Super::Init();
Name = TEXT("Instance"); // 런타임 도중 이름 바꿈
// 런타임에 인스턴스 생성
UE_LOG(LogTemp, Log, TEXT("GameInstance : %s"),
*(RuntimeClassInfo->GetDefaultObject<USXGameInstance>()->Name));
// 현재 객체
UE_LOG(LogTemp, Log, TEXT("GameInstance : %s"), *Name);
}

첫 번째 로그는 런타임에 인스턴스를 새로 생성하였으므로, 해당 인스턴스는 CDO를 복사하여 초기화 됨.
따라서 CDO에서의 Name값인 CDO가 출력
두 번째 로그는 현재 인스턴스의 Name이므로, "Instance"로 초기화했으므로 "Instance"를 출력
StaticClass()
프로그램이 돌다가 해당 함수가 호출되면, 해당 객체의 컴파일 타임 시점의 UClass*를 반환
GetClass()
마찬가지로 런타임 중 호출되면, 해당 시점에서의 객체의 UClass*를 반환
// MyCharacter.h
UCLASS()
class INTOTHEPARADOX_API AMyCharacter : public ACharacter
{
GENERATED_BODY()
protected:
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Bullet")
TSubclassOf<ABullet> BulletClass;
};
// MyCharacter.cpp
void AMyCharacter::Fire() {
ABullet* Bullet = GetWorld()->SpawnActor<ABullet>(
BulletClass,
SpawnLocation,
SpawnRotation
);
check(Bullet->StaticClass() == Bullet->GetClass())
};
캐릭터 객체에 총알 클래스를 멤버변수로 가짐
그러나 에디터 상에서 해당 멤버변수에 총알 클래스를 기반으로한 블루프린트(BP_Bullet)를 연결

그러면 Bullet의 컴파일타임 시점의 클래스는 ABullet이고, 런타임에는 블루프린트 객체인 BP_Bullet으로 연결됨
따라서 서로 다르므로 check에서 중단점이 걸림
마찬가지로, BulletClass도 컴파일 시점엔 ABullet이지만, 런타임에 블루프린트가 연결되었으므로 서로 다름
따라서 BulletClass->GetClass() == BulletClass->StaticClass()도 거짓