I want to flip my character on the horizontal axis, but what's the best way?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Bleenx
:warning: Old Version Published before Godot 3 was released.

I’ve tried to use the set_flip_h in my script, but it says it’s nonexistent, so I guess I need to call the function somewhere, or create it? I’m also guessing in order to use that I need to grab the sprite node that’s a child of the Rigidbody2D?

I’ve also tried to just set the scale to -1 when going left, but it makes the character erratic and scale back and forth. Does anyone have a good way of flipping the character on the horizontal axis? Would creating a custom function to scale the character be the best way and then call it when I need it?

Any suggestions would rock from you guys. Thanks!

:bust_in_silhouette: Reply From: nokungfu

There may be a better way, but I currently have my script attached to my KinematicBody2D with the sprite as a child, and when left:

set_scale(Vector2(-1,1))

when right:

set_scale(Vector2(1,1))

This flips all of the children, including my CollisionShape2D that is slightly off center.

I tried this but my player acts funky when I try to move it. The code to move my character is this:

if rightButton:
	set_axis_velocity(Vector2(moveSpeed, 0))
elif leftButton:
	set_axis_velocity(Vector2(-moveSpeed, 0))
else:
	set_axis_velocity(Vector2(0, 0))

Should I use an & operator in this code or would I need to write the code differently to move my character and flip it?

Bleenx | 2016-05-13 14:44

:bust_in_silhouette: Reply From: Gokudomatic2

Aside using set_scale, you can set the transform (which does exactly the same thing):

set_transform(Vector2(-1,0),Vector2(0,1),get_pos())
:bust_in_silhouette: Reply From: tiernich

In a recente project i created the function:

var Direction = "Left"

func ChangeDirection():
    if Direction == "Left":
	    get_node( "Sprite" ).set_flip_h( false )
	    Direction = "Right"
    elif Direction == "Right":
	    get_node( "Sprite" ).set_flip_h( true )
	    Direction = "Left"

so, in any part of the program, call ChangeDirection, change the sprite of the object. You can improve this to have arguments and other parameters if you wish

This is my movement function:

func Movement():
	var leftButton = Input.is_action_pressed("leftButton")
	var rightButton = Input.is_action_pressed("rightButton")
	
	if rightButton:
		set_axis_velocity(Vector2(moveSpeed, 0))
	elif leftButton:
		set_axis_velocity(Vector2(-moveSpeed, 0))
	else:
		set_axis_velocity(Vector2(0, 0))

Where would I call the ChangeDirection function? I can’t seem to get it to flip no matter what I do. Should I rewrite my movement code?

Bleenx | 2016-05-13 17:33

ok, add the line:

if rightButton:
    get_node( "Sprite" ).set_flip_h( false ) #this line
    ...

remember to change the path for the sprite and if the direction is wrong change false to true.

than tell me if works

tiernich | 2016-05-13 17:54

That worked! I was trying to add an “&” operator for some silly reason. My final movement code looked like this:

# Player Movement Control (left and right)---------------------|
func Movement():
	var leftButton = Input.is_action_pressed("leftButton")
	var rightButton = Input.is_action_pressed("rightButton")
	
	if rightButton:
		set_axis_velocity(Vector2(moveSpeed, 0))
		get_node( "playerSprite" ).set_flip_h( false )
	elif leftButton:
		set_axis_velocity(Vector2(-moveSpeed, 0))
		get_node( "playerSprite" ).set_flip_h( true)
	else:
		set_axis_velocity(Vector2(0, 0))

Thanks a lot for your help. I had the right idea but was doing it completely wrong. :slight_smile:

Bleenx | 2016-05-13 17:59

No problem :smiley:

tiernich | 2016-05-13 18:03

:bust_in_silhouette: Reply From: Rob Blob

I want to provide an answer for Godot 3 users who are stumbling upon this page in 2018, like I did:

You can accomplish flipping an entire Node2d and all its children through use of apply_scale.

Here is how I have horizontal flipping set up for my platform game:

const DIRECTION_RIGHT = 1
const DIRECTION_LEFT = -1
var direction = Vector2(DIRECTION_RIGHT, 1)

func set_direction(hor_direction):
    if hor_direction == 0:
        hor_direction = DIRECTION_RIGHT # default to right if param is 0
    var hor_dir_mod = hor_direction / abs(hor_direction) # get unit direction
    apply_scale(Vector2(hor_dir_mod * direction.x, 1)) # flip
    direction = Vector2(hor_dir_mod, direction.y) # update direction

Then, when needed, just call:

set_direction(DIRECTION_LEFT)

or:

set_direction(DIRECTION_RIGHT)

The Node2d will then flip if it is facing the opposite direction of the parameter.

The nice thing about this implementation is that the var direction can be applied to dependent scenes, such as when determining the direction of a projectile:

func create_projectile():
    var projectile = PROJECTILE_SCENE.instance()
    projectile.direction = direction
    get_parent().add_child(projectile)

Note the above function does not define PROJECTILE_SCENE or cover translating it to the correct coordinates - it is only to show the use of direction.

:bust_in_silhouette: Reply From: GreasyMcBeef

Finding this question years later when wondering the same thing myself, I found the following useful macros under part of Transform2D:

FLIP_X = Transform2D( -1, 0, 0, 1, 0, 0 )
Transform2D with mirroring applied parallel to the X axis.

FLIP_Y = Transform2D( 1, 0, 0, -1, 0, 0 )
Transform2D with mirroring applied parallel to the Y axis.

These can be use to flip an object and all its children in a way similar to the one Rob describes in his answer, but in the following single line:


transform *= Transform2D.FLIP_X

and the funny thing about @Rob Blob is that the only code working is :

apply_scale(Vector2(-1, 1))

and all the other stuff are excessive!

javadmajidi | 2020-11-02 17:44

A disclaimer: be careful when trying to change your character’s rotation after modifying its transform. The rotation value is adjusted based on the transform at each processing step.

GreasyMcBeef | 2020-11-13 00:35

:bust_in_silhouette: Reply From: TGMG

Sometimes simple is best, just stick to set_flip_h(), I’ve been using scale.x * -1 in order to reflect the sprite but this approach modifies de value of rotation_degrees and makes everything more complicated.

I found this out the hard way… My rotation was all screwy and had no idea why and after hours of debugging it hit me. Yes just use set_flip_h(). Less headache down the line.

fobmasta | 2021-10-09 21:17

:bust_in_silhouette: Reply From: k3nzngtn

This works for me:

if(_velocity.x > 0):
	scale.x = scale.y * -1
elif(_velocity.x < 0):
	scale.x = scale.y * 1

Thank you very much!

Only this worked for me, and i have no idea why… if someone could explain, i will appreciate!!

gloostao | 2023-01-31 00:53

THIS WORKS!!! Thank you so much, i’m crying rn

JohnCoderunner3000 | 2023-03-16 03:42