Hey there! I have two actors: a Projectile and an Explosive Barrel.
Both have their collision presets set to block each other.
My aim is to destroy the Projectile upon impact but also pass some information to the Explosive Barrel.
It works correctly when the Explosive Barrel’s OnComponentHit is implemented in C++, but not when I use a Blueprint version, which results in the following error:
Blueprint Runtime Error: "Attempted to access BP_MagicProjectile via property K2Node_ComponentBoundEvent_OtherActor, but BP_MagicProjectile is not valid (pending kill or garbage)". Node: Cast To ZCharacter Graph: EventGraph Function: Execute Ubergraph BP Explosive Barrel Blueprint: BP_ExplosiveBarrel
I’m getting that this is happening because I called “Destroy Actor” on the Projectile, so the reference to it has already gone and cannot be resolved in Explosive Barrel.
My question is, why can I successfully resolve the reference for OtherActor in C++ but not in Blueprint?
Here’s the Projectile OnComponentHit implementation in BP:
PendingKill means the actor/object still exists in memory, but no longer part of the world and is set for garbage collection to free the memory on the next GC pass. In this state, it is considered “invalid” by the engine because in most cases there’s a chance that it could already have been freed, and if you tried to access that memory after being freed, you’d run into major issues.
If you added if (OtherComp) in C++ the check would not pass. But since you are not checking validty, and accessing its memory directly, it just works because the memory is still valid.
This specific scenario may actually be safe, as the two Hit events will fire in the same frame, and the OtherActor should never have already been freed at this point. But it is a risky bet.
To do this properly, you should keep only the Hit event on the projectile. From the projectile, before destroying it, you can fire another event into the hit actor, that is more suitable to the situation. For example, use one of the builtin damage events. When projectile hits, apply damage to hit actor and destroy projectile itself. In the receiving actor, bind one of the damage events (AnyDamage) and you can retrieve/cast DamageCauser as projectile since it has not been destroyed just yet. In your specific case, you can even directly pass projectile’s instigator as instigator of the damage event.