개발단에 가입하여 베르의 게임 개발 유튜브를 후원해주세요! 

 

베르의 게임 개발 유튜브

안녕하세요! 여러분들과 함께 게임 개발을 공부하는 베르입니다! 게임 개발에 도움이 되는 강좌들을 올리는 채널입니다! [투네이션 후원] https://toon.at/donate/637735212761460238 [유니티 어필리에이트

www.youtube.com

안녕하세요! 여러분들과 함께 게임 개발을 공부하는 베르입니다!

이번에는 언리얼 C++에서 만든 함수를 블루프린트에서 호출할 수 있게 만드는 방법을 알아봅시다!

 

사용 엔진 버전 : 5.0.2

 

타임라인

0:00 인트로

0:10 프로젝트 및 클래스 생성

0:47 함수 복습

1:35 함수를 블루프린트에서 호출할 수 있게 만들기

2:53 C++ 클래스 기반으로 블루프린트 클래스 만들기

4:09 함수를 블루프린트에서 호출하기

5:15 아웃트로

스크립트

인트로

안녕하세요. 여러분들과 함께 게임 개발을 공부하는 베르입니다.

이번에는 C++ 클래스에서 만든 함수를 블루프린트에서 호출하는 방법을 알아보도록 하겠습니다.

프로젝트 생성 및 클래스 생성

그럼 이제 언리얼 엔진에서 함수를 만들어보기 위해서 언리얼 엔진을 실행하고 새 프로젝트를 생성합니다.

카테고리는 게임으로 하고, 다른 코드 없이 완전히 비어있는 기본 템플릿을 선택하겠습니다.

그리고 프로젝트 타입을 C++로 변경한 다음 프로젝트를 생성합니다.

프로젝트가 생성되면 Actor 클래스를 상속받아서 C++ 클래스를 하나 생성합니다.

클래스의 이름은 언리얼 엔진이 기본으로 추천해주는 MyActor를 그대로 쓰도록 하겠습니다.

함수 복습

클래스가 생성되고 나면 먼저 MyActor의 헤더 파일로 이동해서 저번 영상의 복습으로 간단한 함수를 만들어 보겠습니다.

일단 bool 타입으로 키가 눌렸음을 알리는 bPressedKey 변수를 선언합니다.

그리고 InputSpaceKey 함수와 MoveUp 함수를 선언합니다.

그 다음에는 소스 파일로 이동해서 함수를 구현해줍니다.

먼저 InputSpaceKey 함수에서는 매개변수를 가져와서 bPressedKey를 설정해줍니다.

그리고 MoveUp 함수에서는 키가 눌려서 bPressedKey 변수가 true가 되었을 때 액터의 위치 값을 가져와서 상승시키도록 계산한 뒤에 다시 액터의 위치로 설정하도록 코드를 작성합니다.

함수를 블루프린트에서 호출할 수 있게 만들기

함수를 완성한 다음에는 이 함수들을 블루프린트에서 호출해서 사용할 계획입니다.

다만 이렇게 그냥 만들어진 함수들은 기본적으로 블루프린트에서 호출하려고 해도 컨텍스트 메뉴에는 보이지 않습니다.

그럼 이제 C++ 클래스에서 직접 만든 함수들을 블루프린트 클래스에서 호출할 수 있도록 만들어 보겠습니다.

언리얼 C++ 변수 영상에서 프로퍼티를 언리얼 에디터에서 볼 수 있게 하기 위해서 UPROPERTY 매크로를 사용한 것을 기억할 겁니다.

그와 대응되는 기능으로 함수에서는 UFUNCTION 매크로를 사용하면 함수를 블루프린트에서 사용할 수 있게 설정하는 등의 기능을 지정자로 넣을 수 있습니다.

함수들에 UFUNCTION 매크로를 추가해주고 지정자는 BlueprintCallable과 Category="Move"로 입력하겠습니다.

UFUNCTION 매크로에서 BlueprintCallable 지정자를 넣어주면 해당 함수를 블루프린트에서 사용할 수 있게 됩니다.

그리고 블루프린트에서 사용할 모든 함수에는 카테고리를 할당해줘야만 정상적으로 호출 할 수 있게 됩니다.

그렇기 때문에 함수를 블루프린트에서 사용하려면 UFUNCTION 매크로에 반드시 카테고리 지정자를 넣어줘야 합니다.

UFUNCTION 매크로를 모두 작성하면 저장하고 언리얼 에디터로 돌아가서 명령 콘솔 창에 LiveCoding.Complie을 입력해서 수정 사항을 컴파일 해줍니다.

C++ 클래스 기반으로 블루프린트 클래스 만들기

그 다음에는 만든 함수가 블루프린트에 잘 호출되는지 확인하기 위해서 MyActor 클래스를 기반으로 블루프린트 클래스를 만들어야 합니다.

콘텐츠 브라우저에서 MyActor C++ 클래스 에셋을 우클릭하고 [MyActor 기반 블루프린트 클래스 생성]을 선택하면 블루프린트 클래스 추가 창이 뜹니다.

블루프린트 클래스의 이름을 BP_MyActor로 입력한 다음 블루프린트 클래스 생성 버튼을 누릅니다.

블루프린트 클래스가 생성되고 나면 생성된 블루프린트 클래스를 대상으로 블루프린트 에디터가 열립니다.

그 다음에는 이 액터가 키 입력을 받아서 움직이는 것을 잘 보이게 만들기 위해서 컴포넌트 패널의 [추가] 버튼을 누르고 Sphere 컴포넌트를 찾아서 추가해줍니다.

그리고 추가된 Sphere 컴포넌트를 DefaultSceneRoot에 드래그&드롭해서 루트 컴포넌트로 만들어 줍니다.

그리고 Sphere 컴포넌트를 선택하고 디테일 패널의 피직스 카테고리에서 피직스 시뮬레이트에 체크해줍니다.

블루프린트 세팅의 마지막 과정으로는 이 액터가 입력을 받을 수 있도록 설정할 차례입니다.

블루프린트 에디터에서 이벤트 그래프 패널로 이동합니다.

그 다음에는 Begin play 이벤트 근처의 그래프 빈 영역에 우클릭하고 컨텍스트 메뉴에서 Get Player Controller와 Enable Input 함수를 찾아서 노드를 배치해줍니다.

그리고 Begin Play 이벤트 노드와 연결해줍니다.

이렇게 하면 이 액터가 입력을 받을 수 있도록 설정됩니다.

함수를 블루프린트에서 호출하기

기본 세팅을 끝냈으니 이제 앞에서 만든 함수들을 블루프린트에서 호출해볼 차례입니다.

그래프의 빈 영역에 우클릭하고 컨텍스트 메뉴에서 스페이스 바 이벤트를 찾아서 추가해줍니다.

그 다음에 다시 빈 영역에 우클릭하고 컨텍스트 메뉴를 살펴보면 Move 카테고리에 우리가 만든 함수를 찾을 수 있습니다.

먼저 InputSpaceKey 함수 노드를 두 개 추가하고 각각 Pressed 핀과 Released 핀에 연결해줍니다.

그리고 Pressed 핀에 연결된 노드에는 Pressed가 true가 되게 체크해줍니다.

그 다음에는 MoveUp 함수 노드를 추가하고 틱 이벤트와 연결해줍니다.

블루프린트 작성이 모두 끝난 다음에는 블루프린트 에디터의 컴파일 버튼과 저장 버튼을 차례대로 누른 뒤 블루프린트 에디터를 닫아줍니다.

