Unreal Engine 5 – Full Course for Beginners
https://www.youtube.com/watch?v=6UlU_FsicK8
11시간의 30분의 강의를 5일만에 드디어 반 왔다.
확실한건 배우면서 유니티보다 낫겠다는 생각을 했다.
그 이유는 유니티보다 구현된 기능들이 훨씬 많아서 어떻게든
찾기만하면, 편리하게 사용할 수 있다는 점이다.
인생 첫 3D게임을 만들떄까지 기초를 다져보자.
오랜만에 Unreal을 켰는데, 끌때까지 없었던 오류가 갑자기 생겼다.
언리얼에 인터페이스를 추가한다.
이전에 만든 Remove함수를 인터페이스를 통해서 수정해본다고 한다.
인터페이스 헤더를 Pickup에 추가한다.
Character는 pickup의 헤더를 상속받기에
결국 인터페이스 헤더는 character와 pickup에서 선언된다.
그리고, 위의 사진처럼, IMyInterface라는 interface파일
(I는 prefix)
도 상속받도록 한다.
interface에서는 Destruct라는 가상함수를 적어놓는다.
interface는 설계도처럼 이런 기능이 있어야한다고 미리 선언해두는 것이고,
C++에서는 virtual 예약어를 통해서 가상함수들로 구현을 한다.
그래서 다음의 사진은,
Pickup에서 해당 interface를 상속받았으니,
interface에 정의된 가상함수 Destruct를 구현해야하고,
Destruct를 override하여 실체를 이제 구현하게 된다.
그래서 구현한다.
그냥 Pickup을 두 BP객체가 상속받도록 setting하면 되는건데 왜 인터페이스를 만드는거지?
과거의 나는 바보였다.
MyInterface를 상속받은 Pickup이라는 CPP클래스를 각기 다른 BP에서 Setting하면 똑같이 사라지게 동작하게 된다.
하지만,
다른 Actor객체를 만들고, MyInterface를 상속받게 하고,
해당 Interface의 Destruct라는 함수를 다르게 구현한다면?
이름은 같은 Destruct지만 다르게 동작하게 할 수 있다.[수정된 Character CPP 구문]
- 위의 사진처럼 IMyInterface로 통일되어 Cast할 수 있게되고,
해당 객체의 Destruct를 실행하게 하지만,
해당 Destruct가 다른기능을 수행하도록 할 수 있게 된다는 의미이다.
다른 pickup 2 BP객체에 interaction cpp로 설정해주고,
정상적으로 출력되고 사라진다..
CPP에서 BP class를 가져오는 것은 불가능하다.
그 이유는, 지금 CPP의 class를 가져오는데에도 반드시 Live Debugging을 통해서 언리얼에 인식시켜야되는데,
그 반대로 VS에서 BP를 인식하는 방법이 없다고 한다.
언리얼은 어떻게든 구현해놓은 것이 존재하기에 찾기만하면 방법이 있다.
다음과 같다. Character 헤더파일에 다음과 같이 TestFunc함수를 선언만 해놓는다.
여기서 BlueprintImplementableEvent를 설정한다.
BlueprintCallable은 굳이 하지 않아도 되는것이, CPP에서만 호출해도 되기 때문에 필요하면 설정.
참고로, 선언만하고 Debug하면 오류가 발생하는데,
BlueprintImplementableEvent를 설정하면,
BP에서 구현할거라는 의미인지 오류가 발생하지 않고 정상적으로 디버깅 된다.
BlueprintImplementableEvent를 설정하면,
다음과 같이, Functions에 override탭을 누르면 다음과 같이 TestBPFunc가 보이게 된다.
이렇게 BP중에 Print String이라는 BP와 연결한다면,
해당 BPFunc를 실행하게 될 때, 해당 PrintString에 인자까지 전달되어 실행하게 매핑되는 것이다.
다음과 같이, 부실때마다, 전역변수 i를 1씩 증가시켜 출력하도록 해보았다.
다음과 같이 정상동작한다.
그냥 BP함수처럼 사용도 가능하다.
문제가 있었다.
static int i
를 전역변수로 두고, 출력을 했는데, 게임을 다시 실행하면 초기화가 되지 않는다.
처음 실행시 딱 한번만 실행하는 초기화구문으로 인식되나보다라고 생각해서,
그래서 위처럼 그냥 int i를 사용했는데도 게임을 다시 실행해도 초기화가 되지 않는다.
일단 지나가지만, 사용하게 된다면 방법이 있을 것이다.
BP의 함수를 CPP에서 호출하는 방법을 봤고,
이제는 그것도 하고, BP에서도 CPP를 호출도 하는,
양방향 방법에 대해서 살펴본다.
다음과 같이 BlueprintNativeEvent를 설정한 함수를 만들어 보았다.
해당 함수는 조건이 까다롭다.
여기서 Implement함수는 간단한 String문장을 출력하도록 하였다.
[Parent함수 생성하는 법]
여기서 Native의 Parent함수는 CPP에서 구현한 _Implement로 인식하게 된다.
혹은 아래처럼 이를 동시에 연결하여,
CPP에서 해당 Native함수가 호출될 때, CPP쪽의 함수와 BP쪽의 함수를 동시에 실행하게 할 수도 있다.
마찬가지로, 그냥 BP함수처럼 사용도 가능한데,
이 경우에는 _Implementation인 CPP에 구현된 함수가 아니라,
BP에서 구현된 함수를 실행하게 된다.
게임에서 여러 데이터를 관리하기 위해서 Array와 Map을 가장 많이 쓴다고 한다.
Linked List는 주로 사용하지 않는다고 한다. -강사님의 생각-
추가로 Static Array나 STD::Vector도 잘 사용하지 않는다고 한다.
STD::Vector는, C++의 라이브러리용 배열이었다. 그것과 Unreal에서의 Array는 사용법이 상당히 비슷하다고 한다.
BP에서 인식할 수 있도록, 배열을 다음과 같은 매크로를 사용하여 헤더에 선언한다.
TArray를 사용한다 - 이전 C++에서 만들어봤던 T 관련에 대해 참고
[>> Template <<]
일단 생성자에서 배열을 초기화 한다.
Array관련 함수들을 적어보았다.
여기서 Emplace는, C++ Vector의 emplace_back과 같다고 한다.
출력하는 방식에는 2가지가 있다.
위의 것을 더 선호한다고 한다.
추가로 봐야할 것이 있는데,
알아서 잘 쓸 것
BP에서 배열을 사용할 수 있게 된다.
물론 프로그램을 시작하면, add emplace 등 함수로 인해 값이 바뀐다.
Character의 BeginPlay부분에 그냥 Add함수를 넣어보았다.
0,1,2,3,4,5,6,7,300000
이었는데,OurIntArray = {0,1,2,3,4,5,666};
Array 함수의 동작이, BP부터 우선적으로 실행하는 것을 보게 되었다.
Map도 template TMap으로 Array와 비슷한 형식으로 선언한다.
key, value자료형을 정해주고,
다음과 같이 Add를 통해 Map을 추가한다.
따로 초기화 하는 방법이 있긴할듯
그리고 for문을 통해서 key, value를 mapPrint라는 FString변수에 하나로 모아서 출력한다.
하나 주의할 것은, for문을 저렇게 쓰면, element는 key,value의 pair로 나오게 된다.
그러므로 .value, .key를 통해서 분리해서 사용.