+2 votes

EDIT - Never Mind - I didn't google enough the first time. Apparently this is a known behavior, but I'd hesitate to call it expected or correct.

https://github.com/godotengine/godot/issues/21849

I have a KinematicBody2D scene with an AnimatedSprite child. Previously, in order to make the character face the opposite direction, I changed the scale of the AnimatedSprite to -1 if the character was facing that direction. However, I recently added a another child node with a RayCast2D and some Particles2D that always face forward, so I decided to change the Scale of the whole KinematicBody2D instead of the AnimatedSprite so that the Sprite and the RayCast2D/ Particles2D would be facing the correct direction.

This system works the same so far when the character is facing right (positive x scale) but exhibits strange behavior when the character is facing left (negative x scale). The whole character (Sprite and Particles) appears to flip back and forth horizontally each frame. Upon further inspection, I have narrowed the issue to when I call move_and_slide_with_snap and the end of my _phyisics_process method.

Immediately before I call move_and_slide_with_snap on the first loop facing left, my body's scale is (-1,1) as I expect. However, when I return from that method call, both signs have flipped, and the scale is (1,-1). At the start of the next loop, I change just the x component of the scale to -1 (because the character's state is facing left) and immediately before the next move_and_slide_with_snap call, the scale is (-1, -1) (I have never touched the y component of the scale.) Immediately after the move_and_slide_with_snap call, the scale is (1,1) and the cycle continues.

Should move_and_slide_with_snap have a side effect on the body's scale? Is setting the body's x scale negative not an appropriate way to flip the whole node and children horizontally? Does anyone have any insight here?

Godot version 3.2.3.stable.mono.official
in Engine by (16 points)

1 Answer

+1 vote

Yeach, you can do this. With separate boolean variable. I use what solution:

var  changed_scale = false

func _physics_process(delta):
    if Input.is_action_pressed("player_left"):
        if (!changed_scale):
            scale.x=-1.0
            changed_scale=true
    elif Input.is_action_pressed("player_right"):
        if (changed_scale):
            scale.x=-1.0
            changed_scale=false

Why variable, not checking "scale"? Because "scale" isn't properly represents real scale of object for some reason. And transform.get_scale().x does the same thing, I'm checked it recently.

Physics work properly, by the way.

Looks like in engine code, variable multiplie old value by new. I find something (116 line) in engine code, what maybe causes what, but I'm not sure.

by (22 points)
edited by

UPD: I find a bit better solution. For better understanding read this tutorial from documentation.

var h_scale = true

func _physics_process(delta):
    if <condition to change scale to left> && !h_scale:
        <Node2D>.transform.x *= -1.0
        h_scale = true
    elif <condition to change scale to right> && h_scale:
        <Node2D>.transform.x *= -1.0
        h_scale = false

    if str(<Node2D>.transform.x.x) == "-0": <Node2D>.transform.x.x=0
    if str(<Node2D>.transform.x.y) == "-0": <Node2D>.transform.x.y=0
    if str(<Node2D>.transform.y.x) == "-0": <Node2D>.transform.y.x=0
    if str(<Node2D>.transform.y.y) == "-0": <Node2D>.transform.y.y=0

#<Node2D> - it's any node what you need to change scale

Why it may help you: here

Wow, thanks. This was driving me crazy.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.