그 다음에는 테스트를 위해서 BP_MyActor를 레벨에 배치하고 게임을 플레이시켜줍니다.

이제 스페이스 바를 누르면 액터가 떠오르고 손을 떼면 다시 중력의 영향을 받아 떨어지는 모습을 볼 수 있습니다.

이런 방식으로 프로그래머가 블루프린트에서 호출할 수 있게 핵심 기능을 가진 함수를 만들면 디자이너는 블루프린트에서 함수를 조합해서 게임 기능을 만들면 됩니다.

아웃트로

이번 영상에서는 C++에서 만든 함수를 블루프린트에서 호출하는 방법에 대해서 알아보았습니다.

이 강좌는 시청자 여러분들의 시청과 후원으로 제작되었습니다.

이상 베르의 게임 개발 유튜브였습니다. 감사합니다.

 

[투네이션]

 

-

 

toon.at

[Patreon]

 

WER's GAME DEVELOP CHANNEL님이 Game making class videos 창작 중 | Patreon

WER's GAME DEVELOP CHANNEL의 후원자가 되어보세요. 아티스트와 크리에이터를 위한 세계 최대의 멤버십 플랫폼에서 멤버십 전용 콘텐츠와 체험을 즐길 수 있습니다.

www.patreon.com

[디스코드 채널]

 

Join the 베르의 게임 개발 채널 Discord Server!

Check out the 베르의 게임 개발 채널 community on Discord - hang out with 399 other members and enjoy free voice and text chat.

discord.com

 

반응형

개발단에 가입하여 베르의 게임 개발 유튜브를 후원해주세요!

 

베르의 게임 개발 유튜브

안녕하세요! 여러분들과 함께 게임 개발을 공부하는 베르입니다! 게임 개발에 도움이 되는 강좌들을 올리는 채널입니다! [투네이션 후원] https://toon.at/donate/637735212761460238 [유니티 어필리에이트

www.youtube.com

 

안녕하세요! 여러분들과 함께 게임 개발을 공부하는 베르입니다!

이번에는 프로그래밍의 함수에 대해서 알아보고 언리얼 프로그래밍에서 함수를 만들고 사용하는 방법을 배워봅시다.

 

사용 엔진 버전 : 5.0.1

 

타임라인

0:00 인트로

0:12 함수란?

2:05 프로젝트 및 클래스 생성

2:39 변수 선언

3:36 함수 선언 및 구현

4:29 함수 만들어보기

5:15 함수 호출하기

7:52 아웃트로

스크립트

인트로

안녕하세요. 여러분들과 함께 게임 개발을 공부하는 베르입니다.

이번 영상에서는 함수의 기본적인 내용과 함께 언리얼 프로그래밍에서 함수를 만들고 호출하는 방법을 알아보도록 합시다.

함수란?

프로그래밍에서 함수는 일정한 동작을 수행하는 코드들을 묶어놓은 것을 이야기하며 이 함수는 반환형, 이름, 매개변수, 몸체를 가집니다.

차례대로 살펴보자면 먼저 반환형은 이 함수가 모든 과정을 수행하고 나서 어떤 타입의 결과값을 돌려주는지 알려주는 부분입니다.

반환형이 int로 되어있다면 이 함수가 모든 동작을 끝내고나서 돌려줄 결과 값의 타입이 정수형이라는 뜻입니다.

언리얼 프로그래밍에서 사용되는 모든 자료형은 반환형으로 사용할 수 있습니다.

또한 함수가 동작을 끝내고 나서 결과값을 돌려줄 필요가 없다면 void라는 타입으로 결과값을 돌려주지 않을 것임을 알려줄 수도 있습니다.

그리고 함수 이름은 이 함수를 호출하는데 사용되는 것으로 개발자가 원하는 대로 이름을 지어주면 됩니다.

다만 함수의 이름을 지을 때는 이 함수가 어떤 작업을 하는 함수인지 이름만 보고도 알 수 있게 하는 것이 좋습니다.

매개변수 부분은 괄호로 묶여있는데 이 부분을 통해서 함수가 동작하는데 필요한 변수를 함수 외부에서 받아와서 함수 내부에서 사용할 수 있게 됩니다.

이렇게 매개변수 괄호가 비어있을 때는 함수에 필요한 외부 변수가 없다는 뜻이 됩니다.

외부에서 변수를 받아와서 사용할 필요가 있을 때는 이렇게 매개변수의 타입과 이름을 넣어주면 됩니다.

만약 여러 개의 매개변수가 필요하다면 끝에 쉼표를 찍고 다음 매개변수의 타입과 이름을 적어주면 됩니다.

마지막으로 함수의 몸체는 이 함수가 실제로 해야할 일을 처리하는 코드를 작성하는 부분입니다.

예를 들어 캐릭터를 원하는 위치로 이동시키는 함수를 구현한다고 가정하면 반환형으로는 남은 거리를 돌려주기 위해서 float으로 하고 함수 이름은 Move로 정하게 될겁니다.

그리고 매개변수는 목적지의 좌표를 받게 되겠죠.

그 다음 함수의 몸체에서는 함수가 호출될 때마다 목적지를 향해서 캐릭터의 이동속도와 시간을 이용해서 조금씩 이동시키고 남은 거리를 반환하는 코드를 작성하게 될 겁니다.

이렇게 프로그래밍에서 함수는 어떠한 작업을 하나의 묶음으로 만들어서 필요할 때마다 재사용할 수 있게 되는데, 작업 효율을 위해서는 필요한 기능 별로 함수를 잘 만들어서 사용해야 합니다.

프로젝트 생성 및 클래스 생성

그럼 이제 언리얼 엔진에서 함수를 만들어보기 위해서 언리얼 엔진을 실행하고 새 프로젝트를 생성합니다.

카테고리는 게임으로 하고, 다른 코드 없이 완전히 비어있는 기본 템플릿을 선택하겠습니다.

그리고 프로젝트 타입을 C++로 변경한 다음 프로젝트를 생성합니다.

프로젝트가 생성되면 지난 영상인 언리얼 프로그래밍 입문 1편에서 배운 것처럼 Actor 클래스를 상속받아서 C++ 클래스를 하나 생성합니다.

클래스의 이름은 언리얼 엔진이 기본으로 추천해주는 MyActor를 그대로 쓰도록 하겠습니다.

변수 선언

클래스 생성이 끝나고 나면 헤더 파일로 가서 몇 가지 변수를 선언해주겠습니다.

int32 타입으로 TotalDamage를 선언하고 UPROPERTY 매크로를 붙여준 뒤 지정자로 EditAnywhere, BlueprintReadWrite, Category=”Damage”를 넣어줍니다.

그리고 float 타입으로 DamageTimeInSeconds와 DamagePerSecond 변수를 선언하고 UPROPERTY 매크로 붙여주되 DamageTimeInSeconds에는 TotalDamage 변수와 같은 지정자를 넣어주고 DamagePerSecond에는 지정자로 BlueprintReadOnly, VisibleAnywhere, Transient, Category="Damage”를 넣어줍니다.

그리고 생성자 함수로 가서 간단하게 변수들의 기본값을 지정해줍니다.

하지만 이중에서 DamagePerSecond 프로퍼티는 기본값을 넣지 않고 그냥 놔두겠습니다.

함수 선언 및 구현

그 다음 클래스에 함수를 만들기 위해서는 두 단계의 과정을 거쳐야 합니다.

바로 함수 선언과 구현입니다.

자세하게 설명해보자면 우선 헤더 파일에서 이 클래스에 새로 생성할 함수의 원래 형태, 즉 원형을 적어서 알려야 합니다.

