Hi, i need help with this problem,
I fixed the shoot to the right. the position of the FireFlash/Gunflash and the Sprite2D bullet is correct. But shooting to the left is wrong. The position is wrong for both FireFlash / Sprite2D bullet.
Do I need to make a script to make the the sprite2d position flip to the left with a corrected position.x or offset = something?
what should the script be like?`
This is difficult to fully assist without being able to see more details of your scene for the position of the FireFlash/GunFlash and the code for how you’re generating your bullets. It looks like you’re already toggling flip_h correctly on the FireFlash/GunFlash. How are you designating the correct location when shooting to the right?
Let me make some assumptions:
Player position: Vector2(0, 0)
FireFlash/GunFlash position: Vector2(100, 0) < this is relative to Player/Muzzle position.
Bullet is created at the position of FireFlash/GunFlash.
A simply way to make this work is to invert the FireFlash/GunFlash position when the player changes direction.
Player is facing right: FireFlash/GunFlash position: Vector2(100, 0)
Player is facing left: FireFlash/GunFlash position: Vector2(-100, 0)
If the change you need to make is on the Sprite2D within the Bullet scene, then I would put the code to toggle direction within the Bullet scene and call down
I don’t know exactly how you’re firing the bullet but consider this psuedo code:
Player Scene
var direction: float = 1.0 # this will either be 1 (facing right), or -1 (facing left)
def _input(event: InputEvent) -> void:
if event.is_action_pressed("move_right"):
direction = 1.0
# other player movement code
elif event.is_action_pressed("move_left"):
direction = -1.0
# other player movement code
def shoot():
var bullet: Bullet = (preload("res://bullet_scene.tscn") as PackedScene).instantiate()
bullet.set_direction(direction)
# other shoot code
Bullet Scene
def set_direction(direction: float):
$Sprite2D.offset = $Sprite2D.offset.abs() * direction # this effectively inverts the current offset - note that if you use a Y value in offset other than zero you may need to change this to compensate.
This way the Bullet scene has all the implementation for what to do when the direction is set, and all the Player (or anything else you make that shoots a bullet) needs to do is tell the Bullet which direction it is supposed to face.
extends Area2D
@onready var sprite_2d: Sprite2D = $Sprite2d
@export var speed = 750
var direction: int = 1
func _ready():
update_flip()
func _physics_process(delta):
position += transform.x * speed * delta * direction
if position.x < -1900 and direction > 0:
direction = -1
update_flip()
func update_flip():
$Sprite2d.flip_h = direction < 0
func _on_body_entered(body: Node2D) -> void:
if body.has_method("enemy_hit"):
body.enemy_hit()
queue_free()
func _on_despawntimer_timeout() -> void:
queue_free()
And
This is in the player script
extends CharacterBody2D
var health = 31
var direction: int = 1
@onready var bullet: Area2D = $Bullet
@onready var player: CharacterBody2D = $Player
@onready var sprite_2d: AnimatedSprite2D = $Sprite2d
@export var bullet2 : PackedScene
@onready var fire_flash: AnimatedSprite2D = $Muzzle/FireFlash
var is_shooting := false
const SPEED = 500
const JUMP_VELOCITY = -750.0
func _physics_process(delta: float) -> void:
HP()
handle_hp_regen(delta)
# Add the gravity.
if not is_on_floor():
velocity += get_gravity() * delta
if not is_shooting:
# Get the input direction and handle the movement/deceleration.
var direction := Input.get_axis("left", "right")
if direction != 0:
$Sprite2d.flip_h = direction < 0
$Muzzle/FireFlash.flip_h = direction < 0
velocity.x = direction * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
move_and_slide()
if Input.is_action_just_pressed("shoot"):
shoot()
sprite_2d.animation = "shoot"
is_shooting = true
if Input.is_action_just_released("shoot"):
sprite_2d.animation = "idle"
is_shooting = false
func shoot():
var b = preload ("res://bullet.tscn").instantiate()
b.direction = -1 if sprite_2d.flip_h else 1
get_tree().root.add_child(b)
b.transform = $Muzzle.global_transform
func shoot2():
var c = preload ("res://bullet2.tscn").instantiate()
c.direction = -1 if sprite_2d.flip_h else 1
get_tree().root.add_child(c)
c.transform = $Muzzle.global_transform
func shoot3():
var a = preload ("res://bullet_3.tscn").instantiate()
a.direction = -1 if sprite_2d.flip_h else 1
get_tree().root.add_child(a)
a.transform = $Muzzle.global_transform
Hey there, not really caught up to speed with all the replies but i had a similar issue when i was making an enemy for my game. Heres the code that works for that enemy. Hope it helps!
Arrow/bullet script:
extends Area2D
var direction = null
var on_screen = true
@onready var player = get_tree().get_first_node_in_group("Player_body")
@onready var timer: Timer = $VisibleOnScreenNotifier2D/Timer
func _ready(): # gets direction and sprite flip when arrow is instantiated
direction = (player.position - self.global_position).normalized()
if direction.x > 0:
$Sprite2D.flip_h = false
direction.x = ceil(direction.x) # ceiling() auto snaps the direction to the nearest whole value that is not less than the current value while floor does the opposite
else:
$Sprite2D.flip_h = true
direction.x = floor(direction.x)
func _physics_process(delta): # uses direction to flip
position.x += direction.x * 200 * delta
script for the bullet / arrow position and instantiation:
func on_enter():
Flee_state.attack_next = false
keep_attacking = true # Allow continuous shooting
attack()
func attack():
if keep_attacking and timer.is_stopped(): # Only attack if the player is in range and the timer is ready
playback.travel(Attack_animation)
timer.start()
func _process(_delta):
if not timer.is_stopped():
character.velocity.x = 0
var distance_to_player = snapped(character.player.position.x - character.global_position.x, 1)
if -100 < distance_to_player and distance_to_player < 100 and Flee_state.timer_cooldown.is_stopped():
keep_attacking = false
Flee_state.attack_next = true
if snapped(timer.time_left, 0.01) == 0.45:
const Arrow = preload("res://Enemy_archer/Arrow.tscn")
var New_Arrow = Arrow.instantiate()
var Arrow_offset = Vector2i(0,-10)
New_Arrow.global_position = character.global_position + Vector2(Arrow_offset)
character.add_sibling(New_Arrow)
if $"../../damageable_archer".Archer_health == 0:
next_state = Archer_death_state
this is part of an attack state in a finite state machine
This works for me and can hopefully be modified in a way that works for you
In this part of your Player script you are adjusting the flip_h of the FireFlash but not flipping the Muzzle or FireFlash position/offset. In your scene does the FireFlash AnimatedSprite2D have an offset configured?.. or is the position of the FireFlash determined by the Muzzle Marker2D position? This is the part of the code you need to be inverting based on the direction of your player so it moves to the opposite side of the Player. That would either be one or both of the following:
if not is_shooting:
# Get the input direction and handle the movement/deceleration.
var direction := Input.get_axis("left", "right")
if direction != 0:
$Sprite2d.flip_h = direction < 0
$Muzzle/FireFlash.flip_h = direction < 0
# add this:
$Muzzle/FireFlash.offset.x = abs($Muzzle/FireFlash.offset.x) * direction
# and/or this:
$Muzzle.position.x = abs($Muzzle.position.x) * direction
velocity.x = direction * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
# Get the input direction and handle the movement/deceleration.
if not is_shooting:
var direction := Input.get_axis("left", "right")
if direction != 0:
# Flip the sprite and adjust muzzle position
$Sprite2d.flip_h = direction < 0
$Muzzle/FireFlash.flip_h = direction < 0
# Adjust muzzle position based on facing direction
if direction < 0: # Facing left
muzzle.position.x = -110 # Your specified offset
else: # Facing right
muzzle.position.x = -22 # Reset to positive value (original position)
velocity.x = direction * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
move_and_slide()
```