Setting the target to null in Cancel() after SetTrigger("stopAttack")

My answer for where the bug could be coming from is right in the Hit() event when it Cancel has set the target to null. I noticed that turning up the time between attacks made it more obvious: if I cancelled my attack right before the animation plays, it still tries to call Hit() because we created a target for it, but then set it to null when trying to call TakeDamage(weaponDamage).

Even when we’ve cancelled the attack, the animator blends the transition from whereever we are in Attack to Locomotion, and that often involves the Hit() Animation Event being called.

The solution is to have your first line in Hit() be:

if(target==null) return;
1 Like

I’m not really convinced with this solution to be honest.
Couldn’t race condition still happen even with this fix? Is there any guarantee that the Hit() animation event is atomic?

No, because when the Hit() is called, if(target==null) return; acts as a gatekeeper for the rest of the logic. So even if you put Hit() in Update() and called it every frame, nothing would happen (except for push and pop on the stack for the call to Hit()).

Actually yes. Unless you’re explicitly using async operations or ECS (things that truly run on a separate thread from the main game loop), this will be an atomic operation. The main game loop runs on a single thread, and that includes calls to animation events. If you bridged an ECS or async operation to call Hit() that would be a different matter, and it’s entirely up to any async operation to not call code that is not thread safe. (Believe it or not, coroutines are generally not in this category, as their timeslices run on the main thread).

1 Like

that’s a good point. I was under the impression that one can click away mid attack animation and that could set the target to null even after the null check in Hit(), but fail to realize that our main game loop happen on a single thread.
The fact that I’m using the new input system (instead of checking key pressed in Update) doesn’t help. My intuition would be that the input system actually happens on a different thread, but after some googling it seems to run on the main thread as well, meaning that race condition wouldn’t occur in this case.

1 Like

Privacy & Terms