이것을 함수의 선언이라고 합니다.

다시 말해서 함수 원형 선언은 이 클래스에 이런 함수가 있음을 알리는 것으로 함수의 반환형, 이름, 매개변수까지만 적고 세미콜론을 찍어주면 됩니다.

그리고 소스 파일로 가서 함수를 구현해야 합니다.

함수를 구현할 때는 반환형과 이 함수를 소유하고 있는 클래스의 이름을 적은 뒤 콜론을 두 개 찍어주고 함수 이름을 적습니다.

그리고 매개변수를 적은 뒤 중괄호를 열어서 함수의 몸체를 만들고 이 몸체 안에 실제 함수가 동작할 코드를 작성해야 합니다.

함수 만들어보기

그럼 이제 간단한 함수를 만들어 봅시다.

우선 앞에서 변수들에 기본 값을 넣어주면서 DamagePerSecond는 제외한 것을 기억할 겁니다.

TotalDamage 변수와 DamageTimeInSeconds 변수를 이용해서 이 DamagePerSecond 변수의 값을 바꿔주는 함수를 만들어 보겠습니다.

헤더 파일에서 CalculateDPS라는 이름으로 함수의 원형을 선언합니다.

함수의 원형을 완성하고 나면 소스 파일로 이동해서 함수를 실제로 구현해야 합니다.

소스 파일에서는 앞에서 한 번 이야기한 것처럼 반환형, 클래스 이름, 함수 이름, 괄호와 매개변수를 입력하고 중괄호로 함수의 몸체를 만들어주면 됩니다.

함수의 내용에는 TotalDamage를 DamageTimeInSeconds로 나눠서 DamagePerSecond 변수에 넣어주도록 코드를 작성합니다.

함수 호출하기

이렇게 함수를 작성하고 나면 이 함수가 특정한 시점에 자동으로 호출되게 해주겠습니다.

그 시점으로 알맞은 것은 TotalDamage나 DamageTimeInSeconds와 같은 변수가 초기화되거나 변경될 때 일 겁니다.

언리얼 엔진에서 오브젝트의 변수가 초기화될 때 호출되는 함수는 PostInitProperties이고 변수가 수정될 때 호출되는 함수는 PostEditChangeProperty입니다.

AMyActor의 헤더 파일로 가서 두 함수의 원형을 작성합니다.

이 두 함수는 AMyActor의 부모 클래스인 AActor에서 상속받는 함수이기 때문에 부모 클래스의 함수를 자식 클래스인 AMyActor에서 덮어쓴다는 의미로 virtual 키워드와 override 키워드를 사용해줘야 합니다.

이렇게 두 함수의 원형을 선언하고 나면 다시 소스 파일로 가서 함수를 구현해야 하는데 아까 전의 CalculateDPS 함수처럼 직접 작성할 수도 있지만, 초록색 밑줄이 그어진 함수 이름에 커서를 두고 [Ctrl + .] 단축키를 누르고 [PostInitProperties에서 'AMyActor.cpp' 정의 만들기]를 선택하면 빈 함수의 구현을 스크립트 에디터가 자동으로 해줍니다.

PostInitProperties 함수의 내용은 간단하게 Super::PostInitProperties 함수를 호출한 다음에 CalculateDPS 함수를 호출하게 만들어 줍니다.

참고로 언리얼 C++에서 Super 키워드는 클래스가 상속받은 부모 클래스에 있는 원본 프로퍼티나 함수를 가져오는데 사용되는 키워드입니다.

AMyActor에 override로 선언한 PostInitProperties 함수는 부모 클래스인 AActor 클래스의 PostInitProperties를 덮어씌워서 만든 것이기 때문에 이렇게 AMyActor에서 만든 PostInitProperties 함수에서 부모 클래스의 PostInitProperties를 다시 호출해주지 않으면 부모 클래스의 PostInitProperties에서 실제로 처리하는 작업이 실행되지 않아서 문제가 발생할 수도 있습니다.

그래서 이렇게 부모 클래스의 함수를 덮어씌워서 만드는 경우에는 Super 키워드를 이용해서 부모 클래스의 원본 함수를 한 번 실행시켜주는 것이 좋습니다.

PostInitProperties 함수를 모두 작성하고 나면 PostEditChangeProperty 함수도 역시 똑같이 작성해줍니다.

다만 PostEditChangeProperty 함수에서는 원본 PostEditChangeProperty 함수보다 CalculateDPS 함수를 먼저 호출해주도록 작성하겠습니다.

코드를 모두 작성하면 변경사항을 저장하고 에디터로 돌아가서 [Ctrl + Alt + F11] 단축키를 이용해 수정사항을 컴파일 해줍니다.

코드가 컴파일되고 나서 MyActor 클래스를 레벨에 배치해보면 디테일 패널에서 DamagePerSecond의 값이 계산되어 표시되는 것을 볼 수 있습니다.

그리고 TotalDamage 프로퍼티와 DamageTimeInSeconds 프로퍼티의 값을 변경하면 DamagePerSecond의 값도 곧바로 변경되는 것을 볼 수 있습니다.

아웃트로

이번 영상에서는 함수가 무엇인지 배우고 언리얼 프로그래밍에서 함수를 만들고 사용하는 방법을 알아보았습니다.

이 강좌는 시청자 여러분들의 시청과 후원으로 제작되었습니다.

이상 베르의 게임 개발 유튜브였습니다. 감사합니다.

 

[투네이션]

 

-

 

toon.at

[Patreon]

 

WER's GAME DEVELOP CHANNEL님이 Game making class videos 창작 중 | Patreon

WER's GAME DEVELOP CHANNEL의 후원자가 되어보세요. 아티스트와 크리에이터를 위한 세계 최대의 멤버십 플랫폼에서 멤버십 전용 콘텐츠와 체험을 즐길 수 있습니다.

www.patreon.com

[디스코드 채널]

 

Join the 베르의 게임 개발 채널 Discord Server!

Check out the 베르의 게임 개발 채널 community on Discord - hang out with 399 other members and enjoy free voice and text chat.

discord.com

 

반응형

개발단에 가입하여 베르의 게임 개발 유튜브를 후원해주세요!

 

베르의 게임 개발 유튜브

안녕하세요! 여러분들과 함께 게임 개발을 공부하는 베르입니다! 게임 개발에 도움이 되는 강좌들을 올리는 채널입니다! [투네이션 후원] https://toon.at/donate/637735212761460238 [유니티 어필리에이트

www.youtube.com

안녕하세요! 여러분들과 함께 게임 개발을 공부하는 베르입니다!

이번에는 언리얼 엔진 5의 기본 변수와 UPROPERTY에 대해서 알아봅시다.

 

사용 엔진 버전 : 5.0.1

 

타임라인

0:00 인트로

0:12 변수란?

0:55 프로젝트와 클래스 생성

1:36 변수 선언 방법

2:35 변수 종류

6:59 변수 선언 해보기

7:21 변수 공개 범위

8:45 변수를 에디터에서 보이게 만들기

11:46 변수의 기본 값 설정하기

13:03 아웃트로

스크립트

인트로

안녕하세요. 여러분들과 함께 게임 개발을 공부하는 베르입니다.

이번 영상에서는 프로그래밍에서 사용되는 기본적인 변수와 언리얼 프로그래밍의 특징인 UPROPERTY에 대해서 알아보도록 합시다.

변수란?

먼저 프로그래밍에서의 변수란 간단하게 예를 들어 게임에서 캐릭터의 체력, 공격력, 공격속도와 같은 값과 상태를 저장하기 위한 것입니다.

