Area2D instance with a timer not queue_free

Godot Version

I am using Godot4 in 2D game development.

Question

I have an enemy to attack the player by range attack, so dagger will be spawned for every attack.
The problem was the dagger (area2D) was set to timeout 2.0 seconds but not queue_free.

how it works:

  1. spawn_trajectory() is fired once from the enemy
  2. the dagger is stored in dictionary to be destroyed after 2 seconds
func spawn_trajectory():
	var dagger = DAGGER.instantiate()
	get_parent().add_child(dagger)
	dagger.global_position = $shoot_pos.global_position
	
	var dagger_direction = (body_player.global_position - global_position).normalized()
	dagger.set_direction(body_player.global_position, dagger.global_position, dagger_direction, dagger_speed)
	dagger.set_damage(DAMAGE)

dagger.gd

extends Area2D

var dagger_damage : int
var start_position = Vector2.ZERO
var velocity = Vector2.ZERO
var min_distance = 20 #685
var landing_position = Vector2.ZERO
var spawn_position = Vector2.ZERO
var landing_spawn_pos_dict = {}

func _ready():
	start_position = position
	landing_position = Vector2.ZERO
	#print(self, "start_position= ",start_position)
	pass
func _process(delta):
	#trajectory
	position += velocity * delta
	$Label.text = str(position.distance_to(landing_position))
	pass

func _physics_process(delta):
	destroy_dagger()

func set_direction(target_pos: Vector2 , spawn_pos: Vector2, direction : Vector2, speed : int):
	velocity = direction * speed
	landing_position = target_pos
	spawn_position = spawn_pos
	
	if not landing_spawn_pos_dict.has(self):
		#landing_spawn_pos_dict[self] = {position: landing_position} # Initialize with an array containing the value
		landing_spawn_pos_dict[self] = [{"landing_position": landing_position}]



func set_damage(DAMAGE):
	dagger_damage = DAMAGE

func _on_body_entered(body):
	if body.name == "player":
		body.receive_damage(dagger_damage)
		print(self, "deal damage", dagger_damage)

func destroy_dagger():
	print("landing_spawn_pos_dict= ",landing_spawn_pos_dict)
	for dagger in landing_spawn_pos_dict.keys():
		#var dagger_land_pos= landing_spawn_pos_dict.get(dagger)
		await get_tree().create_timer(2.0).timeout
		dagger.queue_free()

It looks like you want to spawn daggers that move towards a player and get destroyed after 2 seconds. However, your current implementation is a bit convoluted, especially with the handling of the dictionary for tracking daggers.

Here’s a simplified and more robust approach to achieve your goal:

  1. Spawn the dagger and set its direction.
  2. Move the dagger towards the player.
  3. Destroy the dagger after 2 seconds.

Enemy Script (enemy.gd)

Here’s a script that spawns a dagger and sets its direction towards the player:

extends Node2D

@export var dagger_scene: PackedScene
@export var dagger_speed: int = 200
@export var DAMAGE: int = 10
@onready var player = get_parent().get_node("Player") # Adjust the path to your player node
@onready var shoot_pos = $shoot_pos

func spawn_trajectory():
	var dagger = dagger_scene.instantiate()
	get_parent().add_child(dagger)
	dagger.global_position = shoot_pos.global_position
	
	var dagger_direction = (player.global_position - global_position).normalized()
	dagger.set_direction(dagger_direction, dagger_speed)
	dagger.set_damage(DAMAGE)

Dagger Script (dagger.gd)

Here’s the script for the dagger itself:

extends Area2D

var dagger_damage: int
var velocity: Vector2 = Vector2.ZERO

var timer = 0

func _physics_process(delta):
    timer += delta
    if timer >= 2:
        queue_free()

func _process(delta):
	# Move the dagger
	position += velocity * delta

func set_direction(direction: Vector2, speed: int):
	velocity = direction * speed

func set_damage(DAMAGE: int):
	dagger_damage = DAMAGE

func _on_body_entered(body):
	if body.name == "Player": # Make sure this matches your player's node name
		body.receive_damage(dagger_damage)
		queue_free()

spawn_trajectory() in enemy.gd: This function spawns the dagger, sets its position to shoot_pos, calculates the direction towards the player, and sets the dagger’s direction and damage.

Dagger’s _physics_process(): The dagger queues itself to be freed after 2 seconds.

Dagger’s _process(delta): The dagger moves according to its velocity each frame.

Depending on your requirements, you may want to move this to _physics_process, which runs every physics tick rather than every frame. That is up to you.

set_direction(direction: Vector2, speed: int): Sets the direction and speed of the dagger.

_on_body_entered(body): When the dagger collides with the player, it deals damage and then queues itself for freeing.

This approach ensures that each dagger moves towards the player and is destroyed after 2 seconds or upon collision with the player, without the need for complicated dictionary handling.

1 Like

Cool!
Can you teach me how does this delta working?
I tried to print delta , i cannot understand the pattern of it.

delta in this case means the time elapsed since the last time the function was called

So when _process() runs, delta can vary because of the framerate…

When _physics_process() runs, I suppose delta should be the same as the physics tick setting.

Documentation

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