extends CharacterBody2D
const SPEED = 700.0
const JUMP_VELOCITY = -900.0
@onready var sprite_2d = $Sprite2D
var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")
func _physics_process(delta):
if (velocity.x > 1 || velocity.x < -1):
sprite_2d.animation = "running"
else:
sprite_2d.animation = "default"
# Add the gravity.
if not is_on_floor():
velocity.y += gravity * delta
sprite_2d.animation = "jumping"
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = JUMP_VELOCITY
# Get the input direction and handle the movement/deceleration.
# As good practice, you should replace UI actions with custom gameplay actions.
var direction = Input.get_axis("left", "right")
if direction:
velocity.x = direction * SPEED
else:
velocity.x = move_toward(velocity.x, 0, 100)
move_and_slide()
var isLeft = velocity.x < 0
sprite_2d.flip_h = isLeft
Easy solution: Fix the sprite, make it so the character is always centered (add an extra transparent region on one side). That’s a rule number zero for flippable sprites.
Workaround for some designs: Add another collider and enable the correct one when changing direction. This is common when the character has different states (like crouching).
Fliping the sprite, having areas for both left and right, and enabling and disabling them if necesary based of char direction/velocity.
Or, which I prefer, doing everything for just one side (left, for instance) and scaling the entire object.
Something like:
var flipped := false
func flip():
if direction < 0 and !flipped:
flipped = true
scale.x *= -1
elif direction > 0 and flipped:
flipped = false
scale.x *= -1
This approach have some down sides. You may not want to flip under the character everithing always. But there are tweaks to avoid this kind of problems. I like this approach the most.
Like you said, if there are several states with different sprite sizing, having all colliders x2 is a bit ugly if you ask me.
Your code adapted to flip the character based on it velocity:
extends CharacterBody2D
const SPEED = 700.0
const JUMP_VELOCITY = -900.0
var flipped := false
@onready var sprite_2d = $Sprite2D
var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")
func _physics_process(delta):
if (velocity.x > 1 || velocity.x < -1):
sprite_2d.animation = "running"
else:
sprite_2d.animation = "default"
# Add the gravity.
if not is_on_floor():
velocity.y += gravity * delta
sprite_2d.animation = "jumping"
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = JUMP_VELOCITY
# Get the input direction and handle the movement/deceleration.
# As good practice, you should replace UI actions with custom gameplay actions.
var direction = Input.get_axis("left", "right")
if direction:
velocity.x = direction * SPEED
else:
velocity.x = move_toward(velocity.x, 0, 100)
flip()
move_and_slide()
func flip():
if velocity.x < 0 and !flipped:
flipped = true
scale.x *= -1
elif velocity.x > 0 and flipped:
flipped = false
scale.x *= -1
Okay, the hitbox is perfect and I love the fact that when they turn left it stays left now, but I have found something shameful, I have connected an AnimatedSprite2D to the character but have it called Sprite2D by accident, and when I turn, it’s teleporting my character like a mile away each time they turn left and right, is there something I should do that could change this? anything to do with offsetting? I’m very sorry for the confusion
Never do this. It will cause bugs on physics calculations. It works for a time, sure. But when starting complex things, it will bug a lot. Never scale collisions nodes.
The best solution is to center the sprite, so you will only flip the image.
i would not flip the whole character scene, just the visuals.
this can be done by putting all of the character’s visuals in a Node2D child named Visuals and flipping only that Visuals node.