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);  
    } 
}

 

🟣오늘의 옵시디언 현황