카테고리 없음

언리얼 1일차

kbj1234 2024. 11. 19. 00:33

좋은 코딩 표준

1. 코딩 표준을 정해놓고 잘 따르는것

2. (프로젝트에 이미 있다면 그대로 따르자)

3. 프로젝트의 모든 코드는 한 사람이 만든 것 처럼 보여져야 함

- 언리얼 엔진은 자체적으로 코딩 표준이 정해져있다.

 ( 기존 c++ 코딩 방법을 버리고 언리얼 엔진 코딩 표준을 따라야 한다.)

 

언리얼 c++ 코딩 표준

https://dev.epicgames.com/documentation/ko-kr/unreal-engine/epic-cplusplus-coding-standard-for-unreal-engine?application_version=5.3

 

클래스 체계

클래스는 작성자보다 읽는 사람을 염두에 두고 조직되어야 한다.

읽는 사람은 대부분 클래스의 퍼블릭 인터페이스를 사용할 것이므로, 퍼블릭 인터페이스에서 먼저 선언한 후 클래스의 프라이빗 구현이 뒤따라야 한다.

ex)

class HELLOUNREAL_API UMyGameInstance : public UGameInstance
{
	GENERATED_BODY()

public:

	virtual void Init() override;

	
};

해당 코드처럼

public:

private:

를 먼저 선언해서 구분해주자

 

저작권 고지

에픽게임즈에 코드는 저작권이 있으며 임의수정하지 말자

 

명명 규칙

1. 파스칼 케이싱 : 합성어의 첫 글자를 대문자를 사용해 명명 : UnrealEngine

2. 카멜(낙타) 케이싱 : 첫 합성어는 소문자로 나머지는 대문자를 사용해 명명 : unrealEngine

3. 스네이크 케이싱 : 합성어 사이에 언더바(_)를 사용해 명명 unreal_engine

언리얼 엔진은 파스칼 케이싱을 사용한다.

 

클래스 이름

각 클래스에는 상황에따라 접두사를 포함한다.

class HELLOUNREAL_API UMyGameInstance : public UGameInstance

여기에도 클래스 네임앞에 U가 붙어있는 모습이 보인다. -> 언리얼 오브젝트를 상속받는다는 뜻

 

1. 언리얼 오브젝트(UObject)에서 상속하는 클래스에는 접두사 U를 포함한다.

2. AActor에서 상속하는 클래스에는 접두사 A를 포함한다.

3. SWidget에서 상속하는 클래스에는 접두사 S를 포함한다.

4. 추상적 인터페이스인 클래스에는 접두사 I를 포함한다.

5. 에픽의 콘셉트가 유사한 클래스 타입에는 접두사 C를 포함한다.

6. 열거형에는 접두사 E를 포함한다.

7. 부울변수에는 접두사 b를포함한다. (유일하게 대문자가 아님)

 

추가적인 코딩스타일

1. 부울형 참 거짓을 반환하는 함수는 질의형으로 이름을 정해줘야한다.

(단순명사형으로 되있으면 모호하기때문에 좋지않음)

2. 함수 파라미터가 참조로 전달된 후 함수가 그 값에 쓸것인지, 입력으로만 쓸것인지 둘다인지에 따라 접두사 In Out을 써주면 좋다. ( 너무 뻔한 코드엔 안쓰긴하지만, 신경써주면 좋다.)

 

포용적 단어 선택

- 인종, 종교 등 오해의 소지가 있는 단어는 사용하지 않을것

ex) blacklist / whitelist

 

포터블 c++ 코드

int -> int8 / int16 / int32 / int64 int형이 가지고있는 정확한 용량크기를 지정해 줘야한다.

문자열 -> 캐릭터 문자 : TCHAR

 

c++ 규약해서는 int형은 크기를 보장하지 않지만 최소크기는 32비트로 보장을 해줘야한다는 규약이있다.

 

표준 라이브러리 사용

표준라이브러리는 범용적으로 설계되어있기때문에 , 컴파일시간이나 이런 복잡도가 증가하게될수있다.

c++ 표준라이브러리는 그래서 안쓸듯

몇가지 헤더나 키워드가 겹치는 경우가 있으니, 혼합하지 않도록 주의사항유의

언리얼엔진이 따로 만든것이 많으니 그걸 써도될듯?

 

코멘트

 

 

Const 정확도

Const로 선언되는 변수는 불변하다. ( 인지하고 있을것)

변하면 안될 주요 변수는 Const선언 꼭해주자

