Hi! My question came with this example: the enemy has a gun and let’s suppose he instantiates two bullets at the same time, literally two lines of code
The case is: if the player has 1 life and receives 2 shots at the same time, he has -1 life and remains alive because both collisions validate the if condition, at the moment they both collide with the player he still has 1 life.
Is there something at code level that I could do? I’ve already tried creating a damage queue, but the result is the same.
Or would this be some engine configuration? Like, the bullet from the first Instantiate() collides first, but Unity’s processing is configured to not have such a precise distinction due to performance issues, BUT I can change that somewhere.
Have you actually observed this behavior? As far as I know, Unity will process everything sequentially. If there are two OnTrigger conditions in the same physics tick, first one will execute, then the other. The second one will see all the changes caused by the first one.
By the way, I don’t think you should use =- in your if statement. Did you mean to do “currentLife - damage > 0” ?
Sorry friends, I just thought about the code in a free way and typed it wrong. What’s actually inside my project is like @Ryiah said:
public void TakeDamage(int damage)
{
currentLife -= damage;
if (currentLife <= 0)
Die();
}
Checking the documentation @Kurt-Dekker linked, it really doesn’t make sense for the events to happen simultaneously, it should be in order. Does anyone have any idea what could be happening?
Have you added a Debug.Log into your TakeDamage method? Note that each log has a stacktrace attached so you see exactly who called the method. Keep in mind to print out the “currentLife” and maybe the passed damage value as well. So you see what the state is at the time. How well does your “Die” method handle being called multiple times?
The same way. If the player has 2 points of life and take the two simultaneous damage, the player has 0 life points, two logs of (“took damamge”) and he continues alive and walking, because each TakeDamage() applied the damage on top of the initial 2 life points, so both took 1 point of life, but none of them returned true for the if (currentLife <= 0) because currentLife is 1.
If the player only has 1 life point and receives 2 damage, he ends up with -1 life points, two logs of (“death”) and calls the Die() function twice, just triggering the death animation. PS the Die() function deactive the box collider and the second damage was not supose to happen.
Can you add a Debug.Log print to the TakeDamage function which prints out “damage” and “currentLife” at the start and end of the function just as a sanity check?
A common implementation for a TakeDamage method is this:
public void TakeDamage(int damage)
{
if (currentLife > damage)
currentLife -= damage;
else
{
currentLife = 0;
Die();
}
}
This serves several purposes. First of all we can never go into negative life because we only subtract damage when we have more life than the amount of damage that is supposed to be applied. So the first case represents the survival case and the resulting life will always be greater than 0. If the damage is equal to the current life or greater, we will surely die. That’s the else case. So we simply set the life to 0, since we’re dead and call the Die method. This approache makes it impossible for Die to be called twice (unless you use multiple threads calling TakeDamage which you should never do anyways as all this is not threadsafe).
Note: This way of applying damage suffers from the same bug that the GoldSource engine suffered from. Their “trigger_heal” could only heal the player up to the max health. However a func_door, func_door_rotating or a trigger_hurt which can apply damage were not checking for max health. We do I mention this? Well if you have a damage source that has a negative value, you will effectively heal the player, though without any bounds. This “bug” allowed the player in Half-Life to gain almost infinite health by getting himself stuck in a rotating door.
Many assume that this was simply a late fix for issues with supporting NPCs which were necessary to progress and they got constantly stuck in doors and die. So they gave the door a negative value. Maybe it was just a prank by one of the mappers, who knows. Anyways, most speedruns use this bug.
So if you don’t want this bug, you may either add an early exit when damage is negative, or handle the “healing case” properly. Keep in mind that even when you be careful to never have such cases, cheaters and hackers will always try such cheap tricks.