0
\$\begingroup\$

For the sake of getting precise position, I think I need you to clarify whether or not the tutorial calculation is incorrect and my calculation is correct.

Assume we want to move an Actor up and down according to \$f(t)=\sin(t)\$.

Tutorial Version

It is quoted from Unreal Engine Programming Quick Start:

float DeltaHeight = (FMath::Sin(RunningTime + DeltaTime) - FMath::Sin(RunningTime));

My Version

float DeltaHeight = (FMath::Sin(RunningTime) - FMath::Sin(RunningTime-DeltaTime));

Edit

I think I have to quote the whole Tick function:

void AFloatingActor::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

    FVector NewLocation = GetActorLocation();
    FRotator NewRotation = GetActorRotation();
    float RunningTime = GetGameTimeSinceCreation();

    // The declaration and initialization of 
    // float DeltaHeight goes here.

    NewLocation.Z += DeltaHeight * 20.0f;       //Scale our height by a factor of 20
    float DeltaRotation = DeltaTime * 20.0f;    //Rotate by 20 degrees per second
    NewRotation.Yaw += DeltaRotation;
    SetActorLocationAndRotation(NewLocation, NewRotation);
}
\$\endgroup\$
2
  • \$\begingroup\$ As you are preforming the time step from $t$ to $t+h$, it seems consistent that you use the difference $f(t+h)-f(t)$. \$\endgroup\$ Oct 24 '21 at 20:04
  • \$\begingroup\$ @LutzLehmann: But GetGameTimeSinceCreation() is t rather than t+DeltaTime. \$\endgroup\$ Oct 24 '21 at 22:44
1
\$\begingroup\$

Both of these approaches are correct in the sense that they will both accomplish the stated goal of moving the character up and down in a sine wave.

The difference is that your version will have the character hitting the peak of the wave at every time \$t = i \frac \pi 2 + \frac {\Delta t} 2\$ for integer values of \$i\$, and the tutorial version will have the character hitting the peak at every time \$t = i \frac \pi 2 - \frac {\Delta t} 2\$.

(These are the points at which either formulation of the DeltaHeight formula will evaluate to zero while the contributing sine functions have positive values)

This is the difference of a single frame, and will not generally be perceptible in gameplay - especially if there's no visible clock or other oscillation in the game to compare the timing against for synchronization.

Both of these methods are also susceptible to drift over time due to accumulating rounding errors. If you want to ensure the sine wave is followed exactly, you can store a separate middleHeight value and then set:

NewLocation.Z = middleHeight + 20.0f * FMath::Sin(RunningTime);

This will peak exactly at \$t = i \frac \pi 2\$, and minimize drift until RunningTime becomes very very large.

\$\endgroup\$
4
  • \$\begingroup\$ I can also do DeltaHeight = DeltaTime * FMath::Cos(RunningTime), right? \$\endgroup\$ Oct 21 '21 at 0:58
  • 1
    \$\begingroup\$ That's an approximation that assumes that the rate of change of FMath::Sin is constant over the interval DeltaTime, so you'll drift further when DeltaTime is large. \$\endgroup\$
    – DMGregory
    Oct 21 '21 at 1:02
  • \$\begingroup\$ Thank you very much! \$\endgroup\$ Oct 21 '21 at 1:11
  • \$\begingroup\$ It means that middleHeight (that should be MiddleHeight to conform to UE conventions) must be a member variable and initialized in BeginPlay() as MiddleHeight=GetActorLocation().Z;. \$\endgroup\$ Oct 21 '21 at 2:03

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .