728x90

-TArray

Reset() : 배열의 모든 요소를 제거, 할당된 메모리는 유지, 즉 배열을 다시 채울 계획이 있어서 메모리가 재할당을 피하고 싶을때 사용

Empty() : 배열의 모든 요소를 제거, 할당된 메모리 까지 해제, 즉 배열을 더이상 사용하지 않아서 메모리 사용을 줄이고 싶을때 사용

 

-Delegate

UFUCTION() 매크로 : 델리게이트에 등록하여 사용할 함수는 UFUNCTION 매크로를 선언해주어야 한다. 이유는 언리얼에서 이 매크로를 통해 리플렉션 시스템이 해당 함수를 인식하고 등록하여 사용될수 있도록 작동하기 때문

IsBound() or IsAlreadyBound() : 언리얼에서는 델리게이트에 함수를 등록하려할때 이미 해당함수가 등록되어 있으면 에러를 발생시킨다.
언리얼에서는 기본적으로 중복 등록을 허용하지 않으며, 중복 등록으로 인한 의도하지 않은 동작, 메모리 누수와 같은 성능문제, 기타 예상치 못하는 예외 발생등을 고려하여 허용하지 않는다.

그래서 함수를 등록전에 이 함수들을 사용하여 이미 등록되어있는지 체크를 하여 등록 해줄수 있다.

RemoveAll(const void* InUserObject) or Clear() : 위 함수 델리게이트 등록전 등록 여부를 체크하는것이 아닌, 이 함수들을 사용하면 현재 델리게이트에 등록되어있는 함수들을 제거해준다.
차이점은 RemoveAll은 해당하는 객체에 등록된 모든 함수를 제거 해주는것으로 보통은  this인자로 해당 객체를 넘겨준다, Clear는 델리게이트에 등록된 모든 함수를 그냥 제거해 주는것이다.

그래서 델리게이트에 중복 등록 여부 체크를 하고 싶지 않다 하면 종료시점에 델리게이트에 등록된 함수를 제거해주는것도 하나의 방법이다.

728x90
Posted by 정망스
,
728x90

작업을 하던중 브러시 모드에서 펜툴을 이용해 내가 원하는 모양의 지오메트리를 생성했고
브러시 세팅 탭에서 브러시 셰이프를 내가 직접 만든 클래스 (ATriggerVolume 상속)로 변환해주었다.
의도는 내가 원하는 모양의 충돌 영역을 만들고 싶었던것이다.

그런데 작업을 하고 충돌 체크를 확인해보는데 아예 충돌 자체가 안되는 것이다.

찾다가 브러시 버텍스 정렬이라는 것을 보았고 이걸 한번 거친후에 다시 확인해보니 충돌이 제대로 되었다.

정확한 정보인지는 알수 없지만 내가 알아본 바로는
언리얼 엔진에서 브러시를 사용하여 TriggerVolume을 만들 때, 브러시의 버텍스(Vertex)가 제대로 정렬되지 않으면 충돌 체킹이 제대로 작동하지 않을 수 있다라는 것이다. 

브러시 버텍스 정렬을 통해  기대할수 있는 상황은 아래 3가지 정도였다

1. 정확한 지오메트리 생성: 브러시의 버텍스가 정렬되지 않으면, 브러시의 지오메트리가 왜곡되거나 비정상적으로 생성될 수 있다. 이로 인해 충돌 체킹이 제대로 작동하지 않을 수 있다.
버텍스 정렬을 통해 브러시의 지오메트리가 정확하게 생성되면, 충돌 체킹도 정상적으로 작동하게 된다.

2. 충돌 데이터 갱신: 브러시의 버텍스를 정렬하면, 언리얼 엔진은 브러시의 충돌 데이터를 갱신한다.
이 과정에서 충돌체의 경계와 폴리곤이 다시 계산되므로, 충돌 체킹이 정상적으로 작동하게 된다.

3. 브러시의 일관성 유지: 버텍스 정렬은 브러시의 일관성을 유지하는 데 도움이 된다.
일관된 브러시는 충돌 체킹과 같은 물리 연산에서 더 예측 가능하고 안정적으로 작동한다.

비슷한 상황으로 안된다면 버텍스 정렬을 해보자.

728x90
Posted by 정망스
,
728x90

언리얼에서 TFieldIterator을 사용하여 리플렉션으로 속성과 함수들의 검색이 가능하다.

