전체 글 (93)
-
2022.05.07 [UE] Unreal C++ 스크립트 규칙
언리얼에서는 자료형을 int32 등으로 사용하게 된다. int 는 4바이트 int32 는 4바이트 int 뒤에 붙는 32 표기는 비트 정보이다 int32 는 8*4 = 32 비트 ▶ 언리얼은 PC용 게임으로만 제작되는 것이 아니기 때문에 멀티플랫폼을 지원한다. 그래서 자료형 크기를 변환할 수 있게 사용 플랫폼마다 int 크기가 다를 수 있다. (phthon) C++ 스트립트에서 데이터 경로로 블루프린트의 클래스타입 쓸 때는.. 경로 마지막에 _C 를 붙여줘야 한다. ( 블루프린트로 레퍼런스를 가지고 올 경우 _C ) ▶ 오브젝트가 아니라고 명시 EX. 레퍼런스로 가져온 경로 : AnimBlueprint'/Game/ABP_CPlayer.ABP_CPlayer' CHelpers::GetClass(&animIn..
-
2022.05.06 [C++] 함수 포인터
함수 포인터 함수의 주소값을 저장하는 포인터 (함수의 시작 주소를 가리킨다) 함수 : 프로그램(exe 파일)이 실행될 때, 우리가 소스파일에 정의한 모든 함수가 메인 메모리(프로그램이 실행되면서 할당받은 메모리)에 올라간다. 이때. 우리가 작성한 함수이름은 함수의 시작 주소를 가리키는 포인터가 되는데, 이 포인터가 가리키는 주소가 변경되면 안되니까.. 포인터 상수로 함수의 시작 주소를 가리키게 된다. 이것을 함수 포인터 라고 부른다. 포인터 상수 : const ptr 포인터를 상수로 처리했다 는 의미이다. ---> "포인터를 상수로" 라고 생각하면 쉽다. cf. 상수 포인터 : ptr 상수를 가리키는 포인터 라는 의미이다. ---> "상수를 가리키는 포인터" 라고 생각하면 쉽다. ① 함수 포인터 선언 문..
-
2022.05.02 컴퓨터와 프로그램 메모리
프로그램(exe) 메모리 프로그램을 실행하면 운영체제가 프로그램을 위한 메모리 공간을 할당한다. 우리가 하는 일은 모두 이 연속된 메모리 안에서 일어나게 된다. 프로그램의 메모리 공간은 네 개의 영역으로 나눠서 관리된다 ( 위의 이미지 ) 1. 코드 영역 : 프로그램에 작성된 코드가 저장된다. 2. 데이터 영역 : 프로그램의 글로벌 데이터들이 저장된다. 3. 힙 영역 ( 위에서부터 아래로 데이터를 쌓아간다. ) : 단, 너무 많은 동적할당을 할 경우.. 힙 데이터가 스택 영역을 침범하게 된다. 이것을 힙 오버플로우라고 한다. 4. 스택 영역 ( 아래에서 부터 위로 데이터를 쌓아간다. ) : 함수 데이터들이 차곡차곡 쌓이는 공간이다. 코드에서 각각의 함수를 호출할 때마다 지역 변수나 매개 변수, *반환 주..
-
2022.05.01 [UE] 언리얼 오브젝트와 UClass
언리얼 오브젝트 언리얼 엔진의 관리를 받는 특수한 객체 언리얼 오브젝트가 아닌, 입력에 따라 결과 값만 받고싶은 C++ 클래스도 언리얼 프로젝트에서 전혀 문제없이 쓸 수 있다. 언리얼 엔진에서는 이러한 오브젝트를 구분하기 위해 클래스에 접두어를 사용한다. - 언리얼 오브젝트 (언리얼 엔진의 관리를 받는 객체) : U로 시작. ex) UObject, UMeshComponent... - 일반 C++ 오브젝트 ( C++ 네이티브 객체) : F로 시작. ex) FName, FVector... 언리얼 오브젝트를 생성하기 위한 최상단 기본 클래스는 UObject 이다. 언리얼 오브젝트는 언리얼 엔진이 자체적으로 만들어 제공하는 프레임웍이기 때문에 언리얼 헤더 툴 ( UHT ) 이라는 프로그램의 도움을 받아야 한다...
-
2022.04.30 [UE] 리플렉션
리플렉션 프로그램이 실행시간(런타임)에 자기 자신을 조사하는 기능 ▶ 자기자신의 정보를 들여다본다. ① 런타임 우리가 코드를 짜고 빌드를 하게되면 컴파일을 하게 되는데 컴파일의 순서는 아래와 같다. 번역된 어셈블리는 우리가 미리 작성한 스크립트(소스파일) 기준으로 생성이 된다. 런타임 때( = 어셈블리가 동작할 때 )는 메서드가 호출되거나 필드의 값을 변경하는 것들이 모두 프로그래머가 빌드하기 전에 스크립트로 미리 작성해놓은 대로 실행된다. 즉, 런타임 때 동작하는 것들은 스크립트에 정의해놓은 일련의 작업일 뿐이다. --> ex. ( C++ 스타일 ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 switch( selectType ) { cas..
[UE] Unreal C++ 스크립트 규칙2022. 5. 7. 21:58
언리얼에서는 자료형을 int32 등으로 사용하게 된다.
int 는 4바이트
int32 는 4바이트
int 뒤에 붙는 32 표기는 비트 정보이다
int32 는 8*4 = 32 비트
▶
언리얼은 PC용 게임으로만 제작되는 것이 아니기 때문에 멀티플랫폼을 지원한다. 그래서 자료형 크기를 변환할 수 있게 사용 플랫폼마다 int 크기가 다를 수 있다. (phthon)
C++ 스트립트에서 데이터 경로로 블루프린트의 클래스타입 쓸 때는.. 경로 마지막에 _C 를 붙여줘야 한다.
( 블루프린트로 레퍼런스를 가지고 올 경우 _C )
▶ 오브젝트가 아니라고 명시
EX.
레퍼런스로 가져온 경로 : AnimBlueprint'/Game/ABP_CPlayer.ABP_CPlayer'
CHelpers::GetClass<UAnimInstance>(&animInstance, "AnimBlueprint'/Game/ABP_CPlayer.ABP_CPlayer_C'");
언리얼 오브젝트가 아닌, 언리얼에서 제공하는 일반 C++ 오브젝트들은 모두 ToString이라는 함수를 가지고 있다.
- 언리얼 오브젝트 : UObject, UMesh... (언리얼의 관리를 받는 오브젝트)
- 언리얼에서 제공하는 일반 C++ 오브젝트 : FVector, FRotator...
GEngine
언리얼 자체에 GEngine 객체가 있는데 많은 것을 가지고 있기 때문에 무겁다.
필요한 곳에서만 사용하는 것이 좋다.
EX.
CLog.cpp
UE_LOG 를 출력할 때 문자열 타입이 FString 일 경우 포인터로 넘겨주어야한다.
EX.
FString testStr;
UE_LOG( Category, Verbority, L"%s", *testStr);
'Engine > Unreal' 카테고리의 다른 글
[UE] USceneComponent 와 PrimitiveComponent (0) | 2022.05.09 |
---|---|
[UE] 델리게이트와 이벤트 (0) | 2022.05.09 |
[UE] 언리얼 오브젝트와 UClass (0) | 2022.05.01 |
[UE] 리플렉션 (0) | 2022.04.30 |
[UE] 자주 사용하는 언리얼 함수/변수/매크로 (0) | 2022.04.23 |
[C++] 함수 포인터2022. 5. 6. 06:10
함수 포인터
함수의 주소값을 저장하는 포인터 (함수의 시작 주소를 가리킨다)
함수 :
프로그램(exe 파일)이 실행될 때, 우리가 소스파일에 정의한 모든 함수가 메인 메모리(프로그램이 실행되면서 할당받은 메모리)에 올라간다.
이때. 우리가 작성한 함수이름은 함수의 시작 주소를 가리키는 포인터가 되는데, 이 포인터가 가리키는 주소가 변경되면 안되니까.. 포인터 상수로 함수의 시작 주소를 가리키게 된다.
이것을 함수 포인터 라고 부른다.
포인터 상수 : const ptr
포인터를 상수로 처리했다 는 의미이다. ---> "포인터를 상수로" 라고 생각하면 쉽다.
cf.
상수 포인터 : ptr
상수를 가리키는 포인터 라는 의미이다. ---> "상수를 가리키는 포인터" 라고 생각하면 쉽다.
① 함수 포인터 선언 문법
void (*FuncPtrName)(int, int)
---> 반환값과 매개변수 타입이 동일한 함수만 호출 가능
FuncPtrName : 함수 포인터의 이름
문법상 괄호와 포인터 표기는 필수!
- 괄호 :
예를 들어, int (*FuncPtrName) ( ); 에서.. 괄호는 제거하게 되면
int* FuncPtrName( ); 이렇게 된다. 이것은 int형 포인터를 반환하는 함수 의 전방선언으로 해석되기 때문에, 함수 포인터를 선언할 때는 문법상 괄호는 꼭 넣어줘야 한다.
- 포인터 :
함수 포인터도 포인터니까.. 포인터 변수 선언하듯 이름 앞에 붙여준다.
② 상수 함수 포인터 선언 문법
상수 함수 포인터 : 함수 포인터가 가리키는 주소를 변경할 수 없도록 상수화 처리한 것
void (*const FuncPtrName)(int, int);
포인터 뒤에 const 를 붙인다.
이 함수 포인터는 초기화 외에는 주소값 변경이 불가능하다.
함수 포인터 사용 ① : 기본
double Add( double left, double right )
{
return left + right ;
}
void main( )
{
// double (*FuncPtrCalc)(double, double) ---> 자체가 변수 선언이다.
// 변수 이름은 함수 포인터가 된다.
double (*FuncPtrCalc)(double, double) = NULL;
FuncPtrCalc = Add;
double value1 = FuncPtrCalc( 1.234, 3.141592 );
double value2 = GetCalcTypeValue( Add, 1.234, 3.141592 );
}
double GetCalcTypeValue( double (*InFuncPtr)(double, double), double left, double right )
{
return InFuncPtr( left, right );
}
해당 방식은 가독성이 떨어져서 잘 사용하지 않는다.
함수 포인터 사용 ② : typedef 로 일반 함수처럼 보이게 만든다
typedef double (*FuncPtrCalc)(double, double);
double Add( double left, double right )
{
return left + right ;
}
void main( )
{
FuncPtrCalc = Add;
double value1 = FuncPtrCalc( 1.234, 3.141592 );
double value2 = GetCalcTypeValue( Add, 1.234, 3.141592 );
}
double GetCalcTypeValue( FuncPtrCalc funcCalc, double left, double right )
{
return funcCalc( left, right );
}
가독성을 위해 가장 일반적으로 사용한다.
함수 포인터 사용 ③ : 가독성을 높이기 위해 C++11 에 추가된 방법
ⓐ using 을 사용한 방법
using FuncPtrCalc = double ( * )(double, double);
double Add( double left, double right )
{
return left + right ;
}
void main( )
{
FuncPtrCalc = Add;
double value1 = FuncPtrCalc( 1.234, 3.141592 );
double value2 = GetCalcTypeValue( Add, 1.234, 3.141592 );
}
double GetCalcTypeValue( FuncPtrCalc funcCalc, double left, double right )
{
return funcCalc( left, right );
}
ⓑ std::function 키워드를 사용한 방법
단, #include <functional> 을 추가해줘야 사용가능하다.
double Add( double left, double right )
{
return left + right ;
}
void main( )
{
std::function<double (double, double)> FuncPtrCalc;
FuncPtrCalc = Add;
double value1 = FuncPtrCalc( 1.234, 3.141592 );
double value2 = GetCalcTypeValue( Add, 1.234, 3.141592 );
}
double GetCalcTypeValue( std::function<double (double, double)> funcCalc, double left, double right)
{
return funcCalc( left, right );
}
'Language > C++' 카테고리의 다른 글
[C] 문자열 상수 (0) | 2022.10.23 |
---|---|
[C++] 코드 위치나 정보를 받아오는 매크로 들 (0) | 2022.05.08 |
[C++] 문법 - 범위 지정 연산자 (0) | 2022.04.01 |
C++ for_each 함수 (0) | 2018.03.21 |
wsprintf 정리 (0) | 2018.02.28 |
컴퓨터와 프로그램 메모리2022. 5. 2. 00:30
프로그램(exe) 메모리
프로그램을 실행하면 운영체제가 프로그램을 위한 메모리 공간을 할당한다.
우리가 하는 일은 모두 이 연속된 메모리 안에서 일어나게 된다.
프로그램의 메모리 공간은 네 개의 영역으로 나눠서 관리된다 ( 위의 이미지 )
1. 코드 영역 : 프로그램에 작성된 코드가 저장된다.
2. 데이터 영역 : 프로그램의 글로벌 데이터들이 저장된다.
3. 힙 영역 ( 위에서부터 아래로 데이터를 쌓아간다. ) :
단, 너무 많은 동적할당을 할 경우.. 힙 데이터가 스택 영역을 침범하게 된다. 이것을 힙 오버플로우라고 한다.
4. 스택 영역 ( 아래에서 부터 위로 데이터를 쌓아간다. ) :
함수 데이터들이 차곡차곡 쌓이는 공간이다. 코드에서 각각의 함수를 호출할 때마다 지역 변수나 매개 변수, *반환 주소 같은 것들이 쌓이게 된다.
단, 호출 스택이 너무 길어지거나.. 지역 변수를 너무 많이 만들게 되면 운영체제가 할당해준 스택 영역 범위를 벗어나게 되고. 결국 힙 영역을 침범하게 된다. 이것을 스택 오버플로우 라고 한다.
* 반환 주소 : 프로그램이 함수를 호출하고 반환하는 과정은 반환 주소를 통해 이루어진다.
그래서 함수들이 호출되는 과정을 Call Stack 이라고 부른다.
cf.
버퍼 오버플로우 : 힙 오버플로우와 스택 오버플로우를 합쳐 부르는 단어
'CS' 카테고리의 다른 글
배열 할당 : 메모리 상태 (0) | 2015.11.06 |
---|---|
메모리의 구조과 프로그램 완성과정 (0) | 2015.06.03 |
[UE] 언리얼 오브젝트와 UClass2022. 5. 1. 04:31
언리얼 오브젝트
언리얼 엔진의 관리를 받는 특수한 객체
언리얼 오브젝트가 아닌, 입력에 따라 결과 값만 받고싶은 C++ 클래스도 언리얼 프로젝트에서 전혀 문제없이 쓸 수 있다.
언리얼 엔진에서는 이러한 오브젝트를 구분하기 위해 클래스에 접두어를 사용한다.
- 언리얼 오브젝트 (언리얼 엔진의 관리를 받는 객체) : U로 시작.
ex) UObject, UMeshComponent...
- 일반 C++ 오브젝트 ( C++ 네이티브 객체) : F로 시작.
ex) FName, FVector...
언리얼 오브젝트를 생성하기 위한 최상단 기본 클래스는 UObject 이다.
언리얼 오브젝트는 언리얼 엔진이 자체적으로 만들어 제공하는 프레임웍이기 때문에
언리얼 헤더 툴 ( UHT ) 이라는 프로그램의 도움을 받아야 한다.
헤더파일에서 *클래스 선언을 언리얼 오브젝트 규격에 맞게 선언해주면 언리얼 헤더 툴 ( UHT ) 이 이를 먼저 파싱하고 분석한다.
규격에 맞지 않으면 에러를 출력하고, 규격이 맞으면 UHT 이 부가적인 메타 정보를 담은 소스코드를
프로젝트 내의 Intermediate 폴더에 메타 파일을 생성한다.
이 작업이 모두 끝나면 컴파일이 진행된다.
* 클래스 선언을 언리얼 오브젝트 규격에 맞게 선언 ▶ UCLASS( ) 매크로를 사용해서 선언해준다.
참고로 멤버 변수는 UPROPERTY( ), 멤버 함수는 UFUNCTION( ) 매크로를 지정해주면 앞으로 언리얼 엔진의 관리를 받게된다. (언리얼 오브젝트 기능을 사용할 수 있게된다)
언리얼 오브젝트가 되면 생기는 기능
1. CDO : 객체의 초기값을 자체적으로 관리한다.
2. Reflection : 객체 정보를 런타임에서 실시간 조회가 가능하다.
3. GC ( Garbage Collection ) : 참조되지 않는 객체를 메모리에서 자동으로 해제한다.
4. Serialization : 객체와 속성 정보를 통으로 안전하게 보관하고 로딩한다.
5. Delegate : 함수를 묶어서 효과적으로 관리하고 호출 가능하다.
6. Replication : 네트워크 상에서 객체 간에 동기화를 시킬 수 있다.
7. Editor Integration : 언리얼 에디터에서 값을 편집할 수 있다.
UCLASS( ) 매크로 ( 헤더파일 class 위에 선언되어 있는 것 ) ▶ 이것은 매크로 함수일 뿐...
클래스 선언 시, 언리얼 오브젝트로 사용하고 싶을 때 지정해주는 매크로
UCLASS( ) 와 *GENERATED_BODY( ) 는 짝을 이루어야 한다.
* GENERATED_BODY( ) :
리플렉션된 클래스나 구조체에 필수적. UHT 에 의해 클래스 본문에 추가적인 함수나 typedef 를 주입해준다.
UCLASS( ) 매크로는 UObject 에게 자신이 언리얼에서 기반으로 삼은 유형에 대해 설명해주는 UClass 타입을 레퍼런스로 넘겨준다. ( UHT 에 의해 )
UClass ( 클래스 타입 )
언리얼 오브젝트에 대한 클래스 계층 구조 정보 + 멤버 변수/멤버 함수 를 모두 기록한다.
CDO 를 유지한다.
UClass 타입은 StaticClass( ) 또는 GetClass( ) 함수로 가져올 수 있다. (=접근이 가능하다)
- 컴파일 단계 : StaticClass( ) ▶ UClass 타입의 정보를 얻어올 때 사용
- 런타임 단계 : GetClass( ) ▶ 실제 객체의 클래스를 조회할 때 사용
> 이 함수들은 우리가 선언한 적이 없지만 GENERATED_BODY( ) 에 의해 UHT 이 추가적인 함수를 생성해줬기 때문에 호출이 가능하다.
cf.
StaticClass 함수는 컴파일 단계에 이미 정해진 것이다.
하지만 포인터가 가리키는 실제 객체 타입은 런타임에서 달라질 수 있으므로
실제 객체의 클래스를 리턴하는 GetClass 함수의 리턴 값은 다를 수 있다.
CDO ( Class Default Object )
*실행 초기의 런타임 과정에서는 언리얼 오브젝트마다 클래스 정보와 함께 언리얼 오브젝트의 인스턴스가 생성된다. 이 특별한 인스턴스는 언리얼 오브젝트의 기본 세팅을 지정하는데에 사용된다.
이 특별한 인스턴스를 CDO 라고 한다.
*실행 초기의 런타임 과정 = 생성자
언리얼 오브젝트 클래스의 생성자는 인스턴스를 초기화해서 CDO 를 만들기 위한 목적으로 사용된다.
이 생성자 코드는 초기화에서만 실행되고 실제 게임 플레이에서 생성자 코드는 사용할 일이 없다.
언리얼 엔진에서 게임 플레이에서 사용할 초기화 함수는 Init 또는 BeginPlay 함수를 제공한다.
( → 아.. 그래서 생성자에 코드 짜고 빌드하면.. 클래스 블루프린트 열었을 때 그 내용들이 적용되어있는거구나... )
언리얼 클래스 생성자 심화 : 생성자에 매개변수를 추가할 수 있는데
UTESTObject::UTESTObject(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) 의 경우
FObjectInitializer 매개변수는 const 마킹이 되어있음에도 불구하고 내장된 mutable 함수를 통해서 프로퍼티와 서브오브젝트를 덮어쓰도록 설정할 수 있다.
그로 인해서 생성되는(덮어씌워진) UObject는 이러한 매개변수로 들어온 변경사항에 영향을 받을 것이며, 이를 사용해서 등록된 프로퍼티나 컴포넌트의 값을 변경할 수 있다.
CDO 를 만드는 이유
언리얼 오브젝트를 생성할 때마다 매번 초기화하지 않고, 기본 인스턴스( CDO ) 를 복사해서 프로퍼티만 변경하는 방식의 매커니즘으로 구성되어 있다.
( 수많은 오브젝트들이 로드가 될 경우 캐릭터를 하나씩 처음부터 생성하고 초기화시키는 것보다, 미리 큰 기본 객체 덩어리를 복제한 후 속성값만 바꾸고 로드하는 것이 훨씬 빠르기 때문이다 )
▶ CreateNewObject( ) 함수나 SpawnActor( ) 같은 함수로 생성할 경우 생성된 오브젝트에 CDO 가 복사될 것이다.
언리얼 에디터도 일종의 언리얼 어플리케이션이다보니, 사용하는 모듈이 초기화되거나 갱신된 코드로 컴파일이 진행되면 CDO 가 생성된다.
뿐만 아니라, 에디터의 플레이 버튼을 누르면 에디터와 독립된 게임을 시뮬레이션 해야하기 때문에 또 CDO 가 생성된다.
언리얼 오브젝트 로딩 과정
1. 모듈 로딩 ( 작은 퍼센트 창 뜨는 거 )
2. 모듈( 프로젝트 )에 있는 모든 UObject의 클래스 정보 등록
3. 각 클래스 정보의 CDO 인스턴스 생성
4. 언리얼 오브젝트(클래스)의 생성자를 호출해 CDO 정보를 완성
▶ 이 모든 과정이 끝나면 초기화 수치가 100% 이 된다. 이 때 비로소 에디터가 뜨게 된다.
'Engine > Unreal' 카테고리의 다른 글
[UE] USceneComponent 와 PrimitiveComponent (0) | 2022.05.09 |
---|---|
[UE] 델리게이트와 이벤트 (0) | 2022.05.09 |
[UE] Unreal C++ 스크립트 규칙 (0) | 2022.05.07 |
[UE] 리플렉션 (0) | 2022.04.30 |
[UE] 자주 사용하는 언리얼 함수/변수/매크로 (0) | 2022.04.23 |
[UE] 리플렉션2022. 4. 30. 01:13
리플렉션
프로그램이 실행시간(런타임)에 자기 자신을 조사하는 기능
▶ 자기자신의 정보를 들여다본다.
① 런타임
우리가 코드를 짜고 빌드를 하게되면 컴파일을 하게 되는데
컴파일의 순서는 아래와 같다.
번역된 어셈블리는 우리가 미리 작성한 스크립트(소스파일) 기준으로 생성이 된다.
런타임 때( = 어셈블리가 동작할 때 )는 메서드가 호출되거나 필드의 값을 변경하는 것들이 모두 프로그래머가 빌드하기 전에 스크립트로 미리 작성해놓은 대로 실행된다.
즉, 런타임 때 동작하는 것들은 스크립트에 정의해놓은 일련의 작업일 뿐이다.
--> ex. ( C++ 스타일 )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
switch( selectType )
{
case 1:
{
cout << " A 값을 " + object.a + " 값으로 변경했습니다." <<endl;
}
break;
case 2:
{
cout << " B 값을 " + object.b + " 값으로 변경했습니다." <<endl;
}
break;
case 3:
{
cout << " C 값을 " + object.c + " 값으로 변경했습니다." <<endl;
}
break;
}
|
cs |
> 이 코드는 단순히 이미 알고있는, 미리 정의된 동작만 수행한다.
(case 1, 2, 3 ---> 케이스가 추가되면 상황에 따라 프로그래머가 작성해야한다.)
하지만!! 리플렉션을 사용하게 되면 형식(Type)에 정의된 필드나 메서드를 조사해서 값을 가져오거나 설정하거나 호출할 수 있게된다.
즉, 위의 예제처럼 일일히 하나씩 미리 구현할 필요가 없어진다.
--> ex. ( C# 스타일 - 리플렉션 코드 )
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
|
// GetType() : 오브젝트의 형식(Type)을 가져온다.
// GetField() : 형식(Type) 내의 필드 정보를 조사한다.
// Where((i) => i.FieldType == typeof(int)) : int 즉, 정수 형식 필드만 사용하겠다.
var _getField = myObject.GetType()
.GetField( BindingFlags.Instance | BindingFlags.Public )
.Where( (i) => i.FieldType == typeof(int) )
.ToArray();
// Console.ReadLine() : C# 에서 콘솔 입력 받는 표준 문법
int _userInputValue = Console.ReadLine();
if ( selectType >= 1 && selectType <= _getField.Length )
{
_getField[selectType - 1].SetValue(object, _userInputValue);
Log.Debug(" {0} 값을 {1} 값으로 변경했습니다. ", _getField[selectType - 1], _userInputValue);
}
// 런타임 때
// GetType() 예제로 정보를 가져와서
// GetField() 예제로 정보를 알아내서
// SetValue() 예제로 적절히 맞춰서 사용
|
cs |
위의 예제를 참조하면
런타임 때 코드가 직접 정보를 알아내서(알 수 있어서) 적절히 맞춰서 사용할 수 있다.
▶ 리플렉션
② 리플렉션의 장점
위의 예제에서 Class에 필드가 추가되거나 제거되거나 수정이 되어도
코드 부분은 이를 반영하여 결과를 유동적으로 표시할 수 있다는 것.
언리얼의 리플렉션
1.
에디터의 디테일 패널, 시리얼라이제이션, 가비지 콜렉션, 네트워크 리플리케이션, 블루프린트와 C++의 커뮤니케이션 등 다수의 시스템에 탑재되어 있다.
리플렉션은 JAVA, C# 에서는 기본적으로 제공하는 기능이지만 C++ 에서는 제공하지 않아서 언리얼에서 자체적으로 제공하며 C++ 클래스, 구조체, 함수 멤버변수, 열거형... 등 관련 정보를 수집/질의/조작하는 별도의 시스템이 구축되어 있다.
---> 이것을 언리얼 프로퍼티 시스템 이라고도 부르며, 매크로 함수 형태로 되어있다.
cf.
에디터의 디테일 패널 :
언리얼 에디터도 일종의 언리얼 어플리케이션이다. 그래서 리플렉션을 통해 에디터가 켜져있는 중에도 컴파일이 끝나면 디테일 패널이 갱신된다.
2.
리플렉션 기능이 적용됐으면하는 유형이나 프로퍼티에 특수한 주석을 달아주면 Unreal Hear Tool ( UHT )이 그 프로젝트를 컴파일 할 때 해당 정보를 수집한다.
단, 리플렉션이 있는 유형으로 처리하려면 헤더에 특수한 include 를 해주어야 한다.
---> #include "FileName.generated.h"
* 특수한 주석 :
UCLASS( ), USTRUCT( ), UENUM( ), EFUNCTION( ), UPROPERTY( ) ....
---> 이 매크로 각각은 유형 및 멤버 선언 전에 오며, 추가적인 키워드를 담을 수 있다. (EditAnywhere 등)
----------------------------
★ 주의할 점 !!
UCLASS( )
class A:
private:
int8 MyTeamCount;
리플렉션 클래스에 네이티브 변수를 넣을 수도 있다.
단, 리플렉션된 프로퍼티가 아닌 변수는 리플렉션된 값을 그대로 저장할 경우 ( 예를 들어, UObject* 와 같은 )
가비지 콜렉터가 레퍼런스를 확인할 수 없기에 조심해야한다.
출처:
https://kyoun.tistory.com/126
https://cs-solution.tistory.com/20?category=1046133
'Engine > Unreal' 카테고리의 다른 글
[UE] USceneComponent 와 PrimitiveComponent (0) | 2022.05.09 |
---|---|
[UE] 델리게이트와 이벤트 (0) | 2022.05.09 |
[UE] Unreal C++ 스크립트 규칙 (0) | 2022.05.07 |
[UE] 언리얼 오브젝트와 UClass (0) | 2022.05.01 |
[UE] 자주 사용하는 언리얼 함수/변수/매크로 (0) | 2022.04.23 |