This code is close, but if I’m standing in between an enemy and a homing bullet, I won’t take any damage or have any other effect on the bullet. 100 Secret Service Agents just realized they can’t do their job properly…
This can be fixed quite simply by reversing the order of the statements within the if(hitTarget!=null) method, unless this behaviour is what you’re looking for.
I’m going to take this a step further, as I thought about our Secret Service agents (and also thought about how real friendly fire works)…
Here is a version I might use for this concept, which takes the size fo the offending collider in mind to slow down the projectile and reduce it’s damage… It probably should be extended to include wall penetration as well…
private void OnTriggerEnter(Collider other)
{
if (other.gameObject == instigator) return; //Avoid self harm
if (other.TryGetComponent(out Health health)) //Anything within this block, Health is guaranteed valid
{
if (health.IsDead()) return; //You could consider impacts here anyways, but capsules stay upright, so
//It would capture hits up to a meter and a half over a dead body... no bueno
health.TakeDamage(instigator, damage);
SpawnEffectsAndInvokeHit(); //Not sure if you're at this point, but this just invokes the Hit event and spawns effects
//Get bounds of the collider that we've hit.
float energyAbsorbed = other.bounds.extents.sqrMagnitude;
//Given a standard collider with a radius of .5f and a height of 2, this will be 1.5f
//Given a collider on a big dragon witha radius of 5 and a height of 5, this will be 75f
//Reduce speed by energyAbsorbed
float newSpeed = Mathf.Max(0,speed - energyAbsorbed);
//Reduce damage by the same ratio we removed speed.
damage *= newSpeed / speed;
speed = newSpeed;
//If either is still functional, continue on our merry way regardless of homing
if (speed > 0 && damage > 0) return;
}
//May be covered in later lectures
foreach (GameObject toDestroy in destroyOnHit)
{
Destroy(toDestroy);
}
Destroy(gameObject, lifeAfterImpact);
}
private void SpawnEffectsAndInvokeHit()
{
onHit.Invoke();
if (hitEffect != null)
{
Instantiate(hitEffect, GetAimLocation(), transform.rotation);
}
}
Actually… it only took me a moment to factor in the potential to shoot through walls (with the inherent effect of slowing down the projectile IF it has enough speed
private void OnTriggerEnter(Collider other)
{
if (other.gameObject == instigator) return; //Avoid self harm
if (other.TryGetComponent(out Health health)) //Anything within this block, Health is guaranteed valid
{
if (health.IsDead()) return; //You could consider impacts here anyways, but capsules stay upright, so
//It would capture hits up to a meter and a half over a dead body... no bueno
health.TakeDamage(instigator, damage);
}
SpawnEffectsAndInvokeHit(); //Not sure if you're at this point, but this just invokes the Hit event and spawns effects
//Get bounds of the collider that we've hit.
float energyAbsorbed = other.bounds.extents.sqrMagnitude;
//Given a standard collider with a radius of .5f and a height of 2, this will be 1.5f
//Given a collider on a big dragon witha radius of 5 and a height of 5, this will be 75f
//Reduce speed by energyAbsorbed
float newSpeed = Mathf.Max(0,speed - energyAbsorbed);
//Reduce damage by the same ratio we removed speed.
damage *= newSpeed / speed;
speed = newSpeed;
//If either is still functional, continue on our merry way regardless of homing
if (speed > 0 && damage > 0) return;
//May be covered in later lectures
foreach (GameObject toDestroy in destroyOnHit)
{
Destroy(toDestroy);
}
Destroy(gameObject, lifeAfterImpact);
}
private void SpawnEffectsAndInvokeHit()
{
onHit.Invoke();
if (hitEffect != null)
{
Instantiate(hitEffect, GetAimLocation(), transform.rotation);
}
}
With this, if anything besides the player is hit, first we test for Health, and damage accordingly.
Next, we check the sqrMagnitude of the collider that was hit, and reduce the projectiles speed accordingly. If we have effects to spawn at this point, we do so.
Now if the speed or damage has been reduced to zero, we set the object up for destruction.
If you hit a health, the first hit will do full damage, but the second target hit will do less damage, and will reduce in speed. This is very much like how real world projectiles would occur, if I jumped in front of a bullet to save you, the bullet might still travel right through me, but it won’t hit you as hard.
If you hit a wall, that projectile might go through if it’s a thin wall, or it might stop cold if it hits a 10x10x10 building.
There are other factors that could go into play for a system like this…
You could, for example, have a “piercing” value that modifies how much speed is lost… it could be scaled by the shooter’s offense or the target’s defense (with non-health items having the most piercing resistance).