(값이 변경되면 안되는 경우 : 루프돌때 값이 변경되면 전체 루프 데이터가 깨질 수 있다거나..)

각 요소를 돌때 엘리먼트들에 대해서 Const를 이때 지정해주자.

 

Const없는경우엔 주석을 달아주자

 

포인터 자체를 Const, 즉 포인터의 증감연산자를 사용하면 안되는걸 명시하려면 , 포인터자체에 Const를 달아주는 경우도 있다.

레퍼런스 자체는 Const의 의미를 가지고있기때문에 여기엔 Const 지정시에 오류 발생한다.

 

T* const Ptr = ...; // const 포인터에서 const 이외 오브젝트 - 포인터로의 재할당은 불가능 하지만
					   T는 여전히 수정가능

T& const Ref = ...; // 이건 틀렸음

 

포인터나 레퍼런스에 Const를 지정할때, 주의해서 지정해야한다.

예시

const TArray<FString> GetSomeArray();  - const 배열 반환(나쁨)
//레퍼런스 지정이 없어 복사가 일어날 수 있음
const TArray<FString> & GetSomeArray(); - const 배열로의 래퍼런스 반환(좋음)
//함수를 통해서 반환된 값 콘스트로 받았기때문에, 복사가 일어나지 않고 바로 사용가능
//TArray안에 있는 데이터를 고치지 않는것
const TArray<FString> * GetSomeArray(); -const 배열로의 포인터 반환(좋음)
// 포인터에 const가 선언되어있지않아 증감연산자 선언
// 포인터가 일으키는 데이터는 바뀌면 안된다.
const TArray<FString> * const GetSomeArray(); - const 배열로의 const 포인터 반환 (나쁨)

 

예시 포맷

규칙을 지정해서 코딩을 만들면, 이걸 취합해서 만들어주는 프로그램 (java doc)같은게 있음

 

최신 c++ 언어 문법

(참고해둘것) 

Override, final

 

null값은 c가아닌 nullptr을 이용해 체크를 해줘야함

 

auto 키워드 : 몇가지 예외를 제외하면 쓰지말것

 

범위 기반 for

 

람다 및 익명함수

 

강 - 타입 Enum

 

이동 시멘틱 : ( 언리얼 제공함수)MoveTemp 이거 쓰면 됨 : Stl을 안쓰기때문에 C++과의 함수와 호환이 안되서 

 

디폴트 멤버 이니셜라이저

C++ 생성자 헤더에다가 기본값을 지정하는것이 좋지만 언리얼엔진의 기본 프로젝트에선 생성자 구문에서 기본값 지정

 

서드 파티 코드 : third party라고 명시할 것

 

중괄호

if()
{
 return;
}

이렇게 확실하게 경계를 구분하는것이 좋음

 

파일 이름 : 접두사를 뺄 것

 

#pregma once : 헤더에서 중복된 헤더를 지정하지 않게 해주는 역할 ( 반드시 지정해 줄 것)

헤더에 뭔가를 선언할때, 꼼꼼하게 살펴볼것 ( include라는 구문 자체가 헤더가 가지고있는 모든 내용을 컴파일 단계에서 복사하는데, 이때 복사하는 양이 늘어남 -> 시간이 증가하는 악영향) -> 전방선언 사용 ,  가급적이면 적은 수의 헤더를 include할것

 

캡슐화

왠만하면 private으로 선언하고 getter setter로 접근할수 있게 선언하는게 좋다.

final이라는건  상속받을때 명확하게 파생시킬 클래스가 아니면 잠가주라는것을 쓰면 좋다.

 

일반적인 스타일 문제

스트링 문자열을 표현할때, TEXT() 매크로를 사용할 것

코드가 길어지더라도 보기 편하게

포인터를 선언할때

FShaderType* Ptr
// 좋은예시
FShaderType *Ptr
// 안좋음
FShaderType * Ptr
// 안좋음

명확하게, 이해할 수 있게

// SomeModule.h
static const FString GUsefulNamedString = TEXT("String");

// 헤더에 스태틱 변수를 선언하게 되는 경우엔 헤더를 참조하는 모든 인스턴스들이 컴파일 되기때문에
//따로 빼줘야한다.

// SomeModule.h
extern SOMEMODULE_API const FString GUsefulNamedString;
// SomeModule.cpp
const FString GUsefulNamedString = TEXT("String");

 

함수 파라미터가 너무 길 경우, 구조체를 사용 할 것