2D How to flip weapon rotation during left facing of pivot

Godot Version

4.2.1

I have made the weapon node rotate around the weapon_pivot node based on the mouse location, however I am not sure how to make the sword rotate to essentially be mirrored.

Here is the player script, please let me know if any other information is needed.

extends CharacterBody2D

class_name Player

signal healthChanged

@export var speed: int = 100
@export var knockbackPower: int = 1000
@export var maxHealth: int = 3

@onready var animations: AnimationPlayer = $playerAnimations
@onready var effects: AnimationPlayer = $Effects
@onready var arrowAnimations: AnimationPlayer = $arrowAnimations
@onready var weapon: Node2D = $weapon_pivot/weapon
@onready var hurtTimer: Timer = $hurtTimer
@onready var currentHealth: int = maxHealth
@onready var bow: Area2D = $bow_pivot/bow
@onready var bow_pivot: Node2D = $bow_pivot
@onready var arrow = preload("res://actors/player/weapons/arrow.tscn")
@onready var arrowNode2D: Node2D = $arrowNode2D
@onready var weapon_pivot: Node2D = $weapon_pivot
@onready var weaponAnimation: AnimationPlayer = $weaponAnimationPlayer
@onready var swordSprite: Area2D = $weapon_pivot/weapon/sword

var lastAnimDirection: String = "Right"
var isAttacking: bool = false
var isHurt: bool = false
var isArrowCharging: bool = false
var isArrowCharged: bool = false
var isArrowFired: bool = false
var enemyCollisions = []
var bow_equipped: bool = false
var bow_cooldown: bool = true
var mouseLocFromPlayer = null
var bowCharge = 0.0
var maxBowCharge = 1.0
var bowChargeSpeed = 1.0

func _ready():
	effects.play("RESET")
	arrowAnimations.play("RESET")
	bow.visible = false

func handleInput():
	var moveDirection = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down") 
	velocity = moveDirection * speed 
	if Input.is_action_just_pressed("attack"):
		attack()

func attack():
	if bow_equipped: return
	
	#ATTACK ANIMATION HERE
	
	isAttacking = true
	await animations.animation_finished
	isAttacking = false

func updateAnimation():
	if isAttacking: return
	
	mouseLocFromPlayer = get_global_mouse_position() - self.position
	
	var mouse_pos = get_global_mouse_position()
	$Marker2D.look_at(mouse_pos)
	
	var direction = "Right"
	
	if mouseLocFromPlayer.x > 0:
		# Mouse is to the right of the player
		direction = "Right"
	elif mouseLocFromPlayer.x < 0:
		# Mouse is to the left of the player
		direction = "Left"
	
	if velocity.length() == 0:
		animations.play("idle" + direction)
	else:
		animations.play("walk" + direction)
	
	lastAnimDirection = direction


func knockback(enemyPosition: Vector2):
	var knockbackDirection = (enemyPosition - position).normalized() * knockbackPower
	velocity = knockbackDirection
	move_and_slide()

func handleCollision():
	for i in get_slide_collision_count():
		var collision = get_slide_collision(i)
		var collider = collision.get_collider()
		print_debug(collider.name)

func player():
	pass

func _physics_process(delta):
	handleInput()
	move_and_slide()
	updateAnimation()
	handleCollision()
	bowAttack(delta)
	if !isHurt:
		for enemyArea in enemyCollisions:
			hurtByEnemy(enemyArea)
	
	mouseLocFromPlayer = get_global_mouse_position() - self.position
	
	var mouse_pos = get_global_mouse_position()
	$Marker2D.look_at(mouse_pos)
	
	if !bow_equipped:
		var angle = atan2(mouseLocFromPlayer.y, mouseLocFromPlayer.x)
		# Add or subtract an offset to adjust the rotation
		weapon_pivot.rotation_degrees = rad_to_deg(angle) + 45
		if mouseLocFromPlayer.x < 0:
			swordSprite.flip_h = true
		elif mouseLocFromPlayer.x >= 0:
			swordSprite.flip_h = false
	
	# Rotate the bow pivot based on the angle between the player and the mouse
	if bow_equipped:
		var angle = atan2(mouseLocFromPlayer.y, mouseLocFromPlayer.x)
		# Add or subtract an offset to adjust the rotation
		bow_pivot.rotation_degrees = rad_to_deg(angle) - 90
	
func bowAttack(delta):
	if Input.is_action_just_pressed("bowEquip"):
		if bow_equipped:
			bow_equipped = false
			bow.visible = false
		else:
			bow_equipped = true
			bow.visible = true
			
	if Input.is_action_pressed("bowAttack") and bow_equipped and bowCharge <= maxBowCharge:
		isArrowCharging = true
		bowCharge += delta * bowChargeSpeed
	else:
		if bowCharge < maxBowCharge:
			if Input.is_action_just_released("bowAttack"): return
		elif bowCharge >= maxBowCharge:
			isArrowCharging = false
			isArrowCharged = true
			if Input.is_action_just_released("bowAttack"):
				isArrowCharged = false
				isArrowFired = true
				bowFire()

	if isArrowCharging:
		# Customize behavior when the arrow is charged
		effects.play("chargeFlash")
	if isArrowCharged:
		# Customize behavior when the arrow is charged
		effects.play("correctTiming")
	if isArrowFired:
		# Customize behavior when the arrow is fired
		effects.play("")

func bowFire():
	var arrow_instance = arrow.instantiate()
	arrow_instance.rotation = $Marker2D.rotation
	arrow_instance.global_position = $Marker2D.global_position
	add_child(arrow_instance)
	bowCharge = 0.0
	isArrowFired = false

func hurtByEnemy(area):
	currentHealth -= 1
	if currentHealth == 0:
		animations.play("death")
		await animations.animation_finished
		queue_free()
		# Activate the Game Over screen here
	else:
		healthChanged.emit(currentHealth)
		isHurt = true
		knockback(area.get_parent().velocity)

This is what it looks like:

I tried adding this if-else statement to my if !bow_equipped, but it didn’t quite work mostly because the pivot rotation feels weird for the weapon, it’s tough finding the correct offset/position.

if !bow_equipped:
    var angle = atan2(mouseLocFromPlayer.y, mouseLocFromPlayer.x)
    # Add or subtract an offset to adjust the rotation
    weapon_pivot.rotation_degrees = rad_to_deg(angle) + 45
    if mouseLocFromPlayer.x < 0:
        weapon_pivot.scale.x = -1
    else:
        weapon_pivot.scale.x = 1

I figured it out:

if !bow_equipped:
	var angle = atan2(mouseLocFromPlayer.y, mouseLocFromPlayer.x)
	if mouseLocFromPlayer.x < -9:
		weapon_pivot.scale.x = -1
		weapon_pivot.rotation_degrees = rad_to_deg(angle) + 90
	elif mouseLocFromPlayer.x >= -9:
		weapon_pivot.scale.x = 1
		weapon_pivot.rotation_degrees = rad_to_deg(angle) + 90
1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.