목표

- Custom UAsset을 생성해보자!!

최종 결과물

 

1. Custom UAsset이란?

DataTable / WidgetBlueprint / BlendSpace 등과 같은 UAsset을 만드는 것

 

2. UFactory

UFactory 클래스

* 모든 UAsset의 기본 Factory 클래스로 UAsset을 만드는 경우 Factory 클래스를 상속.

내부에 다양한 가상 함수들이 존재한다.

 

UAsset을 사용하기 위해 가장 기본적으로 Override 되어야 할 함수

- Factory Class의 생성자

Supported Class를 지정해주고, 새로 생성될 것인지 Flag를 세팅해준다.

- FactoryCreateNew

UAsset을 통해 생성하고자 하는 UObject를 Return 해준다.

 

  •  SupportedClass를 잘못 세팅하는 경우(아래의 더보기 클릭)
더보기
Factory의 잘못된 SupportedClass 세팅
Factory 구성 시 AssetTypeAction의 Support Class 체크
등록한 AssetTypeAction을 순회하면서 Factory 클래스가 Support 하는 클래스와 같은 것이 있는지 파악

 

 

 

 

 

4.24에서는 위의 세팅만으로 Category -> Miscellaneous 에 출력 되었으나

4.25로 버전이 올라가면서 자동으로 Miscellaneous에 등록되지 않는 것으로 보인다.

'프로그래밍 > 언리얼엔진' 카테고리의 다른 글

[UE4] 나만의 UAsset을 만들어보자 - 3  (0) 2020.09.11
[UE4] 나만의 UAsset을 만들어보자 - 2  (0) 2020.09.11
[UE4] Delegate  (0) 2020.03.09
[UE4] UPROPERTY 매크로  (0) 2020.03.08
[UE4] Log 남기기  (0) 2020.02.23

WRITTEN BY
KeithHong
개인 기록 공간입니다. 잘못된 정보에 대한 수정 및 조언은 항상 감사합니다 ( _ _ )

,

- Delegate

특정 객체가 해야 할 로직을 다른 객체가 대신 처리할 수 있도록 만드는 보편적인 설계의 개념

 

언리얼 Delegate

- C++ 객체에서만 사용할 수 있는 Delegate와 C++/블루프린트 객체가 모두 사용할 수 있는 Delegate로 나뉜다.

블루프린트는 멤버 함수에 대한 정보를 저장하고 로딩하는 Serialization 메커니즘이 적용되어 있다.

블루프린트와 관련된 C++ 함수는 모두 UFUNCTION 매크로를 사용해야 한다.

 

C++/블루프린트에 같이 사용할 수 있는 Delegate를 Dynamic Delegate라 한다.

 


WRITTEN BY
KeithHong
개인 기록 공간입니다. 잘못된 정보에 대한 수정 및 조언은 항상 감사합니다 ( _ _ )

,

- 언리얼 엔진에서 지정한 문법

언리얼 헤더 툴에 의해 분석되며 UPROPERTY로 선언된 변수를 분석하여 generated라는 이름의 추가 코드를 생성한다.

언리얼 헤더 툴에서 생성하는 코드는 Intermediate 폴더에 저장되며, 헤더의 내용이 변경될 때 자동 생성어 덮어쓰므로 코드를 열어 수정하는 것은 무의미하다.

 

UPROPERTY() 지정된 변수는 GC에 의한 삭제가 일어나지 않는다.

UObject는 사용하지 않으면 GC에 의해 자동 정리가 일어나는데

UPROPERTY() 지정된 변수는 변수를 담고 있는 클래스의 라이프 사이클을 따라간다.

class UTestObject

class UGameInstance
{
	UTestObject* pObject;
}

UGameInstance::UGameInstance()
{
	pObject = NewObject<UTestObject>();
}
// 위의 pObject 는 GC에 의해 사용하지 않는 타이밍에 제거됨.

 

