Dev./UE 언리얼 엔진
[TIL_250124] Tick 함수로 Actor의 Transform 조정하기 (2)
raindrovvv
2025. 1. 24. 20:20
💭회고
액터의 변형 중에서 위치 변화, 회전 변화까지는 어렵지 않게 구현했는데...
스케일 변화에서 꽤나 막혔다.
[단계별 트러블]
1. 액터가 사라졌다.
2. 액터가 계속 커지기만 한다.
...
🗺️마인드맵
📒학습 내용
TimeElaped와 DeltaTime 이해
1. `DeltaTime` : 게임 엔진에서 각 프레임이 렌더링 되는데 걸리는 시간을 초단위로 나타냄
➡️FPS(Frame Per Second) 일정 치 않을 때 속도를 보정하기 위해 사용!
- 게임이 60 FPS로 실행되면 델타타임은 약 1/60초
- " 30FPS " 약1/30초
2. `TimeElapsed` : 매 프레임마다 델타타임을 더해 게임이 실행된 총 시간을 측정하거나 특정 타이머를 구현할 때 활용.
float TimeElapsed = 0.f
void Tick(float DeltaTime){
TimeElapsed += DeltaTime;
if(TimeElapsed >= 5.f){ // 5초 이상일 때 <어떤 메서드> 수행
PerformAction(); //<어떤 메서드>
TimeElapsed = 0.f; //초기화
}
}
> 이거 왜 많이 쓰일까?
1. 프레임 속도에 관계없이 동일한 속도를 보장.
2. 주기적인 이벤트 처리
- 1) 반복되는 동작이나 시간에 따라 달라지는 상태를 구현할 때 유용
- 2) 물리적인 흔들림, **점프 효과**, 조명 변화 등 다양하게 응용.
- 3) 부드러운 애니메이션 : 천천히 객체의 위치나 크기를 변경.
🌟 float SinValue = FMath::Sin(TimeElapsed);
3. 시간 기반 조건 이벤트 처리
- 특정 시간이 지나면 이벤트 발생 시키게 하거나 게임이 실행된 총 시간 추적 가능 ➡️ 폭발, 생성 등
> if(TimeLapsed >= MaxDuration){EndGame();}
> [Warning]
타임랩스가 너무 커질 경우, 숫자 범위를 초과하거나 불필요한 계산을 할 수 있으니 방지하기 위해서
- 적절히 초기화하고
- 제한을 두는 것이 좋다.
위치 변형
void AItem::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
TimeElapsed += DeltaTime; // 경과 시간 업데이트
// 1. Z축 위치 변경 (둥둥)
if (!FMath::IsNearlyZero((SpeedZ)))
{
// 현재 위치 가져오기
FVector CurrentLocation = GetActorLocation();
// Z축 방향으로 이동
CurrentLocation.Z += FMath::Sin(TimeElapsed) * SpeedZ * DeltaTime;
// 새로운 위치를 저장
SetActorLocation(CurrentLocation);
}
}
회전 변형
void AItem::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
TimeElapsed += DeltaTime;
// 1. Z축 위치 변경 (둥둥)
if (!FMath::IsNearlyZero((SpeedZ)))
{
//현재 위치 가져오기
FVector CurrentLocation = GetActorLocation();
CurrentLocation.Z += FMath::Sin(TimeElapsed) * SpeedZ * DeltaTime; // Z축 방향으로 이동
SetActorLocation(CurrentLocation); // 새로운 위치를 저장
}
// 2. 일정 속도로 Yaw 회전, RotationSpeed
if (!FMath::IsNearlyZero((RotationSpeed)))
{
FRotator CurrentRotation = GetActorRotation();
CurrentRotation.Yaw += RotationSpeed * DeltaTime;
SetActorRotation(CurrentRotation);
}
}
스케일 변형
🚨트러블 슈팅
// 3. 스케일 변경
if (!FMath::IsNearlyZero((ScaleFreq)))
{
FVector CurrentScale3D = GetActorScale3D();
float ScaleChange = FMath::Sin(TimeElapsed) * ScaleFreq * DeltaTime;
SetActorScale3D(CurrentScale3D);
}
🐞 BUG
문제 : 액터가 걍 사라져버렸다.
뭘까...?
- 조사 결과 : 스케일이 음수 값일 수가 없는데, Sin은 `-1~1` 사이 값을 반환하므로 버그 발생.
- 음수 값을 방지하려면 FMath::Abs를 사용해야 한다.
그리고 기본 스케일 값을 적용해야 하니까, `1.0f +`로 기본값을 유지해야 한다.
if (!FMath::IsNearlyZero((ScaleFreq)))
{
FVector CurrentScale3D = GetActorScale3D();
float ScaleChange = 1.0f + (FMath::Abs(FMath::Sin(TimeElapsed)) * ScaleFreq * DeltaTime);
CurrentScale3D *= ScaleChange;
SetActorScale3D(CurrentScale3D);
}
이번에 사라지는 것은 잡았는데... 액터가 계속 커지기만 한다.
사인 함수의 기본 주기
사인 함수(`FMath::Sin`)의 기본 주기는 `2π`
- 즉, `0`에서 `2π`까지 변화하면 사인 함수는 한 번의 완전한 주기(파동)를 생성.
- 입력 값이 `0 → π → 2π`로 증가할 때:
- `0`에서 시작 → `1`(최댓값) → `0` → `-1`(최솟값) → 다시 `0`.
✅해결
DeltaTime 제거
누적 변화 제거 : CurrentScale3D *= ScaleChange; ➡️ FVector Newscale = Scale * ScaleChange;
void AItem::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
TimeElapsed += DeltaTime;
// 1. Z축 위치 변경 (둥둥)
if (!FMath::IsNearlyZero((SpeedZ)))
{ FVector CurrentLocation = GetActorLocation(); //현재 위치 가져오기
CurrentLocation.Z += FMath::Sin(TimeElapsed) * SpeedZ * DeltaTime; // Z축 방향으로 이동 변화
SetActorLocation(CurrentLocation); // 새로운 위치를 저장
}
// 2. 일정 속도로 Yaw 회전, RotationSpeed
if (!FMath::IsNearlyZero((RotationSpeed)))
{ FRotator CurrentRotation = GetActorRotation();
CurrentRotation.Yaw += RotationSpeed * DeltaTime; // 회전 변화
SetActorRotation(CurrentRotation);
}
// 3. 스케일 변경
if (!FMath::IsNearlyZero((ScaleFreq)))
{ float ScaleChange = FMath::Abs(FMath::Sin(TimeElapsed * PI * ScaleFreq)) * 0.5f + 1.0f;
FVector Newscale = Scale * ScaleChange;
SetActorScale3D(Newscale);
}
}