
Character 클래스를 만들어 뷰포트에서 제어할 Player를 만들어보았다.
1. ACharacter 상속받는 클래스 만들어서 SpringArm, Camera 생성하기

먼저, Capsule Component 바로 밑에 붙일 Spring Arm과, Camera를 직렬화하여 생성해주었다.

이후, CapsulComponent를 가져와서 부모로 설정해줘야하기 때문에 헤더파일을 불러오고, 나머지 변수를 초기화할 SpringArm, Camera 헤더파일도 호출하였다.

이전에 간단히 Component를 생성하기 위해 만들어두었던 CreateComponent에는 부모 Component를 설정하는 코드가 없었다.

따라서 CreateComponent의 마지막 매개변수로 부모 Component가 들어온다면, (즉 부모 매개변수가 null 이 아니라면) 생성할 컴포넌트(OutComponent)에 SetupAttachment 함수를 통해 부모의 객체 아래 붙여주었다.

또한 Character의 기본 Controller 설정과, CharacterMovement 설정, SpringArm의 설정을 수행해주었다.
모든 함수는 블루프린트에서 설정했던 디테일 패널 속 속성 값들과 동일하다.
2. Character Mesh 적용하기

이후, 만들어진 Character 객체에 SkeletalMesh를 만들어 적용시킬 USkeletalMesh 에셋을 불러와 적용해주었다.
클래스 자체가 ACharacter를 상속받고있기 때문에 GetMesh() 함수를 통해 바로 메시에 접근할 수 있다.
이후, Mesh의 기본 설정값인 Location과 Rotation을 초기화해주었고, 이때 Rotation은 저번에 공부했듯이 에디터 상과, C++클래스 상의 Roll, Pitch, Yaw 순서가 다르기 때문에 유의하여 작성해주어야 한다.
(C++: Pitch-Yaw-Roll / 에디터: Roll-Pitch-Yaw)
이후 적용된 Mesh를 블루프린트에서 확인할 때 해줘야하는 특정 행동이 있다.

먼저, C++클래스 기반의 블루프린트 클래스를 생성하고 디테일 패널을 살펴본다.

그럼 GetAsset으로 불러온 메시가 적용되어있지 않고 그대로인 모습을 확인할 수 있는데, 이때 스켈레탈 메시 속성의 노란색 원상복구 화살표가 띄워져있는것을 알 수 있다.
이는 기본값이 없음 상태가 아니고 변경되었다는 뜻인데, 노란색 화살표를 누르면 C++클래스에서 불러온 뒤 적용해놓은 스켈레탈 메시가 정상적으로 보인다.

즉, 스켈레탈 메시의 기본값이 불러온 Asset으로 변경되어, 없음 상태가 기본이 아닌 상태가 된 것이다. 따라서 C++ 클래스에서 Character의 속성값을 변경하고 난 뒤, 블루프린트에 들어와서 되돌리기 화살표를 꼭 눌러 변경된 기본값을 적용시켜야 한다.
(C++ 클래스의 생성자에 들어가는 값은 전부 기본값으로 설정된다)
3. Animation Blueprint에 설정할 AnimInstance 만들기

블루프린트를 통해 애니메이션 블루프린트를 작성했을 땐 부모클래스를 AnimInstance로 설정하여 생성했지만, C++ 클래스를 통해 애니메이션 블루프린트를 작성하려면 부모 클래스를 C++클래스로 작성된 AnimInstance로 설정해주어야 한다.

따라서 AnimInstance를 상속받는 C++클래스를 직접 만들었다.

float speed 변수를 이용해서 Animation Blend Space가 조절되기 때문에 Blueprint클래스에서 읽기만 가능한 Speed 변수를 직렬화하여 생성했다.
이후, AnimInstance 객체의 BeginPlay와 Update 함수를 작성하였는데, 이때 부모 클래스의 UAnimInstance에서 virtual로 선언된 추상클래스를 override하여 재정의하였다.
이처럼 부모클래스에서 자식클래스에 필요하다면 재정의하여 사용할 수 있게끔 virtual 함수로 정의해둔 경우가 있다. 부모클래스에서 virtual이라는 키워드로 단어 찾기(Ctrl+F)를 통해 함수들을 확인하고, 필요한 함수를 재정의하여 사용하면 된다.
BeginPlay와 UpdateAnimation 함수 앞에 붙은 Native는 C++ 클래스에서 사용 가능한 함수라는 의미이다. 블루프린트 클래스에서 사용가능한 함수는 Native대신 Blueprint가 붙어있다.
NativeUpdateAnimation 함수가 Blueprint의 Update 함수와 비슷한 기능을 하므로, 해당 함수를 Update 함수로 사용하였다.

캐릭터 클래스도 GameFramework 경로에 존재하므로 해당 헤더파일을 추가시킨 후, OwnerCharacter를 초기화하였다.
해당 클래스의 Ower를 반환하는 TryGetPawnOwner 함수를 호출해 APawn을 반환받은 뒤, ACharacter 형으로 형변환하여 OwnerCharacter에 초기화하였다.
이후, Update할때마다 OwnerCharacter의 Velocity를 받아온 뒤, VectorLength 대신, Size2D() 함수를 사용하여 Speed 값을 갱신해주었다. (Vector Length도 존재함)
4. Animation Blueprint 생성하기

C++ 클래스를 통해 제작한 CAnimInstance를 애니메이션 블루프린트를 생성할 때 부모클래스로 설정할 수있게 되었다.

해당 클래스를 상속받으면 AnimGraph에서 Get Speed 함수를 통해 C++클래스에서 직렬화해두었던 Speed 변수를 사용할 수 있게 된다. 이런식으로 C++클래스 작업을 수행하다보면 이벤트그래프를 잘 사용하지 않아서 탭을 숨겨두기도 한다.
5. Character 클래스에서 Animation Instance설정하기

Player 클래스에 제작했던 Anim Instance를 설정하기 위해 헤더파일을 추가하였다.


이후, 클래스타입으로 클래스를 가져와 초기화하는 코드를 템플릿화하여 CHelpers에 GetClass라는 함수명으로 생성하였다.
Character의 애니메이션 Blueprint인 ABP_Character의 레퍼런스 주소를 복사하고 클래스 타입이므로 맨 뒤에 _C 를 붙여주었다. 그다음 SetAnimClass 함수롤 통해 Mesh의 Anim Instance를 초기화 해 주었다.
참고로 TSubclassOf 자체가 포인터형 클래스 타입이므로 animInstance 변수에 포인터를 붙이지 않고 바로 주소값을 전달해줘도 된다.

컴파일 한 후 Player의 블루프린트를 확인해보면 성공적으로 Anim Class가 초기화되어있는 것을 볼 수 있다.
6. GameMode 설정하기
게임을 플레이시키면 뷰포트의 Player Start 지점에 캐릭터가 스폰될 수 있도록 Game Mode를 설정해주었다.
C++ 클래스에 기본으로 만들어져있는 GameModeBase 파일의 이름을 수정하여 사용하였다.
C++클래스의 이름을 변경하려면 헤더파일과 클래스, 생성자 등의 파일명들을 전부 변경한 뒤, C++ 내에서가 아닌 엔진의 에디터에서 컴파일을 수행한다.

이후 생성자에서 DraultPawnClass로 Player 블루프린트 레퍼런스를 전달한다.

프로젝트 셋팅에서 이렇게 만든 Game Mode를 적용시키면 Default Pawn Class로 Player가 설정된 것을 볼 수 있고, 게임을 플레이시키면 플레이어가 성공적으로 뷰포트에 스폰된다.