게임이나 프로그램에 필요한 여러 종류의 값들을 담아두는 것이죠.

그리고 일반적인 프로그래밍 언어에서는 담을 수 있는 값의 종류에 따라 변수 타입이 나누어져있습니다.

가장 기본적인 변수의 종류에는 0, 1, 2, 3과 같은 일반 정수, 3.14, 1.5와 같은 소수, "Hello!", "Hi" 같은 문자열, 그리고 참과 거짓을 표현되는 논리 변수가 있습니다.

물론 이외에도 언리얼 엔진에서 제공하는 여러 클래스도 있고 다른 변수들을 묶음으로 다룰 수 있는 컨테이너들 역시 변수로 사용되지만 이번 영상에서는 제일 기본이 되는 변수를 먼저 다뤄보겠습니다.

프로젝트와 클래스 생성

그럼 먼저 언리얼 엔진을 실행하고 새 프로젝트를 생성해보겠습니다.

카테고리는 게임으로 하고, 다른 코드 없이 완전히 비어있는 기본 템플릿을 선택하겠습니다.

그리고 프로젝트 타입을 C++로 변경한 다음 프로젝트를 생성합니다.

프로젝트가 생성되면 지난 영상인 언리얼 프로그래밍 입문 1편에서 배운 것처럼 Actor 클래스를 상속받아서 C++ 클래스를 하나 생성합니다.

클래스의 이름은 언리얼 엔진이 기본으로 추천해주는 MyActor를 그대로 쓰도록 하겠습니다.

변수 선언 방법

C++ 클래스를 생성하고 나면 먼저 그 클래스의 .cpp 파일이 열릴텐데 클래스의 오브젝트가 소유하고 있는 변수, 즉 멤버변수를 만들기 위해서는 클래스의 .h 파일, 즉 헤더 파일에서 선언해주어야 합니다.

새로 만든 MyActor의 헤더 파일인 MyActor.h로 이동합니다.

우선 언리얼 엔진의 C++ 클래스에서 변수를 만들고 사용하기 위해서는 변수를 만들 클래스의 헤더 파일에서 이렇게 변수의 타입과 그 변수를 인식하기 위한 이름을 적어주면 됩니다.

일반 C++ 프로그래밍에서는 이렇게 변수 타입과 변수 이름을 선언하는 것으로 변수 선언이 끝납니다.

여기에 더해서 언리얼 C++ 프로그래밍에서는 이 변수 값을 에디터에서 사용하기 위해서 UPROPERTY라는 매크로를 붙이게 됩니다.

이게 대부분의 언리얼 프로그래밍에서 사용되는 변수의 기본형입니다.

이 UPROPERTY 매크로는 프로퍼티가 언리얼 엔진 및 에디터에 이러한 프로퍼티가 있음을 알리고, 프로퍼티가 엔진과 연결되었을 때 어떻게 작동할지를 지정하기 위한 것입니다.

UPROPERTY 매크로에 넣을 수 있는 지정자는 나중에 총 정리하는 시간을 가져보겠습니다.

변수 타입

이제 앞에서 이야기한 기본적인 변수 타입을 좀 더 자세히 알아봅시다.

앞에서 언급했듯이 기본 변수 타입으로는 정수, 소수, 문자열, 논리변수가 있습니다.

각 변수 타입에 대해서 다시 한 번 천천히 풀어서 설명해보겠습니다.

정수

먼저 정수는 0, 1, 2, 3과 같은 일반 숫자를 표현하는데 쓰이는 타입입니다.

어느 정도 C++를 배워보신 분들은 정수 타입을 이야기하면 제일 먼저 떠올릴 타입은 short, int, long일 겁니다.

하지만 이런 기본 타입은 플랫폼마다 길이가 달라질 수 있기 때문에 언리얼 엔진에서는 길이가 고정되어 있는 타입으로 int8, int16, int32, int64를 제공합니다.

int 뒤에 붙어있는 숫자는 정수를 표현하는데 몇 개의 bit를 사용할 것인지를 의미합니다.

int8은 정수를 표현하는데 8개의 bit를 사용해서 127 ~ -128까지 숫자를 표현할 수 있고, int16은 16개의 bit를 사용해서 32,767 ~ -32,768까지 표현할 수 있습니다.

그리고 int32는 32개의 bit로 21억 4648만 647 ~ -21억 4648만 648까지 표현하고 int64는 64개의 bit로 무려 922경 3372조 0368억 5477만 5807 ~ -922경 3372조 0368억 5477만 5808까지 표현할 수 있습니다.

그리고 만약 해당 변수가 숫자를 음수로 표현할 필요가 없다면 각 타입 이름 앞에 u를 붙여서 uint8, uint16, uint32, uint64로 사용하면 모든 비트를 양수를 표현하는데 사용해서 앞에서 이야기한 각 수가 표현 가능한 최대수의 2배만큼 표현 범위가 넓어집니다.

uint8은 0 ~ 255, uint16은 0 ~ 65535, uint32는 0 ~ 42억 9496만 7295, uint64는 0 ~ 1844경 6744조 0737억 0955만 1615까지 표현할 수 있게 됩니다.

정수 타입을 사용할 때는 필요한 숫자의 범위를 잘 생각해서 어느 타입을 사용할지를 결정하면 됩니다.

만약 127 ~ -128 범위의 숫자가 사용될 것이라고 생각하고 int8 타입을 사용했는데 그 예상을 벗어나서 127에 1이 더해지면 -128이 되고 -128에서 1을 빼버리면 127이 되버리는 문제가 발생합니다.

이걸 프로그래밍에서는 오버플로우와 언더플로우라고 부릅니다.

가끔 몇몇 게임에서 아이템이나 돈을 열심히 모았는데 어느 순간 갑자기 0이나 마이너스가 되버리는 문제를 볼 수 있는데 그게 바로 이것 때문에 발생하는 겁니다.

물론 이런 현상을 막기 위해서 그냥 int64를 사용하면 되지 않겠나하고 생각하겠지만 int8에서 한 단계씩 올라갈 때마다 사용되는 메모리가 2배씩 늘어나기 때문에 게임의 최적화를 위해서는 적절한 범위의 타입을 사용하고 그 범위를 넘어갈 가능성을 배제할 수 없다면 예외처리를 통해서 그 숫자의 범위를 벗어나지 못하도록 예방을 하는게 좋습니다.

소수

그 다음은 0.1, 3.14, 1.5와 같은 소수를 표현하는 타입입니다.

소수를 표현하는 타입으로는 일반 C++와 똑같이 float과 double이 있습니다.

float은 32비트이며 double은 64비트 크기입니다.

보통 float은 소수점 5자리까지의 정밀도를 가지고 double은 그 두 배인 10자리까지의 정밀도를 가집니다.

게임을 만들 때는 보통 float을 사용하고 더욱 정밀한 소수 표현이 필요할 때만 double을 사용하면 됩니다.

문자열

그리고 문자열입니다.

문자열은 말그대로 문자의 집합을 의미합니다.

보통 C++에서는 std::string을 사용하고 유니티에서 자주 사용되는 C#에서는 string 클래스를 사용하지만 언리얼 C++에서는 필요에 따라서 여러가지 클래스로 문자열을 제공합니다.

가장 기본 타입은 FString 타입입니다.

저장되는 글자의 길이에 따라서 변수의 길이가 자동으로 달라지는 타입으로 기본 C++의 std::string과 유사하게 동작합니다.