UPROPERTY Option

Meta = (AllowPrivateAccess=true)  --> 코드상에서는 private 이지만 Editor 상에서 접근 가능하게 해주는 옵션

 

EditAnywhere 과 VisibleAnywhere??

DefaultsOnly와 InstanceOnly로 구분이 가능하다.

DefaultsOnly : 클래스의 기본값을 담당하는 블루프린트 편집 화면에서만 보인다.

InstanceOnly : 인스턴스의 속성을 보여주는 에디터 뷰포트에서만 보인다.

'프로그래밍 > 언리얼엔진' 카테고리의 다른 글

[UE4] 나만의 UAsset을 만들어보자 - 1  (0) 2020.09.10
[UE4] Delegate  (0) 2020.03.09
[UE4] Log 남기기  (0) 2020.02.23
[UE4] 비동기 로딩(RequestAsyncLoad)  (0) 2020.02.23
[UE4] 언리얼에서 EnumFlags 사용하기  (0) 2020.02.16

WRITTEN BY
KeithHong
개인 기록 공간입니다. 잘못된 정보에 대한 수정 및 조언은 항상 감사합니다 ( _ _ )

,

참고 문서

- CodeComplete2

- 읽기 좋은 코드가 좋은 코드다

- 실용주의 프로그래머

- CleanCode

 

1. 해당 함수명을 읽었을 때 무슨 역할을 하는 함수인가 기능과 이름을 일치 시키는 것.

   - CreateABC() -> CreateUI() 와 같이 해당 함수가 하는 역할을 이름만 보고 유추할 수 있을 수준으로 작명하자.

 

2. 각 함수는 하나의 작업만 진행해야 한다.

   - CalcRotation 함수내부에서 Rotation 관련 작업만 처리되어야한다. Scale, Location 등 다른 작업은 그에 맞는 함수를 만들어 작업하도록 하자.

void CalcRotation()
{
	Scale = Set(X Y Z);
    Location = Set(PrevLocation + CurLocation);
    Rotation = Set(Rotation)
}-------------------- X
// 아래와 같이 각 함수 역할에 맞는 함수를 구현
void CalcScale()
{
	Scale = Set(X Y Z);
}
void CalcLocation()
{
	Location = Set(PrevLocation + CurLocation);
}
void CalcRotaiton()
{
	Rotation = Set(Rotation);
}

3. Pair를 갖는 함수인 경우 각 Pair는 서로 동일한 클래스에 위치해야한다.

   - class A::Init() / class A::Reset() or class A::Begin() / class A::End() or class A::Play / class A::Stop() 등 Pair를 이루는 함수는 항상 같은 클래스에 선언 및 구현하자.

class A
{
public:
    void Play();
    void Stop();
    
    void Init();
    void Reset();
    
    void Begin();
    void End();
}

4. 작업하는 모든 사람이 익숙한 방식의 로직으로 설계하도록 노력하자.

   - 그 조직에서 설계된 방식에 맞춰가도록 노력하자. 나만의 로직 및 함수 네이밍을 따라가는 것은 코드를 분석하는데 곤란한 상황이 많이 연출된다.

 

5. 함수 설계 시 무슨 역할을 하는 함수인지 주석으로 우선 서술 한 뒤 그것을 Code로 변경하고, 함수의 역할이 올바르게 구현되었는지 확인하자. 

  - 내가 설계한 함수를 두번, 세번 검수하는 작업을 거치자.

1. void Add(int a , int b)
{
	// 변수 두개를 더한다.
}

2. void Add(int a, int b)
{
	// 변수 두개를 더한다.
    int result = a + b;
}

3. 정확한 명세대로 구현이 되었는가 확인한다.