멤버 변수에는 UPROPERTY, 멤버 함수에는 UFUNCTION 매크로를 지정해주어야 가능하다.

 

TFieldIterator<UProperty>타입을 사용하면 속성을 가져올수 있다.

for (TFieldIterator<UProperty> It(ClassInfo1); It; ++It)
{
    AB_LOG(Warning, TEXT("Field : %s, Type : %s"), *It->GetName(), *It->GetClass()->GetName());
    UStrProperty* StrProp = FindField<UStrProperty>(ClassInfo1, *It->GetName());
    if (StrProp)
    {
       AB_LOG(Warning, TEXT("Value = %s"), *StrProp->GetPropertyValue_InContainer(WebConnection));
    }
 }

 

TFieldIterator< UFunction >타입을 사용하면 함수을 가져올수 있다.

for ( TFieldIterator<UFunction> FunctionIterator( MyObjectsClass ); FunctionIterator; ++FunctionIterator )
{
    UFunction* Func = *FunctionIterator;
    
    UE_LOG( LogTemp, Log, TEXT( "%s" ), *FunctionIterator->GetName() ); 
}

 

함수의 경우 NativeFunctionLookupTable 배열을 사용해 현재 클래스에 어떤 함수가 있는지 알수 있다.

함수의 이름을 사용하여 FindFunctionByName함수를 사용해 가져올수 있다.

for (const auto& Entry : ClassInfo1->NativeFunctionLookupTable)
{
    AB_LOG(Warning, TEXT("Function=%s"), *Entry.Name.ToString());
 
    UFunction* Func1 = ClassInfo1->FindFunctionByName(Entry.Name);
    if (Func1->ParmsSize == 0)
    {
        WebConnection->ProcessEvent(Func1, NULL);
    }
}

 

728x90
Posted by 정망스
,
728x90

-게임 인스턴스 (컨텐츠에 관여하는 용도로 사용하기보다, 어플리케이션의 데이터를 관리하는 용도로 많이 사용)

-에셋 매니저

-게임 플레이 관련 액터 (게임모드, 게임 스테이트)

-프로젝트에 싱글톤으로 등록한 언리얼 오브젝트

728x90
Posted by 정망스
,
728x90

언리얼에서는 런타임에 빠른 타입 체킹과 클래스 검색을 위해, 컴파일 타임에서 클래스와 타입 등의 메타 정보를 생성한다.

생성한 메타정보는 UClass라는 언리얼 클래스에 보관된다. UClass에는 클래스의 계층구조, 멤버 변수, 멤버 함수에 대한 정보가 들어있다.

이러한 UClass를 사용하면 런타임에서 인스턴스의 멤버 변수값을 변경하거나 멤버 함수를 호출할수 있다.

이러한 기능은 C#에서 제공되는 리플렉션과 유사하다.

 

모든 언리얼 오브젝트의 실행 초기 런타임과정에서는 UClass 인스턴스와, 언리얼 오브젝트 인스턴스가 생성된다.

이러한 인스턴스는 언리얼 오브젝트의 기본 세팅을 지정하는데 사용되는데

이를 클래스 기본 객체 (Class Default Object) CDO라고 한다.

 

CDO를 만드는 이유는 언리얼 오브젝트를 생성할때마다 매번 초기화 시키지 않고

기본 인스턴스를 미리 만들어놓고 복제해서 사용하는 방식으로 매커니즘이 구성되어 있기 때문이라고 한다.

 

예를 들어 100명의 캐릭터를 스폰시킨다고 했을때 1명, 1명마다 생성하고, 초기화를 시키는것은 비효율적이다.

이러한 문제를 해결하기 위해 처음에 생성시킨 기본 인스턴스를 복제해서 속성만 변경하여 사용하는것이 훨씬 효율적이기 때문이다.

 

언리얼 오브젝트의 생성자 구문에는 인스턴스를 초기화해서 CDO를 제작하기 위한 용도로 사용이 된다.

즉 생성자 코드는 초기화에서만 실행이되고 이후 게임을 실제로 플레이하는 타임에서는 생성자 코드를 사용할일이 없다고 보면 된다.

게임 플레이시 사용할 초기화 함수는 생성자 대신 Init이나 BeginPlay라는 별도의 함수가 제공이 된다.

 

728x90
Posted by 정망스
,


맨 위로
홈으로 ▲위로 ▼아래로 ♥댓글쓰기 새로고침