기초 5. 캐릭터 생성.
에픽게임즈 런쳐에서 Paragon:Greystone 에셋을 프로젝트에 추가했다.
지난시간엔 Actor와 Pawn까지 확장해 봤는데 Pawn은 빙의해서 움직일수 있다는 차이가 있었다. 또 Character는 Pawn을 상속받았고 애니메이션도 넣을 수 있는 등 여러 기능이 추가된다. Character를 상속받아 MyCharacter 클래스를 만들어보자.
BeginPlay, Tick, Pawn을 상속받았기에 SetupPlayerInputComponent까지 모두 virtual로 가지고 있다.
F12 를 눌러 ACharacter클래스를 둘러보면 Pawn에서는 UMeshComponent를 직접추가해줬는데 Character는 기본적으로 USkeletalMeshComponent* Mesh를 가지고 있다. 메쉬의 종류로 뼈대를 가지고 있어 애니메이션에 필요한것이다. 또 UFloatingMovementComponent가 아니라 UCharacterMovementComponent* CharacterMovement를 가지고 있다. 조금 더 복잡한 움직임 (예)쪼그리기)을 가능하게 한다. 이밖에도 충돌 범위를 나타내는 UCapsuleComponent* CapsuleComponent를 가지고 있으며 나중에 데디케이트 서버를 붙여 사용할 때를 대비해서도 온작 함수와 컴포넌트들을 가지고 있다.
ACharacter의 생성자를 보면 CapsuleComponent를 CreateDefaultSubobject를 이용해 만들고 RootComponent로 만들어주고 CharacterMovement와 SkeletalComponent까지 만들어준다. 즉, 이전처럼 다 추가할 필요 없이 기본설정은 되어있어서 추가적으로 필요한것만 추가하면 되는 것을 알 수 있다.
이전에 만들었던 MyPawn에서 BindAxis하는 부분(UpDown, LeftRight)과 Mesh주소 가져오는 부분만 가져와서 MyCharacter에 붙인다. 그리고 StaticMesh에서 USkeletatMesh로 바꾸고 SkeletalMesh타입의 에셋으로 바꿔주자.
그리고 Mesh에 직접접근은 안되는데 private타입으로 GetMesh()를 이용해야한다.
static ConstructorHelpers::FObjectFinder<USkeletalMesh> SM(TEXT("SkeletalMesh'/Game/ParagonLtBelica/Characters/Heroes/Belica/Meshes/Belica.Belica'"));
if (SM.Succeeded())
{
GetMesh()->SetSkeletalMesh(SM.Object);
}
이런식으로 말이다. 또 GameModeBase의 생성자에서 DefaultPawnClass를 DefaultPawnClass = AMyCharacter::StaticClass(); 로 바꾸고 실행해보면 어쨋든 카메라가 캐릭터 메쉬모양 안에 있는걸 확일할 수 있다.
카메라를 탑다운 RPG처럼 보이게 달아보자.
CameraArm을 캐릭터에 달아서 조금 뒤에서 보도록 해보자.
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = true))
USpringArmComponent* SpringArm;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = true))
UCameraComponent* Camera;
그런데 두 컴포넌트 다 CoreMinimal에 포함되어 있지 않아 헤더에서 전방선언을 해주고 cpp파일에서 include해줘야 할 때도 있다.
#include "Camera/CameraComponent.h"
#include "GameFramework/SpringArmComponent.h"
#include "Components/CapsuleComponent.h" // 미리 추가해두었다.
생성자엔
Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("CAMERA"));
SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("SPRINGARM"));
// (씬컴포넌트 이므로)부모컴포넌트를 지정한다.
SpringArm->SetupAttachment(GetCapsuleComponent());
Camera->SetupAttachment(SpringArm);
// 카메라 조정
Camera->TargetArmLength = 500;
SpringArm->TargetOffset = FVector(0.f, 0.f, 100.f);
SpringArm->SetRelativeRotation(FRotator(-35.f, 0.f, 0.f)); //피치회전
// 메쉬 위치 조정
GetMesh()->SetRelativeLocationAndRotation(
FVector(0.f, 0.f, -88.f),
FRotator(0.f, -90.f, 0.f)
);
SetupAttachment는 루트컴포넌트가 있고(ACharacter클래스에서 디폴트로 지정되어있는 CapsuleComponent) 그 위에 붙인다는 것이다. 캡슐컴포넌트에 스프링암을 붙이고 카메라를 스프링암에 붙인다.
스프링 암은 일종의 셀카봉 같아서 길이와 각도를 설정해 카메라가 찍는 위치를 잡아줘야하는데 캡슐컴포넌트로부터 500정도 떨어지게 한 후 약간 아래를 쳐다보게 SetRelativeRotation으로 각도를 조정해줬다. 또 메쉬가 y축 기준 90도 돌아가 있으며 캡슐에서 가운데에 떠있기 때문에 88만큼 아래로 내려줬다. (-88.f가 일종의 국룰이다.)
그리고 실행해보면 오른쪽처럼 탑다운각도로 되어있다. 또 MyCharacter를 실행중에 보면 SpringArm, Camera가 붙어있고 여러 설정가능한 컴포넌트들도 에디터에서 볼 수 있다.
마우스를 돌릴때 캐릭터가 돌아갈 수 잇도록 해보자.
프로젝트 세팅> 입력에서 새로운 축 맵핑으로 이름을 Yaw로 마우스 X 입력을 받도록 추가하자.
MyCharacter클래스에 SetupInputComponent에서 PlayerInputComponent->BindAxis(TEXT("Yaw"), this, &AMyCharacter::Yaw); 로 묶어주고 void Yaw(float Value);를 추가했다. 내용은ㅇ
void AMyCharacter::Yaw(float Value)
{
AddControllerYawInput(Value);
}
역시 언리얼엔진엔 이미 만들어진게 있어서 사용하면 마우스의 좌클릭하고 돌리면 캐릭터도 돌아가는걸 쉽게 구현했다.
이게 동작하는 이유는 실행하고 빙의해제하고 MyCharacter의 디테일을 보면 Pawn컴포넌트에서 Use Controller Rotation Yaw가 체크되어 있기 때문이다. 즉, Player에 적용시키는게 아니라 Controller에다가 YawInput을 적용시키고 잇는것이다. 이렇게 엔진이 단순함에도 퍼즐이 잘 맞춰져있지 않으면 잘 돌아가지 않을 수 있다. 그래서 차츰차츰 알아가보자...⭐
기초 6. 블루프린트 클래스.
언리얼엔진은 C++외에도 블루프린트로도 게임을 만들수 있다. C++만 있어도 블루프린트를 굳이 사용하지 않아도 되나 경우에 따라 섞어사용하기도 하고 돌아가는 원리를 알아야하므로 이번엔 MyCharacter클래스를 지우고 블루프린트로 대체해가보자.
소스코드를 삭제하고 (삭제하는 방법은 Source\에서 직접 MyCharacter와 MyPawn의 헤더와 cpp파일을 삭제한 후 저장하고 솔루션파일을 지운다음에 언리얼 파일 우클릭으로 Generate Visual Studio project files로 다시 만든 후 언리얼 파일을 실행해 새로 빌드한다.) 블루프린트를 만들 준비한다.
C++코드와 블루프린트의 성능적 차이만 보면 C++코드로 직접 작성하는게 거의 10배정도 빠르고 가볍기 때문에 큰 프로젝트를 만들 때는 C++코드를 사용하고 가벼운 프로젝트를 만들때는 블루프린트를 사용하는게 편리하다.
콘텐츠브라우저에서 콘텐츠 아래에 Blueprints 폴더를 만들자. 그리고 우클릭으로 블루프린트클래스를 추가한다. C++처럼 부모클래스를 선택할 수 있는데 Character를 상속받아 이름을 BP_MyCharacter를 만들어보자. 저장 후 더블클릭으로 자세히 보면 새로운 창이 열린다. 참고로 C++클래스는 이름의 변경이 쉽지 않앗는데 블루프린트는 그냥 우클릭으로 이름도 변경하고 삭제하는게 쉽다.
C++파일에서 SprnigComponent, CameraComponent를 추가하고 축 맵핑과 관련 설정들을 했었는데 블루프린트 에디터 창에서 보면 우선 ACharacter클래스가 가지고 있는 성질들을 기본으로 가지고 있어 설정하고 비주얼적으로 쉽게 나머지들을 추가해보자.
블루프린트를 사용하면 장점 중 하나가 만약 C++클래스에서 스켈레탈메쉬를 바꾸려면 월드에 배치한 객체 하나를 바꿔선 안되고 코드상에서 직접바꿔줘야했다. 그런데 툴을 이용해 간단하게 바꿔줘 더 편하고 컴파일하는데도 시간이 더 짧다. 그런데 컴파일이 기능이 가볍지 실제로 애니메이션같은걸 추가하면 더 나중에 무겁게 된다..
이벤트 그래프탭에 가서 보면 C++클래스처럼 기본 함수들이 있다. 우클릭하며 움직이면 움직이는 창인데 일종의 C++클래스가 설계도였던것처럼 이를 좀 더 시각적으로 볼 수 있다. 즉, 비주얼적으로 코딩하는것이다.
위 사진을 보면 캡슐모양에서 스켈레탈 메시가 가운데부터 잡혀있는걸 볼 수 있다. 그래서 -88.f 내리고 또 Z축 기준 -90도 회전도 해준다.
또 SpringArm이랑 카메라도 추가해보자.
컴포넌트 추가를 눌러 SpringArm과 Camera를 추가하고 드래그드롭으로 계층구조도 바꿔 Camera가 SpringArm밑으로 들어가게 한다음에 디테일 탭에서 SpringArm의 길이(TargetArmLength)를 500, RelativeRotation을 -35했던것처럼 회전값의 pitch값을 바꿔준다.
BeginPlay에서 SpringArm의 값을 특정변수에서 읽어와 설정해주기.
변수추가에서 타입을 Float으로 ArmLength이름으로 기본값을 500으로 추가해주자(컴파일을 해야 기본값 탭에서 값을 넣을수 있다.). 옆에 눈 모양이 생기는데 키면 public이고 끄면 private의 개념이다. 이 ArmLength라는 변수를 TargetArm의 길이를 설정하는 데 쓰고싶은데 이벤트그래프 탭의 BeginPlay 노드에서 설정을 할 수 있다.
컴포넌트 탭에서 드리그드롭으로 SpringArm 컴포넌트를 이벤트 그래프에 가져올 수 있다. 그리고 SpringArm의 포인터를 좌클릭한후 끌고오면 새로운 노드를 연결할 수 있는데 armlength를 검색해 Set Target Arm Length를 추가하고 변수에서 ArmLength도 드래그 드롭으로 끌고와 타깃에 연결해 주었다. BeginPlay의 실행과 저 Set의 실행부분을 연결해 줘야 돌아간다.
AtestprojectGameModeBase::AtestprojectGameModeBase()
{
static ConstructorHelpers::FClassFinder<ACharacter> BP_Char(TEXT("Blueprint'/Game/Blueprints/BP_MyCharacter.BP_MyCharacter_C'"));
if (BP_Char.Succeeded())
{
DefaultPawnClass = BP_Char.Class;
}
}
이러면
DefaultPawnClass = MyCharacter::StaticClass(); 로 MyCharacter클래스를 처음 시작할 때 카메라가 붙어있는 폰이 되게 했던것처럼 Character를 상속받은 블루프린트클래스가 시작하면 기본 폰이 된다.
그리고 MyCharacter에 움직임을 위해 SetupPlayerInputComponent에 UpDown, LeftRight, Yaw를 등록했던 것처럼 움직임을 블루프린트로 만들어보자.
이벤트그래프에서 우클릭으로 노드추가로 leftright을 검색하면 'LeftRight의 입력축'을 추가한다. 그래서 이 이벤트가 발생했을 때 무엇을 할지를 설정하면 된다. C++클래스에서는 입력에서 들어온 scale값을(float Value으로 가져왔던) AddMovementInput(GetActorRightVector(), Value) 의 Value에 넣어 호출했었는데 LeftRight입력축 노드에서 실행해서 뽑아내 AddMovementInput 노드를 만들어내 연결한다. 그리고 Get Actor Right Vector 노드를 추가해서 입력값으로 연결해준다.
같은 방법으로 UpDown에 AddMovementInput(GetActorForwardVector(), Value)을, Yaw에 AddControllerYawInput(Value)를 연결해주었다. (이벤트 노드 추가할 때 축 이벤트이지 축 값이 아닌걸 주의해야한다.)
+)
블루프린트 클래스를 만들 때 처음에 상속할 클래스를 정하곤 했는데 에디터를 보면 맨 왼쪽 위에 부모클래스가 무엇인지 알려준다. 블루프린트는 C++클래스를 상속받아서 만들 수 있는데 역으로는 안된다.
새로운 블루프린트를 Blueprints하위에 만들어보자. 모든클래스에서 찾아서 지정하면 된다. 만약 우리가 만들었던 MyCharacter클래스를 상속받아서 블루프린트 클래스를 만들면 열었을 때 설정했던 모든 값들을 시각적으로 볼 수있다.
이 방법을 응용하자면 GameModeBase C++ 클래스도 상속받아 블루프린트 클래스로 만들 수 있다. 이름을 BP_GameModeBase로 하여 만들고 월드세팅에서 지정하여 사용한다. 이 BP_GameModeBase를 에디터에서 열어보면 우리가 설정했던 DefaultPawnClass외에도 여러 값들을 콤보박스에서 가져와 선택으로 지정할수 있게 되어있다. 또 블루프린트로 만든 게임모드를 사용하면 블루프린트 에디터를 열지 않아도 에디터에서 편집 가능하다.
블루프린트는 무겁긴 하지만 시각적으로 편하게 관리하게 해준다는 장점이 있어.특히 게임모드같은 걸 만들어 사용하기 편하다.
'[Unreal]' 카테고리의 다른 글
[Unreal 4] 충돌과 UI #1 - 충돌 기초, 소켓 실습, 아이템 줍기 (0) | 2023.05.22 |
---|---|
[Unreal 4] 애니메이션 #2 - 애니메이션 몽타주, 델리게이트, 애니메이션 노티파이, 블레드 스페이스. (0) | 2023.04.11 |
[Unreal 4] 애니메이션 - 애니메이션 기초, 스테이트 머신 (0) | 2023.03.24 |
[Unreal 4] 기초 #1 - 인터페이스 분석, 유니티 vs. 언리얼, 로그와 디버깅, 게임플레이 프레임워크 (0) | 2023.02.22 |
프로젝트 세팅 (0) | 2021.09.19 |