6. 상속 클래스를 설계 시 가상함수로 선언 되었으나 함수 내부가 빈 case 가 있는 경우 각 클래스의 상속 관계가 올바른지 다시 한번 확인한다.

   - 빈 함수가 있다는 것은 주로 잘못된 클래스 설계에서 나타난다.

   - Ex) class 전화기

 

 class 전화기
{
	public:
    전화기();
    ~전화기();
    
    virtual void 전화하기();
    virtual void 전화끊기();
    
    virtual void 번호누르기();
    virtual void 번호지우기();
}
전화기::전화하기()
{
	//전화하기
}

class 핸드폰 : public 전화기
{
	public:
    핸드폰();
    ~핸드폰();
    
    virtual void 전화하기() override;
    virtual void 전화끊기() override;
    
    virtual void 번호누르기() override;
    virtual void 번호지우기() override;
}
핸드폰::전화하기()
{
	//전화하기
}
class 삐삐 : public 전화기
{
	public:
    삐삐();
    ~삐삐();
    
    virtual void 전화하기() override;
    virtual void 전화끊기() override;
    
    virtual void 번호누르기() override;
    virtual void 번호지우기() override;
}
삐삐::전화하기()
{}

 

'프로그래밍 > 리팩토링' 카테고리의 다른 글

리팩토링이란?  (0) 2020.02.15

WRITTEN BY
KeithHong
개인 기록 공간입니다. 잘못된 정보에 대한 수정 및 조언은 항상 감사합니다 ( _ _ )

,

------------------ 게임 Screen에 출력되는 Log

GEngine

GEngine->AddOnScreenDebugMessage(-1, 3.f, FColor::Yellow, TEXT("ACampfire BeginPlay"));

Constructor에서 GEngine을 사용하는 경우 Crash의 원인이 될 수 있으므로 사용하지 않도록 하자 혹은 Null Check 후 사용할 것

GEngine->AddOnScreenDebugMessage(-1, 3.f, FColor::Yellow, (TEXT("String = %s"), FString(“VALUE”));

GEngine->AddOnScreenDebugMessage(-1, 3.f, FColor::Red, *FString::Printf(TEXT("HELLO %f"), float));

 

UKistmetSystemLibrary::PrintString

Debug :: %s / %f 사용 예제

 

------------------ 출력창에 표시되는 Log

UE_LOG

UE_LOG(LogTemp, Log, TEXT("Base Anim BP is not available for using")); 


WRITTEN BY
KeithHong
개인 기록 공간입니다. 잘못된 정보에 대한 수정 및 조언은 항상 감사합니다 ( _ _ )

,

BP의 애셋 비동기 로드 함수

 

C++ : FSoftObjectPath를 통해 필요한 Asset을 Load하는 방법

StreamableManager의 RequestAsyncLaod 활용법 -1
StreamableHandle에 LoadedAsset에 대한 정보가 있다.


DefaultEngine.ini 에 세팅된 값에 대한 Load 요청하는 방법

 

/Script/IslandSurvivor.IS_PlayerController =>>

IslandSurvivor의 IS_PlayerController에 있는 TArray<FStringAssetRefrence>CharacterAssets 배열에 + 된 Path를 등록하는 것.

 

// 결과

'프로그래밍 > 언리얼엔진' 카테고리의 다른 글

[UE4] Delegate  (0) 2020.03.09
[UE4] UPROPERTY 매크로  (0) 2020.03.08
[UE4] Log 남기기  (0) 2020.02.23
[UE4] 언리얼에서 EnumFlags 사용하기  (0) 2020.02.16
[UE4] 가비지 콜랙터(Garbage Collector)  (0) 2020.02.15

WRITTEN BY
KeithHong
개인 기록 공간입니다. 잘못된 정보에 대한 수정 및 조언은 항상 감사합니다 ( _ _ )

,
  • EnumFlags를 사용하여 여러 옵션을 조합해서 사용하고자 할때 사용가능한 Flags

EnumFlags 로 사용하기 위한 클래스 세팅

 

Member 변수
사용 예시

 

위 테스트 코드의 결과 

 

'프로그래밍 > 언리얼엔진' 카테고리의 다른 글

[UE4] Delegate  (0) 2020.03.09
[UE4] UPROPERTY 매크로  (0) 2020.03.08
[UE4] Log 남기기  (0) 2020.02.23
[UE4] 비동기 로딩(RequestAsyncLoad)  (0) 2020.02.23
[UE4] 가비지 콜랙터(Garbage Collector)  (0) 2020.02.15

WRITTEN BY
KeithHong
개인 기록 공간입니다. 잘못된 정보에 대한 수정 및 조언은 항상 감사합니다 ( _ _ )

,

 

UpdownCasting

1. static_cast

: 형변환을 위해 사용하는 cast / C언어에서 (int) 와 비슷한 역할을 한다.

: 해당 클래스가 잘못된 캐스팅 시 유효성 검사를 하지 않는다.

: Ex)

