2D TopDown Movement and Animation hiccups

Godot Version

4.6.2 Stable

Question

Godot beginner here, go easy on me. Thanks in advance.

Issue 1: If I’m moving Right and then add Up and Down, everything behaves as expected but if I am facing Right (no velocity) and just press up or down, the sprite moves up and down and then flips to face the Left once I stop pressing the button. Additionally Left and Right trigger the animations just fine but Up or Down by themselves stay in the idle animation and just slide Up or Down.

To note: My player is separated into three AnimatedSprite2Ds: Body, Head, and Gun

Issue 2: Input: Down + Right = player moving down and right (diagonally) and the PlayerHead and PlayerGun rotate to match the angle. Continue pressing Down but switch to Left = the same thing, to the left, as wanted.
But if I press Sprint while doing the same thing, the player will move down + left but the head and gun rotate to point Up and Right.

Issue 3:
My code for rotating the head and gun to match the angle works on the Left, Right, and Diagonals but doesn’t do anything for just straight Up or Down. I feel like there’s a connection but I can’t see it.

I’m stumped.

My goal is to have 8 directions. The body can face in 2 directions, left and right. The head and gun can face in 2 directions, left and right, but can be rotated to “point” in all8 directions. I had this working at one point but between adding actual left frames, ditching flip_h in the process and trying to implement new features and systems, I completely broke it and had to start fresh. So here I am.

I do not want to post my code for anyone to see but I need some help so I’m sorry for anyone who sees it lol I’ve been at this project and others (basically the same one just restarted over and over) for like 10-12 hours a day for a solid week or so now so I’m willing to be that it’s a simple fix but I can’t look at code anymore, I’m positive that my brain is actually changing what I see to look right at this point lol

Here’s a video showcasing the issues. Pretty sure the quality is going to take a massive dive, so sorry in advance, hopefully it still gets the point across.

extends CharacterBody2D


var speed: int = 10
var speed_scale: float = 1.5
var direction: Vector2
var look_direction: Vector2 = Vector2.RIGHT
var is_sprinting: bool = false
var is_strafing: bool = false
var is_reloading: bool = false
var is_shooting: bool = false


func _physics_process(_delta: float) -> void:
	get_input()
	movement()
	move_and_slide()
	animation()

func get_input():
# DIRECTIONAL INPUT
#--------------------------------------------------------------
	direction = Input.get_vector("left", "right", "up", "down")
	if direction != Vector2.ZERO:
		velocity = direction * speed
		look_direction = direction
	else:
		velocity = Vector2.ZERO

# MOVEMENT INPUT
#--------------------------------------------------------------
	if Input.is_action_pressed("sprint"):
		is_sprinting = true
		velocity *= speed_scale
	else:
		is_sprinting = false

	if Input.is_action_pressed("strafe") and velocity !=Vector2.ZERO:
		is_strafing = true
		direction.x *= -1
		velocity.y = 0
	else:
		is_strafing = false

# ACTION INPUT
#--------------------------------------------------------------
	if Input.is_action_just_pressed("shoot"): #add shoot timer here
		print("shoot")
		shoot()

	if Input.is_action_just_pressed("reload") and not is_reloading:
		print("reloaded")
		reload()
		