보통 std::string이나 C#의 string에서는 문자열 변수에 바로 문자열을 넣을 때는 쌍따옴표("")를 사용해서 상수 문자열을 만들어서 넣지만, FString에서는 TEXT()매크로를 사용해야 합니다.

이 외에도 현지화 텍스트를 위해서 사용하는 FText나 자주 사용되는 문자열을 식별자로 지정해서 문자열을 비교할 때 소모되는 메모리와 CPU 시간을 절약하는데 쓰이는 FName, 플랫폼마다 다를 수 있는 문자열 세트와 상관없이 문자열을 저장하는 용도로 사용되는 TCHAR가 있습니다.

FString을 제외한 타입은 나중에 필요한 경우가 생기거나 언리얼 문자열 관련 영상에서 다뤄보도록 하겠습니다.

논리변수

그리고 마지막으로 true 혹은 false 값만 가지는 논리 변수는 bool이라는 타입으로 선언할 수 있습니다.

변수 선언 해보기

그럼 이제 방금 배운 타입으로 몇 가지 프로퍼티를 선언해보겠습니다.

int32 타입으로 TotalDamage, float 타입으로 DamageTimeInSeconds와 DamagePerSecond, FString 타입으로 CharacterName, bool 타입으로 bAttackable 프로퍼티를 만듭니다.

변수 공개 범위

그리고 변수의 공개 범위를 지정하는 방법을 알려드리겠습니다.

변수의 공개 범위란 이 클래스에 속한 변수를 클래스 외부에서 접근할 수 있게 모두에게 보여줄건지, 아니면 이 클래스를 상속받은 자식 클래스에게만 보여줄건지, 그도 아니면 아무에게도 안보여주고 이 클래스 내부에서만 사용할 것인지를 이야기하는 것입니다.

클래스 외부의 모두에게 보여주는 것은 public,

클래스를 상속받은 자식 클래스에게만 보여주는 것은 protected,

외부에는 보여주지 않고 클래스 내부에서만 사용하는 것은 private입니다.

이 공개 범위는 함수에서도 똑같이 동작합니다.

참고로 유니티로 C#을 배우신 분들은 공개 범위를 지정할 때 이렇게 변수 이름 앞에 직접 private, protected, public을 붙여서 사용했을 겁니다.

하지만 C++에서는 이렇게 앞쪽에 따로 적어주고 끝에는 콜론을 달아줘야 합니다.

이렇게 접근지정자를 적어주면 접근지정자의 콜론에서부터 다음 지정자가 등장할 때까지 해당 지정자의 공개 범위를 가지게 됩니다.

즉 여기서부터 여기까지있는 변수와 함수는 public이 되고, BeginPlay 함수는 protect, Tick 함수는 다시 public이 되는 겁니다.

그리고 변수들 중간에 private 접근 지정자를 넣어주면 여기서부터 여기까지는 private이 되서 클래스 외부에서는 접근할 수 없게 됩니다.

참고로 유니티 C#에서는 변수를 public으로 지정하면 유니티 에디터의 인스펙터 뷰, 언리얼로 치면 언리얼 에디터의 디테일 패널에서 공개가 될텐데, 언리얼 엔진에서는 스크립트에서 변수를 public으로 지정한다고 해서 디테일 패널에서 공개되지 않습니다.

변수를 에디터에서 보이게 만들기

그럼 이어서 선언한 변수를 언리얼 에디터에서 보이게 만드는 방법을 알아봅시다.

먼저 각 변수마다 앞에 UPROPERTY 매크로를 붙여주도록 합시다.

UPROPERTY 매크로는 앞에서도 말했다시피 언리얼 엔진 및 에디터에 이러한 프로퍼티가 있음을 알리고, 연결되었을 때 어떻게 작동할지를 지정하기 위한 것입니다.

우선 이렇게 UPROPERTY 매크로가 비어있는 상태에서는 언리얼 에디터에서 프로퍼티가 보이지 않을 겁니다.

프로퍼티가 에디터에서 보이게 만들기 위해서는 UPROPERTY 매크로에 필요한 지정자를 넣어줘야합니다.

UPROPERTY 매크로의 지정자는 많은 종류가 있지만 우선 가장 기본이 되는 것부터 사용해보겠습니다.

TotalDamage의 UPROPERTY 매크로에 EditAnywhere, BlueprintReadWrite, Category="Damage"를 추가합니다.

각 지정자의 의미를 설명하자면 EditAnywhere은 아키타입(archytype)과 레벨에 배치된 인스턴스 양 쪽 모두의 프로퍼티 창에서 편집할 수 있음을 의미합니다.

참고로 아키타입은 아직 인스턴스화되지 않은 블루프린트의 원본을 의미합니다.

BlueprintReadWrite는 이 프로퍼티를 블루프린트에서 읽기와 쓰기가 모두 가능하다는 뜻입니다.

그리고 Category="Damage"는 블루프린트 편집 툴이나 디테일 패널에서 이 프로퍼티를 Damage라는 카테고리로 묶어서 보여준다는 뜻입니다.

밀접한 관계를 가진 프로퍼티들을 같은 카테고리로 묶어두게 되면 에디터에서 작업할 때 필요한 프로퍼티를 빠르게 찾을 수 있게 됩니다.

DamageTimeInSeconds의 UPROPERTY 매크로에도 같은 내용을 입력해줍니다.

그 다음 DamagePerSecond의 UPROPERTY 매크로에는 BlueprintReadOnly, VisibleAnywhere, Transient, Category="Damage" 지정자를 입력해줍니다.

BlueprintReadOnly는 프로퍼티를 블루프린트에서 읽기만 가능하게 해줍니다.

VisibleAnywhere는 프로퍼티를 모든 프로퍼티 창에서 보이지만 편집할 수 없게 합니다.

Transient는 해당 프로퍼티가 휘발성 프로퍼티로 저장되지 않음을 의미합니다.

나머지 두 프로퍼티인 CharacterName과 bAttackable을 EditAnywhere과 BlueprintReadWrite로 설정하겠습니다.

우선 이렇게 작성한 프로퍼티들이 에디터에서 어떻게 보이는지 확인해보겠습니다.

이렇게 수정한 코드를 에디터에 적용하기 위해서는 에디터로 돌아간 뒤 에디터 하단에 있는 콘솔 명령 창에서 LiveCoding.Complie을 입력하거나 [Ctrl + Alt + F11] 단축키를 눌러 컴파일 해주면 됩니다.

컴파일이 끝난 뒤에 C++ 클래스의 MyActor를 월드에 배치하고 선택해서 디테일 패널에서 보면 Damage 카테고리로 묶어준 프로퍼티들은 Damage 카테고리에 모여있고 그렇지 않은 프로퍼티들은 클래스 이름인 MyActor 카테고리에 있는 것을 볼 수 있습니다.

그리고 EditAnywhere로 지정한 다른 프로퍼티와는 다르게 VisibleAnywhere로 지정한 DamagePerSecond 프로퍼티는 짙은 회색으로 표시되서 수정할 수 없는 것을 확인할 수 있습니다.

변수의 기본 값 설정하기

이번에는 스크립트 에디터로 돌아가서 프로퍼티의 기본 값을 설정하는 방법을 배워봅시다.

언리얼 프로그래밍에서는 게임이 시작되거나 오브젝트에 생성되었을 때 변수의 값을 원하는 어떤 값으로 설정하는 것을 생성자 함수에서 진행하게 됩니다.

생성자 함수는 언리얼의 C++ 클래스에서 반환형이 없고 클래스 이름과 같은 이름을 가지고 있습니다.