//Upcasting과 Downcasting
CastBase* pStaticCast = new StaticCastTest(10, 0.5f, 1, "StaticCast");
CastBase* pUpCasting = static_cast<CastBase*>(pStaticCast);
StaticCastTest* pDownCasting = static_cast<StaticCastTest*>(pStaticCast);

 

//잘못된 Casting의 예 static_cast는 이와 같은 잘못된 캐스팅에 대한 처리가 없다.
CastBase* pCastBase = new CastBase(5.f, 15, "CastBase");
StaticCastTest* pDownCasting = static_cast<StaticCastTest*>(pCastBase);

CastBase* pStaticCast = new StaticCastTest(10, 0.5f, 1, "StaticCast");
DynamicCastTest* WrongCast1 = static_cast<DynamicCastTest*>(pStaticCast);

결과

쓰레기 값 및 의도하지 않은 값이 출력

 

더보기

코드 예시

쓰레기 값과 의도하지 않은 값이 출력
잘못된 캐스팅에 의해 크래시 발생 혹은 미정의 동작

 

 

2. dynamic_cast

: 형변환을 위해 사용하는 cast

: 해당 클래스가 잘못된 캐스팅을 하는 경우 nullptr 반환을 해준다.

//Upcasting과 Downcasting
CastBase* pStaticCast = new StaticCastTest(10, 0.5f, 1, "StaticCast");
CastBase* pUpCasting = dynamic_cast<CastBase*>(pStaticCast);
StaticCastTest* pDownCasting = dynamic_cast<StaticCastTest*>(pStaticCast);

 

//Dynamic 캐스팅
CastBase* pCastBase = new CastBase(5.f, 15, "CastBase");
StaticCastTest* pDownCasting = dynamic_cast<StaticCastTest*>(pCastBase);

CastBase* pStaticCast = new StaticCastTest(10, 0.5f, 1, "StaticCast");
CastBase* pUpCasting = dynamic_cast<CastBase*>(pStaticCast);

결과

잘못된 캐스팅의 경우 nullptr 반환

더보기

코드 예시

잘못된 casting에 대해 nullptr 반환

 

3. const_cast

: const로 된 변수를 const_cast를 통해 보통의 변수로 캐스팅 할 수 있다.

//ConstCast
StaticCastTest* pStaticCast = new StaticCastTest(10, 0.5f, 1, "StaticCast");
PointerTest* pTest = const_cast<PointerTest*>(pStaticCast->GetPointerTest());

 

더보기

코드 예시

const * 리턴하는 경우
이와 같이 받아서 처리하므로 값 변경이 불가능. 
const 키워드가 없으면 이와 같이 에러 발생
const_cast를 통해 이와 같이 값을 받을 수 있음.

 

4. reinterpret_cast

: 형에 상관 없이 Byte 단위의 캐스팅을 하는 reinterpret_cast.

 

 

 


WRITTEN BY
KeithHong
개인 기록 공간입니다. 잘못된 정보에 대한 수정 및 조언은 항상 감사합니다 ( _ _ )

