Flipping the Player sprite with its CollisionShape2D

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

Hi,
Up until now I’ve used…
$AnimatedSprite.flip_h = true / $AnimatedSprite.flip_h = false
to flip the Player sprite.

However I’m using the free Kings and Pigs asset pack where the Player character has a large hammer.

enter image description here

Obviously the CollisionShape2D does not flip along with the $AnimatedSprite.

So instead I tried another method which was suggested online, scaling the Player with:

scale.x =  scale.y * 1
scale.x =  scale.y * -1

It does the trick, however there is an issue when the Player flips direction, he isn’t centred - the overall sprite is flipped which makes the character off-centre. This obviously causes a problem when standing on a platform ledge, he naturally falls off when you change direction.

I tried moving the Player’s animated sprite to be off-centre, but that doesn’t seem to work.

I need the Player sprite to stay fixed from his centre, not including the hammer.
Any ideas?

Here’s the script for reference:

extends KinematicBody2D

# Move Player Left/Right with Variable Jump Height


var myVelocity = Vector2() #Store vector coorinates in the variable myVelocity
var onGround = false

const PLAYERSPEED = 90
const GRAVITY = 15
const JUMPPOWER = -300
const JUMPLOW = -150
const FLOOR = Vector2(0,-1)


func _physics_process(delta):	
	
	myVelocity.x = 0
	
	# MOVE PLAYER LEFT/RIGHT
	if Input.is_action_pressed("ui_right"):
		myVelocity.x = PLAYERSPEED
		$AnimatedSprite.play("Walk")
		scale.x =  scale.y * 1
		#$AnimatedSprite.flip_h = false
	elif Input.is_action_pressed("ui_left"):
		myVelocity.x = -PLAYERSPEED
		$AnimatedSprite.play("Walk")
		scale.x =  scale.y * -1
		#$AnimatedSprite.flip_h = true
	else:
		myVelocity.x = 0
		if onGround == true:
			$AnimatedSprite.play("Idle")
		
	# JUMP		
	if Input.is_action_pressed("ui_up") && is_on_floor():
		myVelocity.y = JUMPPOWER
		
	# VARIABLE JUMP HEIGHT		
	if Input.is_action_just_released("ui_up"):
		myVelocity.y = -JUMPLOW	
		
		
	myVelocity.y += GRAVITY # Add gravity to the Player
	

	# Set if on the ground or not
	if is_on_floor():
		onGround = true
	else:
		onGround = false
		if myVelocity.y < 0:
			$AnimatedSprite.play("Jump")
		else:
			$AnimatedSprite.play("Fall")	
	
	
	myVelocity = move_and_slide(myVelocity, FLOOR) # Move Player 
:bust_in_silhouette: Reply From: JayH

Hi,

I found several users online suggesting using a Node2D as the parent of the AnimatedSprite and using that to flip instead.

One of the problems with using a Node2D as the parent of the AnimatedSprite is that the attached CollisionShape2D will no longer work - you get a warning. When in game the Player will fall through the platforms. I read elswhere online a similar suggestion.

My work-around was similar, instead of adding another Node2D as suggested, I just scaled the root node (Kinematic2D), e.g.

# MOVE PLAYER LEFT/RIGHT
if Input.is_action_pressed("ui_right"):
	myVelocity.x = PLAYERSPEED
	$AnimatedSprite.play("Walk")
	$".".scale.x =  scale.y * 1
	
	#$AnimatedSprite.flip_h = false
elif Input.is_action_pressed("ui_left"):
	myVelocity.x = -PLAYERSPEED
	$AnimatedSprite.play("Walk")
	$".".scale.x =  scale.y * -1
	#$AnimatedSprite.flip_h = true
else:
	myVelocity.x = 0
	if onGround == true:
		$AnimatedSprite.play("Idle")
:bust_in_silhouette: Reply From: godot_dev_

I has done this before. Below is scene tree setup I used:

Player (kinematicbody2d)

nodes_that_flip(Node2d)

sprite (Sprite2D)
collisionAreas (Node2D)

Hurtbox(Area2D)

CollisionShape

Hitbox(Area2D)

CollisionShape

BodyBox (Area2D)

CollisionShape

In this example, anytime I flip the character I do $"Player.nodes_that_flip".scale.x = $"Player.nodes_that_flip".scale.x*-1. This way the hurtbox and hitboxes stay properly attached to the sprite, but the bodybox used for stage collision detection (on a platform, for example) is never changed, and as such the bodybox always stays centered on the player. In this example, any node that should flip with the sprite (like particle effects) should be placed as a child of nodes_that_flip