이 생성자라는 함수는 지난 영상에서 이야기한대로 클래스의 객체가 생성될 때 한 번 호출되는 함수이며 방금 설명한 대로 주로 생성된 액터의 프로퍼티, 즉 변수의 기본 값을 설정해주는데 사용됩니다.

이 생성자에서 프로퍼티의 기본 값을 설정해보도록 하겠습니다.

우선 MyActor 클래스의 소스 파일로 넘어가서 AMyActor 생성자에서 작업을 진행합니다.

여기서 프로퍼티를 초기화하는 방법은 두 가지가 있는데 첫 번째 방법은 이렇게 생성자 옆에 콜론을 입력한 뒤 프로퍼티의 이름을 적고 괄호에 기본 값을 넣어주는 것이고 두 번째 방법은 생성자의 바디에서 기본 값을 대입해주는 것입니다.

이 두 가지 방법 중에 선호하는 방법을 사용하면 됩니다.

이렇게 생성자에서 값을 입력해주고 언리얼 에디터로 돌아가서 컴파일해주면 월드에 배치한 MyActor의 각 값들이 생성자에 입력한 기본 값으로 바뀌는 것을 볼 수 있습니다.

아웃트로

이번 영상에서는 언리얼 C++ 프로그래밍의 변수와 UPROPERTY 매크로에 대한 기초적인 내용을 배워보았습니다.

다음 영상에서는 이어서 함수와 UFUNCTION 매크로에 대해서 알아보도록 하겠습니다.

이 강좌는 시청자 여러분들의 시청과 후원으로 제작되었습니다.

이상 베르의 게임 개발 유튜브였습니다. 감사합니다.

 

[투네이션]

 

-

 

toon.at

[Patreon]

 

WER's GAME DEVELOP CHANNEL님이 Game making class videos 창작 중 | Patreon

WER's GAME DEVELOP CHANNEL의 후원자가 되어보세요. 아티스트와 크리에이터를 위한 세계 최대의 멤버십 플랫폼에서 멤버십 전용 콘텐츠와 체험을 즐길 수 있습니다.

www.patreon.com

[디스코드 채널]

 

Join the 베르의 게임 개발 채널 Discord Server!

Check out the 베르의 게임 개발 채널 community on Discord - hang out with 399 other members and enjoy free voice and text chat.

discord.com

 

반응형

4.26 버전이 업데이트 되면서 안보이는 새 C++ 클래스 생성 기능을 찾아봅시다!

 

사용 엔진 버전 : 4.26

 

타임라인

0:00 인트로

0:24 4.25 버전 이전의 C++ 클래스 생성

0:37 4.26 버전 이후의 C++ 클래스 생성

2:02 아웃트로

 

[투네이션]

 

-

 

toon.at

[Patreon]

 

WER's GAME DEVELOP CHANNEL님이 Game making class videos 창작 중 | Patreon

WER's GAME DEVELOP CHANNEL의 후원자가 되어보세요. 아티스트와 크리에이터를 위한 세계 최대의 멤버십 플랫폼에서 멤버십 전용 콘텐츠와 체험을 즐길 수 있습니다.

www.patreon.com

[디스코드 채널]

 

Join the 베르의 게임 개발 채널 Discord Server!

Check out the 베르의 게임 개발 채널 community on Discord - hang out with 399 other members and enjoy free voice and text chat.

discord.com

 

반응형

언리얼 C++ 클래스에서 변수를 만드는 방법과 UPROPERTY 매크로에 대해서 알아봅시다.

 

타임라인

0:00 개요

0:50 새 프로젝트 생성/C++ 클래스 생성

1:21 기본 변수 선언 방법

2:18 언리얼 프로그래밍의 기본 변수 타입

7:40 접근지정자를 이용한 변수 공개 범위 설정

9:10 UPROPERTY를 이용해서 변수를 언리얼 에디터 디테일 패널에 공개하기

12:27 생성자에서 변수의 기본 값 설정하기

 

[투네이션]

 

-

 

toon.at

[Patreon]

 

WER's GAME DEVELOP CHANNEL님이 Game making class videos 창작 중 | Patreon

WER's GAME DEVELOP CHANNEL의 후원자가 되어보세요. 아티스트와 크리에이터를 위한 세계 최대의 멤버십 플랫폼에서 멤버십 전용 콘텐츠와 체험을 즐길 수 있습니다.

www.patreon.com

[디스코드 채널]

 

Join the 베르의 게임 개발 채널 Discord Server!

Check out the 베르의 게임 개발 채널 community on Discord - hang out with 399 other members and enjoy free voice and text chat.

discord.com

 

반응형

언리얼 엔진 4 프로그래밍에 입문해봅시다! 그리고 언리얼 C++ 클래스를 생성하는 방법과 클래스를 처음 생성했을 때 볼 수 있는 생성자와 BeginPlay, Tick과 같은 이벤트 함수에 대해서 알아봅시다.

 

타임라인

0:00 개요

0:09 언리얼 엔진 4 강좌를 만드는 이유

1:59 C++ 클래스와 블루프린트 클래스

3:03 새 프로젝트 만들기

4:02 C++ 클래스 생성하기

4:46 새로 생성한 C++ 클래스의 기본 형태

6:59 언리얼 C++ 클래스의 생성자, BeginPlay, Tick의 실행 테스트

8:40 마무리

 

[투네이션]

 

-

 

toon.at

[Patreon]

 

WER's GAME DEVELOP CHANNEL님이 Game making class videos 창작 중 | Patreon

WER's GAME DEVELOP CHANNEL의 후원자가 되어보세요. 아티스트와 크리에이터를 위한 세계 최대의 멤버십 플랫폼에서 멤버십 전용 콘텐츠와 체험을 즐길 수 있습니다.

www.patreon.com

[디스코드 채널]

 

Join the 베르의 게임 개발 채널 Discord Server!

Check out the 베르의 게임 개발 채널 community on Discord - hang out with 399 other members and enjoy free voice and text chat.

discord.com

 

반응형

C++ 코드 생성자에서 콘텐츠 브라우저의 클래스와 리소스 불러오기

 

작성 기준 버전 :: 4.21.1

 

게임을 제작하는 과정에서 객체를 초기화할 때, 프로젝트에 포함된 다른 클래스나 오브젝트, 리소스를 가져와야하는 경우가 종종 생긴다.

 

 

그런 경우 블루프린트의 이벤트 그래프에서 작업하는 경우라면 위의 이미지와 같이 콘텐츠 브라우저에 있는 리소스나 블루프린트 클래스 등을 곧바로 선택할 수 있지만, C++ 코드에서는 직접 경로를 지정해서 코드를 작성해야 한다.

 

단, C++ 코드에서 직접 경로를 지정해서 리소스나 블루프린트 클래스를 가져올 때, 주의할 점은 리소스나 블루프린트 클래스의 경로나 파일명이 자주 바뀌는 상황을 피하는 게 좋다. 경로를 지정한 이후에 경로가 바뀌지 않을 것이 확실하다면 C++ 코드로 경로를 지정해서 가져오는게 낫겠지만 자주 바뀌는 상황이라면 바뀐 리소스를 불러오는 모든 코드를 일일이 찾아서 수정하고 컴파일하는 문제가 발생한다.

 

그렇기 때문에, 경로나 리소스의 파일명이 자주 바뀔 상황이라면 위의 이미지처럼 블루프린트를 이용해서 초기화를 진행하거나, 별도의 기능을 만들어서 일일이 경로를 지정하고 바꾸는 작업을 자동화시키는 것이 좋다.

 

