How to handle directional change in KinematicBody2D?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Godont

I have an enemy character which walks around and switches directions when it bumps into a wall or cliff. It fires a laser in the direction it is facing if it sees the player character and has non-symmetric collision, so a simple

$AnimatedSprite.flip_h = true

won’t cut it for switching the character’s orientation.

This long and old issue thread seems to conclude that, due to a change (possibly a bug) that was introduced in the move from Godot 2 to Godot 3, using the naïve

scale.x = direction*scale.x

(where direction is 1 or -1 depending on whether the KinematicBody2D is facing to the right or left) won’t work. From the thread, a mysterious workaround is to execute

scale.x = direction*scale.x * sign(scale.y)

whenever you reorient the KinematicBody2D. This works for the character itself, but the healthbar above the character’s head flips and appears beneath the character when it changes direction. I can’t seem to force the healthbar back above the character by fiddling with the Healthbar’s scale properties.

I get that this may be a bug (in fact I think it certainly must be because, without ever modifying the KinematicBody2D’s y scale one of its children is apparently getting a vertical reflection), but I feel as though many developers must have encountered something like this and found work-arounds.

Does anyone know a work-around I can apply to prevent this vertical flipping of the character’s healthbar?

:bust_in_silhouette: Reply From: psear

As I understand, you are not supposed to mess with the scale property of physics bodies. I believe this is something that is aimed to be corrected in Godot 4, but for now I think there may be “safer” ways of accomplishing this task.

I have encountered similar issues, and a common work around is to have two collision objects, and to swap the objects depending on which direction the character is facing.

if facing_right:
    left_shape.disabled = true
    right_shape.disabled = false
    left_shape.disabled = false
    right_shape.disabled = true

Or to cut down on lines, you could use something like a ternary statement:

left_shape.disabled = true if facing_right else false
right_shape.disabled = !left_shape.disabled

It’s a bit messy, but might do what you’re hoping for.