이제 라인트레이스를 사용해서 MovablePawn이 현재 공중에 있는지를 판단해서 공중에 있을 때 VelocityZ가 누적이 되어 중력 효과를 받도록 할것이다.
MovablePawn이 공중에 있는걸 판단하려면 라인트레이스를 아래(바닥)방향으로 짧게 쏴서 바닥이 감지되면 바닥에 있는걸로 판단하여 VelocityZ를 0으로 초기화 할 것이다.
// MovablePawn.h
FHitResult Hit; // 라인트레이스로 충돌 감지한 정보를 담는 변수
FVector LineStart; // 라인트레이스 시작점
FVector LineEnd; // 라인트레이스 끝점
FCollisionQueryParams Params; // 트레이스할 때 규칙(조건?)추가
bool bHit; // 현재 라인트레이스가 충돌한 상태인지(바닥인지)
// MovablePawn.cpp
// 생성자
Params.AddIgnoredActor(this); // 자기 자신 무시하는 규칙
// Tick
void AMovablePawn::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
LineStart = GetActorLocation(); // 트레이스 시작점은 액터의 위치
LineEnd = LineStart - FVector(0, 0, 50); // 액터에서 아래로 50cm 길이의 선을 쏨
// 충돌했는지 판단
bHit = GetWorld()->LineTraceSingleByChannel(
Hit,
LineStart,
LineEnd,
ECC_Visibility
);
if (!bHit) // 충돌 감지 안됐으면(공중에 있을 때) 중력속도 활성화
{
VelocityZ += Gravity * DeltaTime;
}
else // 감지 되면(바닥에 있을 때)
{
VelocityZ = 0;
}
AddActorLocalOffset(FVector(0, 0, VelocityZ * DeltaTime)); // 중력속도만큼 Z축으로 이동
}
ECC_Visibility와 Params
위처럼 구현하니 공중에 있을 때 중력 효과를 받아서 아래로 떨어지긴 하지만 중력속도가 무한대로 빨라져서 스페이스바를 꾹 눌러도 어느정도 높이로 오른 뒤 그 이후는 올라갈 수 없는 현상이 발생했다. 그래서 키를 입력받을 때는 중력효과가 발생하지 않도록 수정을 해야된다.
// MovablePawn.h
bool bHasMoveInput; // 키가 입력중인지 판단하는 변수
// MovablePawn.cpp
void AMovablePawn::Move(const FInputActionValue& value)
{
if (!Controller) return;
bHasMoveInput = true; // Move함수에서 true
AddActorLocalOffset({ value.Get<FVector>().X * Speed, value.Get<FVector>().Y * Speed, value.Get<FVector>().Z * 8});
}
// Tick함수
if(!bHasMoveInput) // Move함수가 호출이 안될 때(키 입력이 없을 때)
{
if (!bHit) // 충돌 감지 안됐으면(공중에 있을 때) 중력속도 활성화
{
VelocityZ += Gravity * DeltaTime;
}
else // 감지 되면(바닥에 있을 때) 중력 0
{
VelocityZ = 0;
}
}
AddActorLocalOffset(FVector(0, 0, VelocityZ * DeltaTime)); // 중력속도만큼 Z축으로 이동
bHasMoveInput = false; // Tick 함수의 마지막 줄에 false
이제 키를 누르면 bHasMoveInput이 true가 되어 중력 관련 로직이 실행이 되지 않고 키를 떼면 false가 되어 중력 관련 로직이 활성화가 된다.
현재 중력 적용이 될때 AddActorLocalOffset 함수를 이용해서 드론이 회전한 상태로 중력효과를 받게되면 바닥방향이 아닌 드론의 아래 방향으로 이동이 되는 문제가 발견되어 AddActorWorldOffset 함수로 수정했다.
// Tick 함수
AddActorWorldOffset(FVector(0, 0, VelocityZ * DeltaTime)); // 중력속도만큼 Z축으로 이동
중력 효과를 받는 도중에 키를 입력하면 VelocityZ가 초기화가 되지 않아서 떨어지면서 이동하는(제 속도를 못내는) 문제가 발생하여 키 입력을 받을 때(bHasMoveInput이 true일 때) VelocityZ를 0으로 초기화 했다.
// Tick 함수
if(!bHasMoveInput) // Move함수가 호출이 안될 때(키 입력이 없을 때)
{
if (!bHit) // 충돌 감지 안됐으면(공중에 있을 때) 중력속도 활성화
{
VelocityZ += Gravity * DeltaTime;
}
else // 감지 되면(바닥에 있을 때) 중력 0
{
VelocityZ = 0;
}
}
else // Move함수 호출될 때 (추가)
{
VelocityZ = 0;
}
이제 인공 중력 구현은 구현이 됐고 에어컨트롤 구현이 남았다.
에어컨트롤 구현
공중에 있을 때 지상 이동속도의 50%로 제한하고 속도가 서서히 감소하도록 구현을 했다.
이동 속도를 담을 Speed 변수를 선언하고 생성자에서 8.0으로 초기화 했다.
// MovablePawn.h
float Speed;
// MovablePawn.cpp
//생성자
Speed = 8.0f;
Move함수에서 중력 구현을 할 때 선언한 bool bHit 변수를 활용하여 지상과 공중을 판단했다
// Movable.cpp
// Move함수
if (bHit) // 지상에 있을 때
{
Speed = 8.0f;
}
else // 공중에 있을 때
{
if (Speed > 4.0f) // 4 초과일 때 서서히 감소
{
Speed *= 0.995f;
}
else // 4 이하가 되면 4 고정
{
Speed = 4.0f;
}
}