우선 C++ 코드에서 콘텐츠 브라우저의 리소스나 블루프린트 클래스를 가져오기 위해서는 다음의 헤더를 전처리기로 포함시켜주어야 한다.

 

#include "UObject/ConstructorHelpers.h"

 

ConstructorHelpers는 생성자에 도움을 주는 클래스로 생성자에서 콘텐츠 브라우저의 리소스나 블루프린트 클래스를 불러오는 작업을 도와주는 기능들을 가지고 있다. ConstructorHelpers는 생성자에서 사용되는 기능이기 때문에 생성자 이외의 장소에서 ConstructorHelpers를 사용하려고 시도하면 컴파일 에러가 발생하게 된다.

 

 

C++ 코드에서 블루프린트 클래스 가져오기

 

콘텐츠 브라우저 패널에 Blueprints 폴더 안에 TestBlueprintClass라는 이름의 APawn 클래스를 상속받은 블루프린트 클래스가 있다고 가정할 때, 그것을 C++ 코드에 가져오기 위해서는 다음 예시와 같이 코드를 작성하면 된다.

 

static ConstructorHelpers::FClassFinder<APawn> BPClass(TEXT("/Game/Blueprints/TestBlueprintClass"));
if (BPClass.Succeeded() && BPClass.Class != NULL)
{
    // 가져온 BPClass.Class를 통한 작업
}

 

FString 경로를 통해서 불러오는 것이니 만큼, 오타나 변경된 경로나 파일명으로 인해서, 클래스가 제대로 불러와지지 않는 경우가 발생할 수 있기 때문에, Succeeded() 함수와 Class의 NULL 체크를 통해서 성공적으로 클래스가 불러와졌는지 체크하고 사용해야 한다.

 

클래스 탐색자(Class Finder)는 성공적으로 블루프린트 클래스를 가져온 경우, Class 멤버 변수 안에 TSubclassOf<T> 타입으로 해당 클래스를 가지고 있게 된다. 이것을 이용해서 필요한 작업을 진행하면 된다.

 

 

C++ 코드에서 리소스 가져오기

 

이번에 알아볼 것은 C++ 코드에서 콘텐츠 브라우저 패널의 리소스를 가져오는 과정이다. 리소스의 종류는 여러가지가 될 수 있는데 대표적인 것으로는 스태틱 메시나 텍스처를 예로 들 수 있다.

 

아래의 예시코드는 드롭된 아이템의 메시가 아이템의 종류에 따라서 달라진다는 가정하에 만들어졌다. 콘텐츠 브라우저의 Item/StaticMesh 폴더 안에 SM_Helmet 이라는 이름을 가진 헬멧 모양의 스태틱 메시가 있을 때, FObjectFinder를 통해서 가져올 수 있다.

 

DropItemStaticMeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("DropItemMesh"));
RootComponent = DropItemStaticMeshComponent;

 

static ConstructorHelpers::FObjectFinder<UStaticMesh> HelmetStaticMesh(TEXT("/Game/Item/StaticMesh/SM_Helmet"));
if (HelmetStaticMesh.Succeeded() && HelmetStaticMesh.Object != nullptr)
{
    DropItemStaticMeshComponent->SetStaticMesh(HelmetStaticMesh.Object);
}

 

FObjectFinder를 통해서 가져온 오브젝트 역시 Succeeded() 함수와 Object 변수의 null 체크를 통해서 리소스가 제대로 불러와졌는지 체크를 한 뒤 사용해야 한다.

 

 

 

 

 

C++ 코드에서 C++ 클래스 가져오기

 

C++ 코드에서 블루프린트 클래스가 아닌 직접 작성한 C++ 클래스를 가져와서 사용하고 싶을 수도 있다. 예를 들어 게임 모드 클래스에서 기본 폰이나 기본 플레이어 컨트롤러를 설정하려고 할 때, C++로 작성한 폰 클래스나 플레이어 컨트롤러 클래스를 기반으로 블루프린트 클래스를 생성해서 넣어주는게 아니라 C++ 클래스를 곧바로 코드에서 넣어주고자 한다면 다음 예시 코드와 같이 작성하면 된다.

 

AYourProjectGameMode::AYourProjectGameMode()
{
    PlayerControllerClass = AYourCustomPlayerController::StaticClass();
}

 

StaticClass() 함수를 이용하면 런타임 중에 해당 클래스를 나타내는 UClass를 얻어낼 수 있다.

 

[투네이션]

 

-

 

toon.at

[Patreon]

 

WER's GAME DEVELOP CHANNEL님이 Game making class videos 창작 중 | Patreon

WER's GAME DEVELOP CHANNEL의 후원자가 되어보세요. 아티스트와 크리에이터를 위한 세계 최대의 멤버십 플랫폼에서 멤버십 전용 콘텐츠와 체험을 즐길 수 있습니다.

www.patreon.com

[디스코드 채널]

 

Join the 베르의 게임 개발 채널 Discord Server!

Check out the 베르의 게임 개발 채널 community on Discord - hang out with 399 other members and enjoy free voice and text chat.

discord.com

 

반응형

데이터 테이블(Data Table) 사용하기

 

작성 기준 버전 :: 4.21.1

 

게임을 제작할 때 레벨업에 필요한 경험치량이나 스킬의 계수 등 추후에 밸런스 수정 작업이 필요한 값들은 함부로 코드에 상수로 넣어서는 안된다. 이런 부분은 기획자가 손쉽게 접근이 가능해야 하기 때문에, 기획자들이 주로 사용하는 엑셀이나 스프레드시트의 데이터를 언리얼 엔진으로 임포트해서 사용하는 방식을 지원한다. 이것을 데이터 주도형 접근법이라고 한다.

 

언리얼 엔진에서는 기획자들이 주로 사용하는 엑셀이나 스프레드시트에서 손쉽게 만들어낼 수 있는 .CSV 파일이나 서버 프로그램에서 주로 사용되는 JSON 파일을 손쉽게 임포트하는 기능을 제공한다.

 

 

데이터 테이블 임포트
 

데이터 테이블은 유용한 방식으로 짜여진 표를 의미한다. .CSV 파일을 임포트하기 위해서는 우선 프로그래머가 데이터를 엔진이 인식할 수 있게 Row 컨테이너를 만들어서 엔진에 데이터 해석 방식을 알려줘야 한다.

 

우리가 예시로 사용할 .CSV 파일은 다음 레벨업까지 필요한 경험치의 양에 대한 것이고 그 내용은 다음과 같다.

 

Name,ExpToNextLevel,TotalExp
1,0,0
2,100,100
3,200,300
4,300,500
5,400,700
6,500,900
7,600,1100
8,700,1300
9,800,1500
10,1600,2400

 

LevelUpTable.csv
다운로드

 

이런 컨테이너를 만드는 방법은 두 가지가 있는데 블루프린트를 이용하는 방식과 C++ 코드를 통해 만드는 방식이 있다.

 

 

블루프린트

 

데이터 테이블 로우를 만들기 위해서는 구조체를 생성해야 한다. 구조체의 이름은 BP_LevelUpTableRow로 한다.

 

 

블루프린트 구조체가 생성되면 더블클릭해서 블루프린트 구조체 에디터를 열고 변수를 추가한다. 추가하는 변수의 이름은 ExpToNextLevel과 TotalExp로 각 열의 이름과 순서가 일치해야 한다. 제일 첫 열인 Name은 게임 내에게 각 행에 접근하는 이름이 되는 것으로 따로 변수를 추가하지 않아도 된다.

 

 