func movement():
# SPRITE MOVEMENT-BASED ROTATION
#--------------------------------------------------------------
	#if LEFT and UP and is NOT Strafing
	if direction.x < 0 and direction.y < 0 and not is_strafing:
		$PlayerWeapon.rotation_degrees = 45
		$PlayerHead.rotation_degrees = 20
	#if LEFT and DOWN and is NOT Strafing
	elif direction.x < 0 and direction.y > 0 and not is_strafing:
		$PlayerWeapon.rotation_degrees = -45
		$PlayerHead.rotation_degrees = -20
	#if RIGHT and UP and is NOT Strafing
	elif direction.x > 0 and direction.y < 0 and not is_strafing:
		$PlayerWeapon.rotation_degrees = -45
		$PlayerHead.rotation_degrees = -20
	#if RIGHT and DOWN and is NOT Strafing
	elif direction.x > 0 and direction.y > 0 and not is_strafing:
		$PlayerWeapon.rotation_degrees = 45
		$PlayerHead.rotation_degrees = 20
	#if last dir_x was LEFT and we go down
	elif look_direction.x < 0 and direction.y == 1:
		$PlayerWeapon.rotation_degrees = -90
		$PlayerHead.rotation_degrees = -45
	#if last dir_x was RIGHT and we go down
	elif look_direction.x > 0 and direction.y == -1:
		$PlayerWeapon.rotation_degrees = -90
		$PlayerHead.rotation_degrees = -45
	elif look_direction.x > 0 and direction.y == 1:
		$PlayerWeapon.rotation_degrees = 90
		$PlayerHead.rotation_degrees = 45
	elif look_direction.x < 0 and direction.y == -1:
		$PlayerWeapon.rotation_degrees = 90
		$PlayerHead.rotation_degrees = 45
	#------------------------------------------------------------
	#rotation of the weapon sprite when strafing
	#------------------------------------------------------------
	#if LEFT and UP and IS Strafing
	elif direction.x < 0 and direction.y < 0 and is_strafing:
		$PlayerWeapon.rotation_degrees = 45
		$PlayerHead.rotation_degrees = 20
	#if LEFT and DOWN and IS Strafing
	elif direction.x < 0 and direction.y > 0 and is_strafing:
		$PlayerWeapon.rotation_degrees = -45
		$PlayerHead.rotation_degrees = -20
	#if RIGHT and UP and IS Strafing
	elif direction.x > 0 and direction.y < 0 and is_strafing:
		$PlayerWeapon.rotation_degrees = -45
		$PlayerHead.rotation_degrees = -20
	#if RIGHT and DOWN and IS Strafing
	elif direction.x > 0 and direction.y > 0 and is_strafing:
		$PlayerWeapon.rotation_degrees = 45
		$PlayerHead.rotation_degrees = 20
	#------------------------------------------------------------
	#this makes the rotation snap back to 0 when not pressing up or down
	else:
		$PlayerWeapon.rotation_degrees = 0
		$PlayerHead.rotation_degrees = 0

func animation():
	if is_shooting or is_reloading:
		return

	if velocity and not is_sprinting:
		if direction == Vector2.LEFT:
			$PlayerBody.play("walk_left")
			$PlayerWeapon.play("walk_left")
			$PlayerHead.play("walk_left")
		elif direction == Vector2.RIGHT:
			$PlayerBody.play("walk_right")
			$PlayerWeapon.play("walk_right")
			$PlayerHead.play("walk_right")
		elif direction.x < 0 and velocity.y != 0:
			$PlayerBody.play("walk_left")
			$PlayerWeapon.play("walk_left")
			$PlayerHead.play("walk_left")
		elif direction.x > 0 and velocity.y != 0:
			$PlayerBody.play("walk_right")
			$PlayerWeapon.play("walk_right")
			$PlayerHead.play("walk_right")

	if velocity and is_sprinting:
		if direction == Vector2.LEFT:
			$PlayerBody.play("run_left")
			$PlayerWeapon.play("run_left")
			$PlayerHead.play("run_left")
		elif direction == Vector2.RIGHT:
			$PlayerBody.play("run_right")
			$PlayerWeapon.play("run_right")
			$PlayerHead.play("run_right")

	if velocity == Vector2.ZERO:
		if look_direction.x > 0:
			$PlayerBody.play("idle_right")
			$PlayerWeapon.play("idle_right")
			$PlayerHead.play("idle_right")
		else:
			$PlayerBody.play("idle_left")
			$PlayerWeapon.play("idle_left")
			$PlayerHead.play("idle_left")

func shoot():
	is_shooting = true
	if look_direction.x > 0:
		$PlayerWeapon.play("shoot_right")
		$PlayerHead.play("shoot_right")
	elif look_direction.x < 0:
		$PlayerWeapon.play("shoot_left")
		$PlayerHead.play("shoot_left")
	await $PlayerHead.animation_finished
	await $PlayerWeapon.animation_finished
	is_shooting = false

func reload():
	is_reloading = true
	if look_direction.x > 0:
		$PlayerWeapon.play("reload_right")
		$PlayerHead.play("reload_right")
	elif look_direction.x < 0:
		$PlayerWeapon.play("reload_left")
		$PlayerHead.play("reload_left")
	await $PlayerHead.animation_finished
	await $PlayerWeapon.animation_finished
	is_reloading = false