,

#GC

 UPROPERTY 키워드가 없는 UObject의 경우 GC 에 의해 임의의 순간에 정리된다.

Garbage Collector에 의한 자동 소멸 방지

 

1. UPROPERTY 키워드를 사용하여 해당 UObject를 멤버로 참조하고 있는 UClass 가 Destroy 될 때 GC 에 의한 정리 되도록 한다.

2. GC 사용을 원치 않는 UObject class의 경우 아래의 함수를 사용하여 GC 대상에서 제외시키자.

3. UStruct는 GC에 포함되지 않는다.

  - UObjectBaseUtility::AddToRoot()
  - UObjectBaseUtility::SetFlags(EObjectFlag::RF_MarkAsRootSet)

 

UObjectBaseUtility::AddToRoot()
UPROPERTY 키워드 없는 UObject

 

 

 

GarbageCollection

 

 

 

UPROPERTY 키워드 있는 UObject

 

'프로그래밍 > 언리얼엔진' 카테고리의 다른 글

[UE4] Delegate  (0) 2020.03.09
[UE4] UPROPERTY 매크로  (0) 2020.03.08
[UE4] Log 남기기  (0) 2020.02.23
[UE4] 비동기 로딩(RequestAsyncLoad)  (0) 2020.02.23
[UE4] 언리얼에서 EnumFlags 사용하기  (0) 2020.02.16

WRITTEN BY
KeithHong
개인 기록 공간입니다. 잘못된 정보에 대한 수정 및 조언은 항상 감사합니다 ( _ _ )

,

▶What?

소프트웨어를 이해하기 쉽고, 수정하기 쉽게 만든다.

기능적으로 소프트웨어의 변경이 없다.

 

 

▶Why?

리팩토링은 소프트웨어의 디자인을 개선시킨다.

  - 사람들이 코드를 수정함에 따라 코드는 원래 의도했던 구조를 벗어나기 쉽다. 코드를 보며 원래 의도했던 디자인을 파악하는 것은 점점 더 어려워진다. 리팩토링은 적절한 곳에 있지 않는 코드를 이동 및 제거하여 코드를 정리하는 것이다.

 

리팩토링은 소프트웨어를 더 이해하기 쉽게 만든다.

  - 기계를 위한 코드가 아니라 사람을 위한 코드를 작성한다.

  - 익숙하지 않은 코드를 이해하기 위해서 리팩토링을 하면 전에 보지 못했던 디자인에 관한 것을 볼 수 있게 되며, 더 높은 수준의 이해로 이끌어준다.

 

리팩토링은 버그를 찾도록 도와준다.

  - 코드를 잘 이해하게 되면 버그를 찾기 쉽다.

 

리팩토링은 프로그램을 빨리 작성하도록 도와준다.

  - 소프트웨어의 개발 속도를 어느 정도로 유지하기 위해서는 좋은 디자인이 필수다. 리팩토링은 시스템의 디자인이 나빠지는 것을 멈추게 하여, 소프트웨어를 보다 빨리 개발 할 수 있도록 도와준다.

 

 

▶When?

기능을 추가할 때 리팩토링을 하라.

  - 추가하기 전에 수정해야 할 코드에 대한 이해를 돕는다. 한번 리팩토링을 하면, 기능을 추가하는 것은 훨씬 더 빠르고, 매끄럽다.

버그를 수정할 때 리팩토링을 하라.

  - 더 깊은 이해를 위해 리팩토링 한다.

 

  - 별도의 시간을 내서 하는 것이 아니라 '틈틈이 계속적으로' 해야하는 것.

  - 리팩토링은 목적이 아니라 수단이다.

 


WRITTEN BY
KeithHong
개인 기록 공간입니다. 잘못된 정보에 대한 수정 및 조언은 항상 감사합니다 ( _ _ )

,