이득우의 언리얼 C++ 게임 개발의 정석을 읽고 개인 공부 목적으로 요약 정리한 글입니다!
: 인간형 폰을 효과적으로 제작하기 위한 모델
ACharacter 클래스는 APawn 클래스를 상속받는다
-Capsule, SkeletalMesh 컴포넌트 사용
CharacterMovement 컴포넌트를 사용하여 움직임 관리
CharacterMovement Component를 제공한다
그냥 플레이어 컨트롤러 : 알빠임? 내가 하고 싶은 대로 할거임
폰 : ㅠㅠ제발.... 나는 물리적으로그렇게못한다니까?ㅠㅠ
플레이어 컨트롤러는 컨트롤 회전을 제공한다
입력에 따라 캐릭터가 Yaw, Pitch, Roll 회전
Raw : 도리도리
Pitch : 끄덕끄덕
Roll : 갸우뚱갸우뚱
아 진짜 DX하다가 축 바뀌니까 죽겠따.. 너무 헷갈린다 ㅠㅠ
== 언리얼 3인칭 템플릿!!
분류 | 내용 |
---|---|
캐릭터의 이동 | 현재 보는 시점 기준 상하, 좌우 방향으로 이동, 카메라는 회전X |
캐릭터의 회전 | 캐릭터가 이동하는 방향으로 회전 |
카메라 지지대 길이 | 450cm |
카메라 회전 | 마우스 상하좌우 이동에 따라 카메라 지지대가 상하좌우로 회전 |
카메라줌 | 장애물 감지되면 캐릭터가 보이도록 카메라를 장애물 앞으로 줌인 |
고정된 3인칭 시점에서 캐릭터를 따라다닌다.
분류 | 내용 |
---|---|
캐릭터의 이동 | 상하좌우 키를 조합해 이동할 방향 결정 |
캐릭터의 회전 | 입력한 방향으로 회전 |
카메라 지지대 길이 | 조금 멀리 떨어진 800cm |
카메라 회전 | 회전없이 항상 고정. 45도로 내려다봄 |
카메라줌 | X 장애물이 있을 경우 외곽선 처리 |
AMyCharacter 클래스에서 ControlMode 를 변경하여 조작할 수 있도록 함
enum class EControlMode {
GTA,
DIABLO
};
열거형 선언 시 enum class로 열거형을 선언하자.
enum은 int로 변환될 수 있기 때문에 다양한 문제를 초래한다!!
자세한건 나중에 포스팅하겟슴!
그리구
UPROPERTY를 사용하지 않는 값 타입 변수들은 반드시 초기화해주자!~!!!!
AMyCharacter::AMyCharacter()
{
...
SetControlMode(EControlMode::GTA);
ArmLengthSpeed = 3.0f;
ArmRotationSpeed = 10.0f;
}
void AMyCharacter::SetControlMode(EControlMode NewControlMode)
{
CurrentControlMode = NewControlMode;
switch (CurrentControlMode) {
case EControlMode::GTA:
{
// 관련 설정
}
case EControlMode::DIABLO:
{
// 관련 설정
}
}
}
void AMyCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// 조작모드 변경 시 부드럽게 카메라가 움직일 수 있도록 SpringArm을 선형보간!
SpringArm->TargetArmLength = FMath::FInterpTo(SpringArm->TargetArmLength, ArmLengthTo, DeltaTime, ArmLengthSpeed);
switch (CurrentControlMode) {
case EControlMode::DIABLO:
{
SpringArm->SetRelativeRotation(FMath::RInterpTo(SpringArm->GetRelativeRotation(), ArmRotationTo, DeltaTime, ArmRotationSpeed));
break;
}
}
switch (CurrentControlMode) {
case EControlMode::DIABLO:
{
// 디아블로 방식에서는 DirectToMove (방향벡터)를 통해 회전행렬을 구해서 냅다 넣는다.
if (DirectionToMove.SizeSquared() > 0.0f) {
GetController()->SetControlRotation(FRotationMatrix::MakeFromX(DirectionToMove).Rotator());
AddMovementInput(DirectionToMove);
}
break;
}
}
}
// 시점변환
void AMyCharacter::ViewChange()
{
switch (CurrentControlMode) {
case EControlMode::GTA:
GetController()->SetControlRotation(GetActorRotation());
SetControlMode(EControlMode::DIABLO);
break;
case EControlMode::DIABLO:
GetController()->SetControlRotation(SpringArm->GetRelativeRotation());
SetControlMode(EControlMode::GTA);
break;
}
}
void AMyCharacter::MoveForward(float AxisValue)
{
// 그냥 앞뒤로 움직이기
// AddMovementInput(GetActorForwardVector(), AxisValue);
switch (CurrentControlMode) {
case EControlMode::GTA:
{
// 카메라가 바라보는 방향대로 움직이기
AddMovementInput(FRotationMatrix(GetControlRotation()).GetUnitAxis(EAxis::X), AxisValue);
break;
}
case EControlMode::DIABLO:
{
// 방향벡터 만들기 (실제로 움직이는 명령은 Tick에서 해줌)
DirectionToMove.X = AxisValue;
break;
}
}
}
void AMyCharacter::MoveRight(float AxisValue)
{
// 그냥 앞뒤로 움직이기
// AddMovementInput(GetActorRightVector(), AxisValue);
switch (CurrentControlMode) {
case EControlMode::GTA:
{
// 카메라가 바라보는 방향대로 움직이기
AddMovementInput(FRotationMatrix(GetControlRotation()).GetUnitAxis(EAxis::Y), AxisValue);
break;
}
case EControlMode::DIABLO:
{
// 방향벡터 만들기 (실제로 움직이는 명령은 Tick에서 해줌)
DirectionToMove.Y = AxisValue;
break;
}
}
}
FRotationMatrix : 회전된 좌표계 정보를 저장하는 행렬
MakeFromX,Y,Z : 하나의 벡터로부터 회전 행렬을 구축하는 명령어
FMath::InterpTo
선형보간해주는 명렁어
(지정한 속력으로 목표 지점까지 진행하되, 목표 지점까지 도달하면 그 자리에서 멈춤)
float : FInterpTo
Vector : VInterpTo
Rotator : RInterpTo