Bullet not flipping with the player direction

Godot Version

Godot v4.3

Question

I have a problem when the player is flipped to the left and I try to shoot, the bullets go only one direction, "Right', and not the same direction the player/character is facing in. How to fix this ?

This is the bullet script

extends Area2D

@export var speed = 750

@onready var bullet: Area2D = $Bullet
@onready var sprite_2d: Sprite2D = $Sprite2d
@onready var bullet_effect: AnimatedSprite2D = $BulletEffect
var pBulletEffect := preload("res://BulletEffect.tscn")


func _physics_process(delta):
	position += transform.x * speed * delta
	
	
func _on_body_entered(body: Node2D) -> void:
	if body.has_method("enemy_hit"):
		var bulletEffect := pBulletEffect.instantiate()
		bulletEffect.position = position
		get_parent().add_child(bulletEffect)
		body.enemy_hit()
		queue_free()

this is the player script

extends CharacterBody2D

var health = 30

@onready var player: CharacterBody2D = $Player
@export var bullet_scene : PackedScene
@onready var sprite_2d: AnimatedSprite2D = $Sprite2d
@onready var bowShoot =$bowShoot
@onready var typhon: AudioStreamPlayer2D = $typhon
@onready var player_walk: AudioStreamPlayer2D = $player_walk
@onready var player_jump: AudioStreamPlayer2D = $PlayerJump

	
	
const SPEED = 400
const JUMP_VELOCITY = -700.0
	
	
func _physics_process(delta: float) -> void:
	# Add the gravity.
	if not is_on_floor():
		velocity += get_gravity() * delta
		
		
	# Handle jump.
	if Input.is_action_just_pressed("jump") and is_on_floor():
		velocity.y = JUMP_VELOCITY
		sprite_2d.animation = "jump"
		player_jump.play()
	if Input.is_action_just_released("jump"):
		sprite_2d.animation = "idle"
	
	
	# 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, SPEED)
		
	move_and_slide()
	
	if Input.is_action_just_pressed("shoot"):
		shoot()
		bowShoot.play()
		sprite_2d.animation = "shoot"
	if Input.is_action_just_released("shoot"):
		sprite_2d.animation = "idle"
		

	
# Animations
	
	if Input.is_action_just_pressed("left"):
		sprite_2d.animation = "left"
		player_walk.play()
	if Input.is_action_just_released("left"):
		sprite_2d.animation = "idle"
	
	if Input.is_action_just_pressed("right"):
		sprite_2d.animation = "right"
		player_walk.play()
	if Input.is_action_just_released("right"):
		sprite_2d.animation = "idle"


	var isLeft = velocity.x < 0
	sprite_2d.flip_h = isLeft

	
func shoot():
	var b = preload ("res://bullet.tscn").instantiate()
	get_tree().root.add_child(b)
	b.transform = $Muzzle.global_transform
	

The bullet goes to the right because you’re never telling it to change its direction. This line: position += transform.x * speed * delta is responsible for that.

What you could do is adding a direction parameter to the bullet, which would be 1 or -1, indicating if the bullet goes right or left. You can then simply add this direction to your instruction to adjust the position increment, like this:

var direction: int = 1

func _physics_process(delta):
	position += transform.x * speed * delta * direction

You then need to set the direction, based on where the player is looking. To do that, go into your shoot function, and set the value in the bullet variable:

func shoot():    
    var b = preload ("res://bullet.tscn").instantiate()
    get_tree().root.add_child(b)
    b.transform = $Muzzle.global_transform

    # Demo code, may need adjustements based on your likings, but the logic can be done like this.
    b.direction = -1 if sprite_2d.flip_h else 1

You can then change the bullet sprite flip_h/scale based on the direction variable too!
Hope that helps.

1 Like

Thank you so much! it worked

but one thing, the Sprite2D “Arrow” is not flipping too!
I mean the png texture file / image

do I need to add script to it or something?
shouldn’t it flip automatically?

Applying the direction to the translation does not flip the sprite automatically, as those two things are decorrelated. As I said, you need to also flip the bullet based on the direction. You could add a line like this:

b.direction = -1 if sprite_2d.flip_h else 1
b.sprite_2d.flip_h = sprite_2d.flip_h  # You may want to revert the boolean, depending on your sprite.

But note that a more proper way would be to add a function in your arrow script to set its direction, something like this:

func set_direction(dir: int):
    direction = dir
    sprite_2d.flip_h = dir > 0  # Again, you may want to use "< 0" instead, depending on your sprite.

And call it like this:

func shoot():
    var b = preload ("res://bullet.tscn").instantiate()
    get_tree().root.add_child(b)
    b.transform = $Muzzle.global_transform
    b.set_direction(-1 if sprite_2d.flip_h else 1)

–

And just to make things clear:

I mean the png texture file / image

The .png file is not flipped. When using flip_h or flip_v, you simply tell the Sprite2D to draw the .png file a different way, but the image itself isn’t affected. That’s why you can shoot multiple arrows with different directions, using the same initial image (as you have one .png, but multiple Sprite2D).

1 Like

But note that a more proper way would be to add a function in your arrow script to set its direction, something like this:

func set_direction(dir: int):
    direction = dir
    sprite_2d.flip_h = dir > 0  # Again, you may want to use "< 0" instead, depending on your sprite.

when I attach a new script to the Arrow 2d sprite and add this code
I get

 Identifier "direction" not declared in the current scope.

I am sorry for the late reply, but I am still stuck on flipping the Arrow Png file with the player’s direction when shooting.

That errors means you are trying to set the value of a variable called direction although it does not exist.

You need to declare it in your script, like that:

var direction: int

func set_direction(dir: int):
    direction = dir
    sprite_2d.flip_h = dir > 0  # Again, you may want to use "< 0" instead, depending on your sprite.

as I did in my first answer.

1 Like

Thanks, now the Arrow and other bullets is flipped when shooting to the left with the player direction
but its position is wrong and its place, a bit far behind the Player/bow/gun
this happens only when shooting to left but shooting to the right it’s good no problem

Doing 16 * direction doesn’t work here because you need to use the bullet direction: 16 * b.direction (using the player direction may work, but I don’t know if the value is correct).
Also, if you’re just offseting by 16 pixels whether you shoot left or right, you should make sure the default position is centered (else, you’d need to offset more on one side than another).

1 Like