projectile keeps colliding after being disposed of
Asked Answered
E

1

0

I am working on a projectile shattering logic. When bullet hits the target it should split into multiple sub-bullets. Currently just trying to make a prototype work with 1 single shard created after hitting the mark:


public partial class Projectile : Area2D
{
    public int Speed { get; set; } = 500;

    private bool _isDead = false;
    public List<ulong> IgnoredTargets = new List<ulong>();
    
    public override void _Ready()
    {
        // Connect the bullet's collision signal to the onBulletCollision method
        BodyEntered += OnBodyEntered;
    }

	public override void _Process(double delta)
    {
        if (_isDead)
            return;

        // Move the bullet forward
        var distance = Speed * (float)delta;
        Vector2 velocity = new Vector2(distance, 0).Rotated(Rotation);

        Position += velocity;
    }

    private void OnBodyEntered(Node body)
    {
        var targetId = ((Node2D)body).GetInstanceId();

        // prevent same projectile hitting same target more than once
        if (IgnoredTargets.Contains(targetId))
            return;

        if (_isDead)
        {
            GD.PrintErr("Projectile hit something after dying!");
            return;
        }

        IgnoredTargets.Add(targetId);

        var shard = (Projectile)this.Duplicate();
        shard.IgnoredTargets.AddRange(this.IgnoredTargets);
        GetParent().CallDeferred("add_child", shard);

        _isDead = true;
        QueueFree();
    }
}

The problem with this approach is I a keep getting the error messages:

Projectile hit something after dying!

Basically it means that the disposing of the old bullet is not happening!

However if I remove the shatter creation logic:

        var shard = (Projectile)this.Duplicate();
        shard.IgnoredTargets.AddRange(this.IgnoredTargets);
        GetParent().CallDeferred("add_child", shard);

the the error goes away... Could someone explain how to fix the issue? I would like the "old" bullet to be disposed of immediately after spawning several other sub-bullets of the same type (in example above I am creating just 1 shard for testing purposes by duplicating the existing node)

I feel like something is blocking the bullet disposal process so it keeps triggering the error message.. I am keeping track of all the objectss that the bullet has previously collided with using the IgnoredTargets property which is then passed to a shattered node.. but somehow this does not prevent the issue from happening.

Electronegative answered 16/4, 2023 at 20:9 Comment(0)
E
0

Ok so I have done 2 changes to the code.

started passing packed scene to projectile, so now initialization of a new bullet looks like

        var shard = ProjectileScene.Instantiate<Projectile>();
        shard.ProjectileScene = ProjectileScene;

        //var shard = (Projectile)this.Duplicate();
        shard.Position = Position;
        shard.Rotation = Rotation;
        shard.Speed = this.Speed;
        shard.IgnoredTargets.AddRange(this.IgnoredTargets);
        GetParent().CallDeferred("add_child", shard);

I have noticed a better result, but I still had the occasional error messages about collisions after bullet death..

So the second change was unsubscribing from collision events BodyEntered -= OnBodyEntered;, i.e.

        _isDead = true;
        BodyEntered -= OnBodyEntered;
        //Hide();
        QueueFree();

This second change has fixed the problem competely.

I have noticed that in times of "lags", i,e. if you click on window title bar for example or your PC just randomly lags and so is the game, then there is a slight delay in everything that is happening on the game screen. For example the bullet is not being disposed of immediately but continues to fly for 1 more frame. If the new enemy is hit during this 1 frame then it will also trigger all of the functions. QueueFree(); is not disposing of stuff immediately.

Here is the example (with shard logic disabled //GetParent().CallDeferred("add_child", shard);)

You can see for a split second that the bullet continues to fly for a bit more (or maybe it just teleports).. Thanks to recording software that records at 60 frames a second I can even show it (edited)

I am wondering if this is so common in Godot-based games? The glitches like that? I will leave the topic open for a bit more to maybe hear some ideas on this matter..

Electronegative answered 17/4, 2023 at 6:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.