@normalized In my haste to develop minimal example, I’ve neglected common sense. I’ve realized I forgot to connect some signals, and now it shows the bug, but it’s even buggier than my real version. So I will try to polish it, unless you really want to see it, then I can share it soon-ish.
@OriginalBadBoy Originally I didn’t change anything about Areas since there was no Area included in the enemy (enemies are CharacterBody2D with single CollisionShape2D). I have divided it to CollisionShape2D and Area2D today, but the bug persists. And playable zone only seeks the CollisionShape2D, Area2D is for projectiles. I needed it anyway since player could destroy enemy in forbidden moments, which would break logic.
Enemies colliding with each other is not unlikely, but it also doesn’t seem to be the source, since collision with each other is not programmed to trigger defeat sequence.
I would add the node name to your print statement so you can see which object is reporting the collision. That will start narrowing it down then.
According to the logs it collides with PlayableZone. Coordinates don’t match, but it is what it is.
I have managed to create fully functional minimal example. Not the prettiest, but it has 1:1 the same problem as the real code. First wave is ok, second one is not. In the example there is only one enemy in the object pool to keep it simple, but behavior is the same.
I’m not going to share it on github since I don’t want to share my real account name, so here is the link to project in an archive + code in pastebin for those who don’t trust archives (too much code for single comment).
At this point I think it happens because the same enemy is reused with close to no delay, so physics engine has no time to actually figure out what is going on. But my assumption can be wrong. I don’t know how Godot works at deeper level.
If thats the case (which I dont think it is) then a test for that would be just to increase the size of the pool.
This is indeed solution to the problem. But I would argue it uses memory for no reason.
It becomes very weird problem to be honest, because at this point it’s better to just get rid of the object pool - at the moment there are no more than 16 enemies active at a time in my use case, and they only spawn in waves once previous wave was cleared. I don’t plan any increases to that number, and even if I do, I can just add the pool back and increase the size. So this honestly shouldn’t a problem, on very old hardware .NET environment itself might be the issue, not the game.
The thing is that bug just haunts me, I want to know what is the true source of the problem.
Why would the physics engine need to figure anything out? There shouldn’t be any problems if an enemy is just teleported to another position without any delays.
Also, get rid of all awaits. Your code is infested with them. Awaits are bug factories. Use regular signal handlers instead.
Here is my disable code for pooled objects, there is double checks in here and stuff of course you wont understand as its not your code, but you should be able to get the gist of what I am doing:
protected override void DisableObject()
{
Sprite.Visible = false;
MovementScript.SetProcess(false);
IsAlive = false;
if (Interactive)
{
CollisionState(false);
}
if(MovementScript.movementType == ObjectMovement.MovementType.ANIM)
{
AnimationPlayerState(AnimObject,false, null);
}
switch (SpawnSubObject)
{
case SubObject.SCRIPT:
SpawnSubObjectNode.StopSpawn();
break;
case SubObject.ANIM:
AnimSubObject.Stop();
break;
case SubObject.NONE:
break;
default:
throw new ArgumentOutOfRangeException();
}
GlobalPosition = Globals.DefaultObjectPosition;
PutBacktoQueue();
}
protected void CollisionState(bool state)
{
_Area2D.SetDeferred(StaticStrings.monitoring, state);
_Area2D.SetDeferred(StaticStrings.monitorable, state);
}
I’m not familiar with ways of achieving the same results without async/await. Sometimes you just have to wait for something to happen.
Edit
Perhaps there is a way. Instead of using await, subscribe to the event that would be fired, and handle it from there. But it doesn’t strike me as objectively better approach. It makes code significantly bigger. For every “do A, wait for A to finish, then do B” we have to create extra method for B. You would also have to store event handlers in some cases, since unsubscription is not automatic for non-native signals.
It’s much easier to mentally follow the execution flow if there are no awaits in the code. Once awaits tangle your execution flow beyond your control - avoiding them becomes objectively better.
That’s not unreasonable but I haven’t encountered any serious issues with awaiting. It makes code more manageable from my point of view, instead of splitting even small sequences into separate event handlers.
I’m actually using signal approach in my enemy attack modules (using signals is natural approach for timers), and I wanted to rework it to use async/await, but those modules work so I’ve decided to not touch them.
There are some quirks you have to worry about, like native .NET stuff that can and will create issues (await ToSignal is cancelled automatically when node is freed and when it relies on stuff in that node, await Task.Delay will continue to run and try to access disposed object). But other than that, it seems fine.
I will rework my example tomorrow to rely on signals only, and see if it fixes the issue.
Except the one you started this thread about 
Await bugs are nasty and sneaky. The problem often manifests in a way that appears to be completely unrelated to its actual cause. If you experience bugs that “make no sense” that’s the first place to look into - if you can muster the mental power to visualize what your asynchronous calls are actually doing at any given time.
I have rewritten the example to use exclusively signals - zero async/awaits used. Behavior did not change.
You said:
Why would the physics engine need to figure anything out? There shouldn’t be any problems if an enemy is just teleported to another position without any delays.
I agree with you, it should work just fine. But it doesn’t. For extremely short period of time engine thinks enemy is still inside the Area2D, even though he has already been moved. At least this is how it looks like, it can something else entirely.
Make another minimal example without awaits. Minimize it even further. Try to reproduce it without the whole pooling mechanism.
This is crazy, I’m having the exact same problem. I wonder if it’s a bug with the engine? Idk if that’s possible tho?
Using Debug → Visible Collisions , my small collision shape is detecting what feels like the entire scene at this point? In other words, it detects all the enemies without colliding with it?
Make a minimal reproduction example. It’ll be helpful in any case. If the bug is in your code it’ll help you narrow it down, if it’s an engine bug - you need a minimal example to report the issue.