Hi!

I created 'bullet' objects and 'enemy' objects, and made the 'enemy' connect and signal to the 'bullet' on collision. The 'bullet' is freed on receiving the signal. I assumed this would shift detection duties away from the 'bullet'. It even works! About half the time... and sometimes it leads to a crash:

"invalid get index '...' (on base: 'previously freed' "

Now, since it works sometimes, I don´t know what goes wrong.

Here the offending code:

var connections = []
var collided

func _physics_process(delta):
	collided = get_overlapping_areas()
	for entity in collided:
		if entity not in connections:
			self.collision.connect(entity._on_collision)
			connections.append(entity)
		collision.emit()

_on_collision does nothing but dequeue. Both the 'bullets' and the 'enemies' get instanced in a main scene.
I thought I could clear the connections list from time to time. Is there a more elegant way to check for existing connections? Is my implementation just crap?
lemme know!

I'm hazarding a guess that it's because you're deleting the scene while it's sending the signal, get_overlapping_areas is constantly running as long as anything is overlapping.
my usual solution to this is to use the "on body entered" signal in combination with groups (ie to check if it's an enemy or a wall) and then in the bullet's scene run queue_free().
for that matter, why do you want the bullet not to handle it's own deletion? that's an odd decision to me.

I plan to have many bullets and fewer enemies and thought making signal connections only when nessesary from the object with fewer instances would improve performance. To be fair I don t actually know if beeing connected to another object is recource intensive. I assumed, that if every bullet were to check for collisions and were to be connected to every enemy, it would impact the amount of bullets that i could have drastically.
I saw a video that described other ways to improve how many bullets you can entertain (in C and something with servers), but that seemed too advanced for me.
I just figured i can call a function on the colliding entity. What I did was just a gross overcomplication. For some reason some Bullets still pass through the enemy instance from time to time, but i guess thats a different problem.
Thank you for pointing me to groups though!

I will assume you are working in 2D, as I don't see any sign of you working in 3D and I don't have any experience with 3D.

  • As I see it this may be an overcomplication, unless you need to use those connections somehow. But the solution I propose might help you write something (cleaner?).

  • A simple solution can be, to add an Area2D to the enemy.

  • Let's say this Area2D's sole purpose is to monitor when anything hit the enemy.

  • So, inside the inspector, turn off monitorable, it is only going to monitor stuff.

  • Next, in the Node tab under signals, depending on what you are using as projectile type, connect either area_entered or body_entered signals to the enemy script, I will assume your bullets are of type Area2D.

  • Inside the function that is created, like _on_area_entered(area) you can have this code example:

    func _on_area_entered(area: Area2D) -> void:
      #Check if the area that entered, is a bullet. You can use groups, has_method("some_method"), is Bullet (if you have a script attached to your bullet with class_name Bullet), etc...
      # Will use the last one ...
      if area is Bullet:
        area = area as Bullet # Redundant, this is for autocompletion purposes, write it, don't write it, this doesn't change anything
        # Now call a function that a Bullet implements, like do_something, and inside do_something can be anything, from queue_free, to instantiating explosion scene, 
        # playing a sound, recochet in a different direction, or anything you can imagine
        # as you can see the bullet handles its behaviour this way, and the enemy doesn't need to know about it. 
        area.do_something(some_argument, other_argument ...) 
        # And now what should the enemy do? maybe hurt animation, hp -= damage, sound?, store the bullet? connect a signal (why?), etc... anything the enemy is concerned with
        get_damaged(damage, other_argument)
  • As you can see, eveything does what it is responsible for, and everyone is happy

  • For performace, you can use collision masks and layers. I believe they have some optimization. But not sure about that.

  • Using circle hit boxes / hurt boxes can be more performant too.

I hope that was helpful 😅
Edit: Formatting

Thanks, I figured something like that would be best. Got lost in wanting to Signal everything 😃