3 methods for flipping your player character
Have you ever been in a situation where your player character was moving to the left - but facing to the right? I call it the "Moonwalk" effect, and in this article, we're gonna explore three different methods to ensure your player character always faces in the direction they are moving in!
The “Moonwalk” effect
Have you ever come across this issue?
When setting up the movement for our player character in a 2D platformer, or similar type of game, we often get to a point where we have our character moving (and maybe even animating) correctly, but it only seems to look right when they move in one direction , usually to the right.
No matter what direction we press in, and no matter what direction our character is moving in, they always face to the right.
Here’s the problem:
When we press left on our keyboard, our character moves to the left, but they still use the sprite (or animation) that has them facing to the right, hence leading to what I call the “Moonwalk” effect.
We need to address this mismatch between the direction our character is moving in, and the direction they are facing in.
What we do not want to do, is have to create separate animations for when our chracter is facing to the right and facing to the left.
Instead, we want to somehow flip our character horizontally whenever they change direction - so that no matter what direction they are moving in, they always face that way as well.
Flipping our character
In this article, we are going to explore three different methods for flipping our character to ensure they always face in the direction they are moving in.
TLDR:
If in doubt, use method 3, rotating the character around its Y-axis. This method works with animations and also flips raycasts.
Method 1: Flip the character’s sprite horizontally
Here’s the idea behind this method:
To flip the character, we flip their sprite on the X-axis using their sprite renderer’s
flipX
option.
In this method, we are using our character’s sprite renderer component. It provides a checkbox that allows us to flip our character’s sprite on the X-axis. This checkbox is accessible to us via the sprite renderer’s flipX
property (bool). This means we can set it in our code to decide which direction we want out character to face in. In particular, we want flipX
to be true
when our character is moving to the left, and we want it to be false
, when they are moving to the right.
I first came across this method when exploring Learn To Code By Making a 2D Platformer in Unity & C# by GamesPlusJames on Udemy. Here’s how it works in practice.
At the start of the game, we set the direction our character is facing in to 1 (meaning right), and get their sprite renderer component.
Then during our physics update, we do three things:
We calculate our character’s horziontal speed based on our player’s input.
We check if our character needs to be flipped: We multiply our character’s new horizontal speed with the direction our character is facing in - and check if the result is negative. If so, we know that our character is not facing in the direction they are moving in, and hence we need to flip them.
To flip them, we first flip their direction, then check what their corresponding flipX value needs to be, then apply that new value to their sprite renderer.
- We apply our character’s new velocity to their rigidbody.
// Method 1
public class PlayerMovement1 : MonoBehaviour
{
// (...)
// Reference to the character's sprite renderer component
private SpriteRenderer spriteRenderer;
// The direction in which the character is currently FACING
// NB: This may be different from the direction in which they are currently MOVING
private int direction;
//
private void Start()
{
// Get a reference to the character's sprite renderer component
spriteRenderer = GetComponent<SpriteRenderer>();
// Initialise the direction in which the character is currently facing
direction = 1;
}
// FixedUpdate is called once per physics step
private void FixedUpdate()
{
// 1) Calculate the character's horizontal speed component
float xSpeed = walkSpeed * playerInput.horizontal;
// 2) Ensure the character faces in the direction they are moving in
CharacterDirectionCheck(xSpeed);
// 3) Apply the new velocity to the character's rigidbody
rigidBody.velocity = new Vector2(
xSpeed,
rigidBody.velocity.y
);
}
// Ensure the character faces in the direction they are moving in
private void CharacterDirectionCheck(float xSpeed)
{
// If the sign of the character's horizontal speed
// is different from the sign of the direction they are facing in,
// then we need to flip the character to face the other direction.
if (xSpeed * direction < 0.0f)
{
// Flip the direction the character is facing in
direction *= -1;
// Check if we need to flip the character's sprite
bool flipX = (direction < 0.0f)
? true
: false;
// Apply the flip to the sprite renderer
spriteRenderer.flipX = flipX;
}
}
NB: You may be wondering why I use the slightly more complex if (xSpeed * direction < 0.0f)
with a second check inside, instead of the simpler, single if (xSpeed < 0.0f)
check with an else statement that might initially come to mind. It’s because the latter approach would introduce a small bug, where if the character moved to the left, but then stopped moving, they would change to facing right, instead of still facing left.
While it may seem easy enough, this method has a big disadvantage. If our character uses any horizontal raycasts, for example to detect walls (for wall jumps) or ledges (for ledge grabs), then those rays are not going to be flipped by this method. This is because we are only flipping our character’s sprite, but not the character itself.
Method 2: Flip the sign of the character’s horizontal scale
Here’s the idea behind this method:
To flip the character, we invert the sign of their scale on the X-axis using their transform’s scale component.
If I remember correctly, I first came accross this method when working my way through the TileVania section of Complete C# Unity Developer 2D: Learn to Code Making Games by Ben T. & Rick on Udemy, and then again when working through Create A 2D Platformer - Unite Berlin Training Day. Here’s how it works in practice.
At the start of the game, we set the direction our character is facing in to 1 (meaning right), and record their original x-scale.
Then during our physics update, we do three things:
We calculate our character’s horziontal speed based on our player’s input.
We check if our character needs to be flipped: We multiply our character’s new horizontal speed with the direction our character is facing in - and check if the result is negative. If so, we know that our character is not facing in the direction they are moving in, and hence we need to flip them.
To flip them, we first flip their direction, then record their current scale, then apply their new direction to that scale.
- We apply our character’s new velocity to their rigidbody.
// Method 2
public class PlayerMovement2 : MonoBehaviour
{
// (...)
// The character's original scale on the x-axis
private float originalXScale;
// The direction in which the character is currently FACING
// NB: This may be different from the direction in which they are currently MOVING
private int direction;
//
private void Start()
{
// Record the character's original x-scale
originalXScale = transform.localScale.x;
// Initialise the direction in which the character is currently facing
direction = 1;
}
// FixedUpdate is called once per physics step
private void FixedUpdate()
{
// 1) Calculate the character's horizontal speed component
float xSpeed = walkSpeed * playerInput.horizontal;
// 2) Ensure the character faces in the direction they are moving in
CharacterDirectionCheck(xSpeed);
// 3) Apply the new velocity to the character's rigidbody
rigidBody.velocity = new Vector2(
xSpeed,
rigidBody.velocity.y
);
}
// Ensure the character faces in the direction they are moving in
private void CharacterDirectionCheck(float xSpeed)
{
// If the sign of the character's horizontal speed
// is different from the sign of the direction they are facing in,
// then we need to flip the character to face the other direction.
if (xSpeed * direction < 0.0f)
{
// Flip the direction the character is facing in
direction *= -1;
// Record the character's current scale
Vector3 scale = transform.localScale;
// Set the character's X-scale to be their original scale
// times the direction they are facing in
scale.x = originalXScale * direction;
// Apply the new scale to the character's transform
transform.localScale = scale;
}
}
This method seems to be popular with beginners. However, I came across a big disadvantage. As soon as we add animations (via the Animator) into the mix, it seems that those animations overwrite our character’s scale, hence making our efforts come to nought.
Method 3: Rotate the character around its Y-axis
Here’s the idea behind this method:
To flip the character, we rotate them by 180 degrees around the Y-axis using the their transform’s rotation property.
This is a method I discovered by searching. I believe it is the best out of the three methods discussed here. Here’s how it works in practice.
At the start of the game, we set the direction our character is facing in to 1 (meaning right).
Then during our physics update, we do three things:
We calculate our character’s horziontal speed based on our player’s input.
We check if our character needs to be flipped: We multiply our character’s new horizontal speed with the direction our character is facing in - and check if the result is negative. If so, we know that our character is not facing in the direction they are moving in, and hence we need to flip them.
To flip them, we first flip their direction, then check what their corresponding rotation around the Y-axis needs to be, then apply their new rotation.
- We apply our character’s new velocity to their rigidbody.
// Method 3
public class PlayerMovement3 : MonoBehaviour
{
// (...)
// The direction in which the character is currently FACING
// NB: This may be different from the direction in which they are currently MOVING
private int direction;
//
private void Start()
{
// Initialise the direction in which the character is currently facing
direction = 1;
}
// FixedUpdate is called once per physics step
private void FixedUpdate()
{
// 1) Calculate the character's horizontal speed component
float xSpeed = walkSpeed * playerInput.horizontal;
// 2) Ensure the character faces in the direction they are moving in
CharacterDirectionCheck(xSpeed);
// 3) Apply the new velocity to the character's rigidbody
rigidBody.velocity = new Vector2(
xSpeed,
rigidBody.velocity.y
);
}
// Ensure the character faces in the direction they are moving in
private void CharacterDirectionCheck(float xSpeed)
{
// If the sign of the character's horizontal speed
// is different from the sign of the direction they are facing in,
// then we need to flip the character to face the other direction.
if (xSpeed * direction < 0.0f)
{
// Flip the direction the character is facing in
direction *= -1;
// Calculate how many degrees the character needs to be rotated
// around the Y-axis to face in that direction
int rotation = (direction < 0.0f)
? 180
: 0;
// Apply the new rotation to the character's transform
transform.eulerAngles = new Vector3(0, rotation, 0);
}
}
Conclusion
In this article, we have explored three different methods for flipping our character to ensure they always face in the direction they are moving in.
My recommendation:
If in doubt, use method 3, rotating the character around its Y-axis. This method works with animations and also flips raycasts.