변수를 모두 추가한 뒤에는 구조체를 저장하고 에디터를 닫는다. 그리고 콘텐츠 브라우저 패널에서 파일 창에 우클릭하여 /Game에 임포트... 를 선택한다.

 

 

CSV 파일을 임포트한다.

 

 

데이터 테이블 옵션 창이 뜨면 데이터 테이블 행 유형 선택을 방금 추가한 구조체로 설정하고 확인을 누른다.

 

 

추가된 데이터 테이블을 열어보면 .CSV 파일의 내용이 훌륭하게 임포트된 것을 확인할 수 있다.

 

 

 

C++ 코드

 

행 컨테이너를 블루프린트 구조체로 만들 경우, C++ 코드에서는 사용할 수 없다는 단점이 있다. C++ 코드에서 사용하기 위해서는 USTRUCT로 만들어야 되는데 언리얼 구조에 대한 설명은 C++ / USTRUCT 사용자 정의 구조체 만들기 문서에서 참고할 수 있다.

 

우선 Actor 클래스를 상속받아서 CustomDataTables라는 더미 클래스를 생성한다.

 

 

클래스가 생성되면 전처리기와 클래스 선언 사이에 구조체를 선언하는 코드를 추가해준다. 행 컨테이너로 사용되는 구조체는 FTableRowBase를 상속받아야만 한다.

 

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Engine/DataTable.h"
#include "CustomDataTables.generated.h"

USTRUCT(BlueprintType)
struct FLevelUpTableRow : public FTableRowBase
{
    GENERATED_BODY()

public:

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "LevelUp")
        int32 ExpToNextLevel;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "LevelUp")
        int32 TotalExp;
};

UCLASS()
class DATATABLETEST_API ACustomDataTables : public AActor
{
    GENERATED_BODY()
   
};

 

코드를 완성하고 프로젝트를 빌드한 뒤, 에디터로 돌아가서 .CSV 파일을 임포트해서 데이터 테이블 옵션의 데이터 테이블 행 유형 선택 드롭다운 메뉴를 열어보면 우리가 방금 추가한 LevelUpTableRow가 있는 것을 확인할 수 있다.

 

 

이를 통해서 .CSV 파일을 임포트하면 아까 블루프린트 구조체를 통해서 임포트했을 때와 동일하게 DataTable이 생성되는 것을 볼 수 있다.

 

 

 

 

 

데이터 테이블 사용하기

 

이번 파트에서는 작성한 데이터 테이블을 사용하는 방법에 대해서 알아보자.

 

블루프린트에서 데이터 테이블 사용하기

 

블루프린트에서 데이터 테이블을 사용하기 위해서는 블루프린트 그래프의 빈 자리에 우클릭해서 컨텍스트 메뉴를 열고 "데이터 테이블 행 구하기"를 검색해서 이 노드를 배치하면 된다.

 

 

GameModeBase를 상속받는 블루프린트 클래스를 하나 생성한다. 이벤트 그래프의 BeginPlay 이벤트로부터 다음과 같이 블루프린트 그래프를 구성하자.

 

 

위 그래프는 LevelUpTable에서 각 행을 가져와서 Total Exp 값을 화면에 출력하는 역할을 한다.

 

블루프린트를 저장하고 에디터로 가서 월드 세팅의 Game Mode를 방금 추가한 게임 모드로 바꿔준다.

 

 

그 다음 에디터에서 플레이 버튼을 눌러보면 화면에 각 레벨의 Total Exp가 연속으로 출력되는 것을 볼 수 있다.

 

 

 

C++ 코드에서 데이터 테이블 사용하기

 

C++ 코드에서 데이터 테이블을 사용하는 과정은 블루프린트에서 노드 하나만 생성하면 되는 것에 비해서는 조금 복잡하다.

 

우선 프로젝트에 DataTableTestGameModeBase라는 이름으로 새 게임 모드 클래스를 만들고 헤더에 다음 멤버 변수와 함수를 추가한다.

 

public:
    ADataTableTestGameModeBase();

    virtual void BeginPlay() override;

private:
    class UDataTable* LevelUpDataTable;

 

그리고 DataTableTestGameModeBase라는 .cpp로 가서 다음 전처리기를 추가한다.

 

#include "CustomDataTables.h"
#include "UObject/ConstructorHelpers.h"

 

ADataTableTestGameModeBase::ADataTableTestGameModeBase() 생성자 함수와 BeginPlay() 함수를 다음과 같이 구현한다.

 

ADataTableTestGameModeBase::ADataTableTestGameModeBase()
{
    static ConstructorHelpers::FObjectFinder<UDataTable> DataTable(TEXT("/Game/LevelUpTable"));
    if (DataTable.Succeeded())
    {
        LevelUpDataTable = DataTable.Object;
    }
}

void ADataTableTestGameModeBase::BeginPlay()
{
    Super::BeginPlay();

    if (LevelUpDataTable != nullptr)
    {
        for (int32 i = 1; i <= 10; i++)
        {
            FLevelUpTableRow* LevelUpTableRow = LevelUpDataTable->FindRow<FLevelUpTableRow>(FName(*(FString::FormatAsNumber(i))), FString(""));
            UE_LOG(LogTemp, Log, TEXT("Lv.%d :: ExpToNextLevel(%d) TotalExp(%d)"), i, (*LevelUpTableRow).ExpToNextLevel, (*LevelUpTableRow).TotalExp);
        }
    }
}

 

코드 작성이 완료되면 프로젝트를 빌드하고 에디터로 넘어간다.

 

그 다음 월드 세팅에서 게임 모드를 방금 만든 것으로 교체한다.

 

 

플레이 버튼을 눌러보면 게임이 시작되면서 데이터 테이블의 값들을 가져와서 로그를 출력하는 것을 확인할 수 있다.

 

 

[유니티 어필리에이트 프로그램]

아래의 링크를 통해 에셋을 구매하시거나 유니티를 구독하시면 수익의 일부가 베르에게 수수료로 지급되어 채널의 운영에 도움이 됩니다.

 

에셋스토어

여러분의 작업에 필요한 베스트 에셋을 찾아보세요. 유니티 에셋스토어가 2D, 3D 모델, SDK, 템플릿, 툴 등 여러분의 콘텐츠 제작에 날개를 달아줄 다양한 에셋을 제공합니다.

assetstore.unity.com

 

Easy 2D, 3D, VR, & AR software for cross-platform development of games and mobile apps. - Unity Store

Have a 2D, 3D, VR, or AR project that needs cross-platform functionality? We can help. Take a look at the easy-to-use Unity Plus real-time dev platform!

store.unity.com

 

Create 2D & 3D Experiences With Unity's Game Engine | Unity Pro - Unity Store

Unity Pro software is a real-time 3D platform for teams who want to design cross-platform, 2D, 3D, VR, AR & mobile experiences with a full suite of advanced tools.

store.unity.com

[투네이션]

 

-

 

toon.at

[Patreon]

 

WER's GAME DEVELOP CHANNEL님이 Game making class videos 창작 중 | Patreon

WER's GAME DEVELOP CHANNEL의 후원자가 되어보세요. 아티스트와 크리에이터를 위한 세계 최대의 멤버십 플랫폼에서 멤버십 전용 콘텐츠와 체험을 즐길 수 있습니다.

www.patreon.com

[디스코드 채널]

 

Join the 베르의 게임 개발 채널 Discord Server!

Check out the 베르의 게임 개발 채널 community on Discord - hang out with 399 other members and enjoy free voice and text chat.

discord.com

 

반응형

+ Recent posts