Download

Shield and Health System

I implemented a shield and health system, where

Damage dealt will go to shield if remaining shield > 0
Certain types of damage will only effect shield, and same goes for health
Death when health reaches 0

Is this correct?


USTRUCT(BlueprintType)
struct FPlayerHitPoints
{
	GENERATED_USTRUCT_BODY();

	UPROPERTY()
		float MaxTotal;

	UPROPERTY()
		float MaxHealth;

	UPROPERTY()
		float MaxShield;

	UPROPERTY()
		float CurrentTotal;

	UPROPERTY()
		float CurrentHealth;

	UPROPERTY()
		float CurrentShield;

	FPlayerHitPoints(float NewHealth, float NewShield)
	{
		MaxHealth, CurrentHealth = NewHealth;
		MaxShield, CurrentShield = NewShield;
		Balance();
		UpdateTotals();
	}

	FPlayerHitPoints(float NewHealth, float NewShield, float NewMaxHealth, float NewMaxShield)
	{
		MaxHealth = NewMaxHealth;
		MaxShield = NewMaxShield;
		CurrentHealth = NewHealth;
		CurrentShield = NewShield;
		Balance();
		UpdateTotals();
	}

	void Recharge()
	{
		CurrentHealth = MaxHealth;
		CurrentShield = MaxShield;
		Balance();
		UpdateTotals();
	}

	void Scale(float Scale)
	{
		CurrentHealth = MaxHealth * Scale;
		CurrentShield = MaxShield * Scale;
		Balance();
		UpdateTotals();
	}

	void Scale(float ScaleHealth, float ScaleShield)
	{
		CurrentHealth = MaxHealth * ScaleHealth;
		CurrentShield = MaxHealth * ScaleShield;
		Balance();
		UpdateTotals();
	}

	void UpdateTotals()
	{
		CurrentTotal = CurrentHealth + CurrentShield;
		MaxTotal = MaxShield + MaxHealth;
	}

	void SetShield(float NewShield)
	{
		CurrentShield = NewShield;
		UpdateTotals();
	}

	void SetHealth(float NewHealth)
	{
		CurrentHealth = NewHealth;
		UpdateTotals();
	}

	void AddShield(float AddValue)
	{
		SetShield(AddValue + CurrentShield);
	}

	void AddHealth(float AddValue)
	{
		SetHealth(AddValue + CurrentHealth);
	}

	void Add(float AddValue)
	{
		const float AbsValue = FMath::Abs(AddValue);
		if (IsShieldActive())
		{
			if (CurrentShield >= AbsValue) AddShield(AddValue);
			else if (CurrentShield < AbsValue)
			{
				// Cache current shield value
				const float OldCurrentShield = CurrentShield;
				// Deplete shield
				AddShield(-1.0f * CurrentShield);

				float HealthToAdd = AbsValue - OldCurrentShield;

				// Negate health to add if AddValue is negative
				if (FMath::IsNegativeFloat(AddValue)) HealthToAdd *= -1.0f;

				AddHealth(HealthToAdd);
				Balance();
			}
		}
		else AddHealth(AddValue);
	}

	void Balance()
	{
		if (CurrentHealth > MaxHealth)
		{
			const float OverloadedHealth = MaxHealth - CurrentHealth;
			AddHealth(-1.0f * OverloadedHealth);
			AddShield(OverloadedHealth);
		}
	}

	bool IsShieldActive() const
	{
		return IsValid() && (CurrentShield > 0.0f);
	}

	bool IsValid() const
	{
		return (CurrentHealth <= MaxHealth) && (CurrentShield <= MaxShield) && (MaxHealth <= 200.0f) && (MaxShield <= 200.0f);
	}

	bool IsAlive() const
	{
		return (CurrentHealth > 0.0f) && IsValid();
	}
};

It depends on how u want to use all this.
U show a structure with some values and functions … don’t think anyone can really answer that

Usally u use the Damage methods and DamageTypes for this in UE4.
For example, u can make for DamageType classes derived from UDamageType. These classes define if the actual damage should affect the shield or the pawn who has the shield.
Then your shield should be an actor, which is spawned as sub-object of your pawn.

Implementation of damage would be something like this:



float MyPawn::TakeDamage(float DamageAmount, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, AActor* DamageCauser)
{
    // Let the shield absorve damage
    float AbsorvedDamage = MyShield ? MyShield->TakeDamage(DamageAmount, DamageEvent, EventInstigator, DamageCauser) : 0.0f;

    // Calculate the remaining damage (damage reduced by the damage absorved by the shield)
    float RemainingDamage = DamageAmount - AbsorvedDamage;

    // Decrease the health
    Health -= RemainingDamage
    return RemainingDamage;
}

float MyShield::TakeDamage(float DamageAmount, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, AActor* DamageCauser)
{
    // Check if the damage type should be absorved by the shield
    if (DamageEvent.DamageTypeClass == UPawnDamage::StaticClass())
    {
        // The shield takes no damage, all damage is taken by the pawn
        return 0.0f;
    }

    // Check how much damage the shield can absorve
    float ActualDamage = DamageAmount;
    if (ActualDamage > ShieldHealth)
    {
         ActualDamage = ShieldHealth;
    }

    // Reduce the shield health
    ShieldHealth -= ActualDamage;
    return ActualDamage;
}


I totally didn’t know about the integrated methods :smiley:
Thanks for the help