2026-04-14 Unreal 5 과제6 — 회전 발판 & 움직이는 장애물
목차
설계 방식
단일 C++ 베이스 클래스에 bool 변수로 회전/이동 동작을 분기. ARotatingPlatform, AMovingPlatform 자식 클래스에서 기본값만 오버라이드.
핵심 구조
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| // 회전
if (bShouldRotate)
AddActorLocalRotation(FRotator(0.f, RotationSpeed * DeltaTime, 0.f));
// 이동 (왕복)
if (bShouldMove)
{
CurrentOffset += MoveDir * MoveSpeed * DeltaTime;
if (FMath::Abs(CurrentOffset) >= MaxRange)
{
MoveDir *= -1.f;
CurrentOffset = FMath::Sign(CurrentOffset) * MaxRange;
}
// EMoveAxis(X/Y/Z)에 따라 위치 적용
SetActorLocation(NewLocation);
}
|
EMoveAxis 열거형
에디터 Details 패널에서 드롭다운으로 이동 축 선택.
1
2
3
4
5
6
7
| UENUM(BlueprintType)
enum class EMoveAxis : uint8
{
X UMETA(DisplayName = "X (앞뒤)"),
Y UMETA(DisplayName = "Y (좌우)"),
Z UMETA(DisplayName = "Z (상하)")
};
|
자식 클래스
1
2
3
4
5
6
7
| // ARotatingPlatform 생성자
bShouldRotate = true;
bShouldMove = false;
// AMovingPlatform 생성자
bShouldRotate = false;
bShouldMove = true;
|
| 클래스 | 역할 | 기본 활성 |
|---|
| ABasePlatformActor | 회전 + 이동 로직 전체 보유 | 둘 다 false |
| ARotatingPlatform | 회전 전용 | bShouldRotate = true |
| AMovingPlatform | 이동 전용 | bShouldMove = true |
동작 사이클
발판이 일정 시간 후 사라지고, 일정 시간 후 복구되는 사이클 반복.
1
2
3
4
| BeginPlay
└→ [ActiveDuration 후] DeactivatePlatform (숨김 + 콜리전 제거)
└→ [InactiveDuration 후] ActivatePlatform (복구)
└→ [ActiveDuration 후] DeactivatePlatform ... (반복)
|
핵심 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| void ATimerPlatform::DeactivatePlatform()
{
SetActorHiddenInGame(true);
SetActorEnableCollision(false);
// 일회성 타이머 → ActivatePlatform 호출
GetWorld()->GetTimerManager().SetTimer(
InactiveTimerHandle, this,
&ATimerPlatform::ActivatePlatform,
InactiveDuration, false
);
}
void ATimerPlatform::ActivatePlatform()
{
SetActorHiddenInGame(false);
SetActorEnableCollision(true);
// 다시 DeactivatePlatform 예약 (사이클 유지)
GetWorld()->GetTimerManager().SetTimer(
ActiveTimerHandle, this,
&ATimerPlatform::DeactivatePlatform,
ActiveDuration, false
);
}
|
SetTimer(..., false) 일회성으로 서로 호출 → 정상 사이클 동작
RandomSpawner — SpawnActor + 랜덤 도전과제
설계
BeginPlay: 플레이어 위치 기준으로 초기 발판 N개를 1초 간격 타이머로 순차 스폰Tick: 플레이어가 마지막 발판 800cm 이내 접근 시 추가 배치 재시작
X축 앞 방향 스폰
1
2
3
4
5
6
7
| float ForwardDist = FMath::RandRange(MinSpawnDistance, MaxSpawnDistance);
float LateralDist = FMath::RandRange(-MaxSpawnDistance * 0.4f, MaxSpawnDistance * 0.4f);
float Height = FMath::RandRange(-HeightVariation, HeightVariation);
SpawnLocation.X += ForwardDist; // 항상 앞으로
SpawnLocation.Y += LateralDist; // 좌우 분산
SpawnLocation.Z += Height;
|
랜덤 속성 부여
1
2
3
4
| NewPlatform->RotationSpeed = FMath::RandRange(30.f, 150.f);
NewPlatform->MoveSpeed = FMath::RandRange(100.f, 350.f);
NewPlatform->MaxRange = FMath::RandRange(150.f, 400.f);
NewPlatform->MoveAxis = static_cast<EMoveAxis>(FMath::RandRange(0, 1));
|
캐릭터 스탯 기준 거리 설정
JumpZVelocity=700, MaxWalkSpeed=500 기준으로 최대 점프 수평 거리 ~700cm.
| 항목 | 값 |
|---|
| MaxSpawnDistance | 550cm |
| SpawnInterval | 2초 |
낙사 리스폰 — Character Tick
구현 방식
캐릭터 Tick에서 Z 좌표 체크 → 기준 이하면 시작 위치로 순간이동.
1
2
3
4
5
6
7
8
9
10
| void ANBC_AssignmentCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (GetActorLocation().Z < FallDeathZ)
{
SetActorLocation(RespawnLocation);
GetCharacterMovement()->Velocity = FVector::ZeroVector;
}
}
|
UPROPERTY로 에디터 조정
1
2
3
4
5
| UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Respawn")
float FallDeathZ; // 기본값 -500.f
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Respawn")
FVector RespawnLocation; // 기본값 (0, 0, 90)
|
Velocity = FVector::ZeroVector 로 낙하 속도 초기화 → 리스폰 후 튕김 방지