Health and Damage
The player and enemies should have a health level that will decrease each time they are hit by a bullet. We'll store the health information in the Health component.
-
Create the Health.cs component and copy the following code into it:
Health.cs
using System; using System.Collections; using System.Collections.Generic; using Unigine; [Component(PropertyGuid = "AUTOGENERATED_GUID")] // <-- this line is generated automatically for a new component public class Health : Component { public int health = 5; // flag indicating that the health value is less or equal to 0 public bool IsDead => health <= 0; public void TakeDamage(int damage) { // calculate damage to health health = MathLib.Max(health - damage, 0); } }
-
Add it to the visuals node of the robot_enemy node.
- Add it to the player_hit_box node of the player node.
-
In order to use the Health.cs component logic, we need to modify number of components.
In WeaponController.cs, add the following several lines to the part detecting that the player has hit an object:
// if the intersection is found if (hitObject) { // render the intersection normal in the hit point Visualizer.RenderVector(hitInfo.Point, hitInfo.Point + hitInfo.Normal, vec4.RED, 0.25f, false, 2.0f); // spawn the visual effect NodeReference in the hit point vfx.OnHit(hitInfo.Point, hitInfo.Normal, hitObject); ${#HL}$ // apply damage Health health = hitObject.GetComponent<Health>(); if (health) health.TakeDamage(damage); ${HL#}$ }
In Bullet.cs, let's add several lines after detecting that the player has been hit and just before removing the bullet in order to apply damage to the characher and update the health information:
// check if any object has been hit if (!hitObject) return; // load a visual effect NodeReference to visuallize the hit Node hitEffect = World.LoadNode(hitPrefab.AbsolutePath); // place the NodeReference to the hit point to set its direction according to the hit normal hitEffect.Parent = hitObject; hitEffect.WorldPosition = hitInfo.Point; hitEffect.SetWorldDirection(hitInfo.Normal, vec3.UP, MathLib.AXIS.Y); ${#HL}$ // check the object that has been hit (hitObject): if it is a player and if it has the Health component Health health = hitObject.GetComponent<Health>(); if (health && hitObject.GetComponentInParent<playerlogic>()) { // apply the damage from the bullet health.TakeDamage(damage); // update the player's health information in HUD ComponentSystem.FindComponentInWorld<HUD>().UpdateHealthInfo(health.health); } // delete the bullet node.DeleteLater(); ${HL#}$
The robots that have zero health should be deleted from the scene. The Health component has the IsDead flag which is checked by the EnemyLogic component of the robot. If the flag is set to true, the node of that robot will be deleted. To do this, we will add the health property to the EnemyLogic component, initialize it in Init() and then we'll check the health level of the enemy robot every frame in Update() and remove it if necessary:
${#HL}$private Health health = null;${HL#}$
// ...
private void Init()
{
// ...
${#HL}$// grab the Health component
health = node.GetComponentInChildren<Health>();${HL#}$
}
private void Update()
{
// ...
${#HL}$// check if the IsDead flag is set
if (health && health.IsDead)
// remove the enemy from the scene if it is killed (IsDead)
node.DeleteLater();${HL#}$
}
We need to add the same check for the player, only instead of deleting it (in this case we'll just delete the main camera and see nothing else) we'll just make it immovable by disabling several components.
-
Create the PlayerLogic.cs component and add the following code into it:
using System; using System.Collections; using System.Collections.Generic; using Unigine; [Component(PropertyGuid = "AUTOGENERATED_GUID")] // <-- identifier is generated automatically for a new component public class PlayerLogic : Component { private Health health = null; private void Init() { // grab the Health component of the node health = node.GetComponentInChildren<Health>(); // update the player's health information ComponentSystem.FindComponentInWorld<HUD>().UpdateHealthInfo(health.health); } private void Update() { // check if the IsDead flag is set if (health && health.IsDead) { // make the player immovable by disabling the components node.GetComponent<FirstPersonController>().Enabled = false; node.GetComponent<WeaponController>().Enabled = false; node.GetComponent<ShootInput>().Enabled = false; } } }
- Add the PlayerLogic component to the player node.
Let's also add displaying of player's health information in the HUD. To do this, we will add a few lines to the Init() method and add the UpdateHealthInfo() method to update the value in the GUI widget in the HUD.cs file:
${#HL}$ private WidgetLabel label = null;${HL#}$
private void Init()
{
// get an instance of the current screen GUI
screenGui = Gui.GetCurrent();
// create a WidgetSprite for crosshair
sprite = new WidgetSprite(screenGui, crosshairImage);
// set the sprite size
sprite.Width = crosshairSize;
sprite.Height = crosshairSize;
// add the sprite to GUI so that it would always be in the center of the screen and overlap any other widgets
screenGui.AddChild(sprite, Gui.ALIGN_CENTER | Gui.ALIGN_OVERLAP);
// bind the widget lifetime to the world
sprite.Lifetime = Widget.LIFETIME.WORLD;
${#HL}$ // add WidgetLabel to display the player's health, set its position and font size
label = new WidgetLabel(screenGui, "");
label.FontSize = 50;
label.SetPosition(10,10);
// add the widget to GUI
screenGui.AddChild(label, Gui.ALIGN_CENTER | Gui.ALIGN_OVERLAP);
// bind the widget lifetime to the world
label.Lifetime = Widget.LIFETIME.WORLD;${HL#}$
}
${#HL}$ // update the current player's health
public void UpdateHealthInfo(int health)
{
label.Text = "Health: " + health.ToString();
}${HL#}$