Help with hitbox offset

Godot Version

v4.6.2.stable.official [71f334935]

Question

Making a top down ARPG. I’m trying to make my hitbox face the direction that the player is facing for my attack but when I load into a game and move, it just doesn’t face the right direction. It stays stuck on top of the player or just not even close to the player at all when I tried to fix it. What could I be doing wrong?

If you share code, please wrap it inside three backticks or replace the code in the next block:

extends CharacterBody2D


const SPEED = 300.0

var last_direction: Vector2 = Vector2.RIGHT
var is_attacking: bool = false
var hitbox_offset: Vector2

@onready var animated_sprite_2d: AnimatedSprite2D = $AnimatedSprite2D
@onready var sword_slash: AudioStreamPlayer2D = $SwordSlash
@onready var hitbox: Area2D = $Hitbox

func ready() -> void:
	
	# Initialize hitbox offset
	hitbox_offset = hitbox.position
	
func _physics_process(_delta: float) -> void:
	
	if Input.is_action_just_pressed("attack") and not is_attacking:
		attack()
	
	# Skip movement if player is attacking
	if is_attacking:
		velocity = Vector2.ZERO
		return
	
	process_movement()
	process_animation()
	move_and_slide()


#--------------------------------------------
#--------MOVEMENT AND ANIMATIONS-------------
#--------------------------------------------

func process_movement() -> void:
	
	var direction := Input.get_vector("left", "right", "up", "down")
	
	if direction != Vector2.ZERO:
		velocity = direction * SPEED
		last_direction = direction
		update_hitbox_offset()
	else:
		velocity = Vector2.ZERO
	


func process_animation() -> void:
	if is_attacking:
		return
	if velocity != Vector2.ZERO:
		play_animation("run", last_direction)
	else:
		play_animation("Idle", last_direction)


func play_animation(prefix: String, dir: Vector2) -> void:
	if dir.x != 0:
		animated_sprite_2d.flip_h = dir.x < 0
		animated_sprite_2d.play(prefix + "_right")
	elif dir.y < 0:
		animated_sprite_2d.play(prefix + "_up")
	elif dir.y > 0:
		animated_sprite_2d.play(prefix + "_down")



#----------------------------------------------------
#-----------ATTACKING AND COMBAT---------------------
#----------------------------------------------------

func attack() -> void:
	is_attacking = true
	sword_slash.play()   
	play_animation("attack", last_direction)
	


func _on_animated_sprite_2d_animation_finished() -> void:
		if is_attacking:
			is_attacking = false



#---------------------------------------------------
#-----------------HIT BOX OFFSET--------------------
#---------------------------------------------------

func update_hitbox_offset() -> void:
	var x := hitbox_offset.x
	var y := hitbox_offset.y
	
	match last_direction:
		Vector2.LEFT:
			hitbox.position = Vector2(-x, y)
		Vector2.RIGHT:
			hitbox.position = Vector2(x, y)
		Vector2.UP:
			hitbox.position = Vector2(y, -x)
		Vector2.DOWN:
			hitbox.position = Vector2(-y, x)

Matching a Vector2 may not work correctly, floating point values are rarely exactly equal. Try using if/else statements like you did with play_animation

how do I do that?

Your play animation function checks if the direction is less than zero for negative numbers, you could use the same format to try offsetting the hitbox.

func update_hitbox_offset() -> void:
	var x := hitbox_offset.x
	var y := hitbox_offset.y
	
	if last_direction.x != 0:
		hitbox.position = Vector2(x * signf(last_direction.x), 0)
	else:
		hitbox.position = Vector2(0, y * signf(last_direction.y))

Here’s me attempting to use math (i.e. signf) to reduce branches

Something else must be going wrong because when I implemented it, the hitbox stayed stuck on top again

it faces the proper direction when I loaded it in but just stays stuck the moment I moved and stays like that

Have you tried using a large number instead of that hitbox_offset variable?

func update_hitbox_offset() -> void:
	const OFFSET: float = 200
	if last_direction.x != 0:
		hitbox.position = Vector2(OFFSET * signf(last_direction.x), 0)
	else:
		hitbox.position = Vector2(0, OFFSET * signf(last_direction.y))

that just makes it only appear when looking to the right as well as just no longer on the player

fiddled with the values and it kind of works but off center

nvm just had to move some things around