Unity Tech | How to implement a ‘sacrifice’ skill - take bullets for companion 🐺🐺🐺

In our latest game development, I implemented an interesting action: “jumping block”.

The team used this skill on the white wolf guard. The specific skill is called “sacrifice”. 🤨

Whenever the wolf leader around him receives deadly ballistic damage, the heroic white wolf guard will take a deep leap and block this damage for his boss.

Here is the video demonstration on Youtube:

And here is the schematic diagram:

The realization of the jumping block is very interesting 🤪. It is a combination of mathematics and physics.

Let’s skip the unimportant part and look directly at the most critical code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/// <summary>
/// A callback invoked when we find a particle(i.e. our bullet) is flying toward something
/// </summary>
/// <param name="collisionInstance">a manager contains information about the particle</param>
/// <param name="estimatedArrival">estimated time of flight</param>
public void OnParticleHeadingToTarget(ParticleCollisionInstance collisionInstance, float estimatedArrival)
{
// Check if the bullet is flying toward our fellow
if (collisionInstance != null && collisionInstance.HeadingTarget == wolfFellow.gameObject)
{
// Calculate which point should I jump in order to take the bullet for my fellow
jumpSpot = collisionInstance.EvaluateNecessaryArrival(4f, out float time);
// of course, you should look at the bullet when you try to take it.
lookSpot = collisionInstance.gameObject.transform.position;

/// Every creature has its react time when something happens
float reactTime = (_dollAction as WolfDollAction).WardJumpToApexDuration;

if (reactTime <= time)
{
Invoke(nameof(WardFellow), time - reactTime);
}
}
}

/// <summary>
/// Ward fellow, for wolf guard, warding is implemented by jump to take bullet for fellow
/// </summary>
void WardFellow()
{
WolfDollAction wolfAction = _dollAction as WolfDollAction;

wolfAction.TriggerJumpWard(wolfFellow, jumpSpot, lookSpot);
}

the mathematical part, EvaluateNecessaryArrival

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

/// <summary>
/// Evaluate necessary arrival which we must pass through
/// </summary>
/// <param name="distanceToHeadingTarget">distance for the arrival to the target</param>
/// <param name="estimatedTime">out parameter, a estimated time by when we arrive</param>
/// <returns>the vector of the must-pass arrival</returns>
public Vector3 EvaluateNecessaryArrival(float distanceToHeadingTarget, out float estimatedTime)
{
// Target
var heading = HeadingTargetSpot - transform.position;
// Distance
var currentDistance = heading.magnitude;
// Direction
var direction = heading / currentDistance;

Vector3 arrival = HeadingTargetSpot + direction * -distanceToHeadingTarget;
estimatedTime = (currentDistance - distanceToHeadingTarget) / MainFlyingParticleVelocity.magnitude;

return arrival;
}

It’s not that difficult, right? 🙊 Hoping you enjoy this skill. 😬