I’m currently taking the course Big Game Project at Uppsala University – Campus Gotland, where the goal is to have, after 10 weeks, a working vertical slice of a game which might have the potential to become a product worth selling at a later stage.
We’re now six weeks into the production of the game Warpers and this time I’ll write about a small feature called “incremental rotation” or “rotation interpolation“. Say you have a top-down character which you want to have facing a particular direction. It will look really unnatural if the character immediately snaps to that direction. What you want to have it do is to rotate towards the target angle at an number of angles per frame basis. All characters in Warpers have this function and makes the game feel so much more polished.
How did we accomplish this behavior then? Well initially I thought that we could use the built in math function FMath::RInterpTo() which returns the interpolated Rotator between two rotations based on delta time and speed as inputs. But since Warpers is a top-down game where only the pitch axis is the one being rotated, this resulted in our characters being rotated on all three axes and the sprites in the game looked like paper cutouts being rotated in 3D space as in Paper Mario.
The solution was an old GML (Game Maker Language) script from my Game Maker 7.0 days. That when translated to C++ code looked like this:
float diff = FMath::Fmod(FMath::Fmod((wantedAngle - currentAngle), 360.0f) + 540.0f, 360.0f) - 180.0f; currentAngle += FMath::Sign(diff) * FMath::Min(FMath::Abs(diff), m_spinSpeed*delta); m_lastRotation = currentAngle;
The code above figure out whether to increase or decrease the angle in order to turn the least amount towards the target rotation. Here m_lastRotation is a member variable which keeps track on the current rotation value in degrees. This is needed because of how Unreal Engine automatically solves gimbal lock with rotations, and one downside to that is that the pitch value ends up between 90° and -90° in pitch. And since the sprites are rotated around the pitch axis you need to have a full 0° to 360° rotation. This is what the following code takes care of.
FRotator rotator = FRotator::ZeroRotator; rotator.Add(currentAngle, 0.f, 0.f); SetActorRotation(rotator);
The short explanation of the above code is that I initialize a FRotator as zero in each axis and then add the previously computed angle-change to the pitch component of the rotator. Lastly the character gets the desired rotation. By changing rotation through this method you skip the whole ordeal with the automatic gimbal lock countermeasure which would otherwise occur for E.g. using the Math::RInterpTo() function.
As of writing this the Unreal Engine API currently don’t have support for 2D rotations on any axis (that I know of) and this is the workaround that I find work best. But when such a feature is added at a later stage, it’s probably wise to use that method instead.
I hope that cleared some things up when it comes to how Warpers’ character rotation is handled. Next week I’ll write about some other part of Warpers. Until then, happy coding!
~Lead Designer and Programmer, Per “Gimmic” Johansson