Code/Stamina.cs
using Sandbox;
using Sandbox.Rendering;
using System;
namespace Maxine;
[Title( "Maxine's Simple Stamina Component" )]
public sealed class Stamina : Component
{
/// <summary>
/// The current available stamina. Use ConsumeStamina() and RegainStamina() unless you want to bypass their event triggers.
/// </summary>
public float CurrentStamina = 1000f;
/// <summary>
/// The maximum amount of stamina this component can wield.
/// </summary>
[Property] public float MaxStamina = 1000f;
/// <summary>
/// The amount of time passed before recovering stamina.
/// </summary>
[Property] public float StaminaRecoveryAfterSeconds = 0.25f;
[Property] public float DelayBeforeStaminaRecovery = 2f;
/// <summary>
/// How much stamina is recovered after StaminaRecoveryAfterSeconds triggers.
/// </summary>
[Property] public float StaminaRecoveryAmount = 10f;
/// <summary>
/// Event for when CurrentStamina loses some of its charge.
/// Can be used for updating UI for example.
/// </summary>
[Property] public Action<float> OnStaminaConsumed { get; set; }
/// <summary>
/// Event for when CurrentStamina gains some stamina.
/// Can be used for updating UI for example.
/// </summary>
[Property] public Action<float> OnStaminaRegenerated { get; set; }
[Property] private bool enableDebugHud = false;
private TimeSince lastRegenCheck = 0;
private TimeSince delayBeforeRegen = 0;
protected override void OnAwake()
{
base.OnAwake();
CurrentStamina = MaxStamina;
}
protected override void OnUpdate()
{
base.OnUpdate();
if ( enableDebugHud ) DrawDebugHud();
if ( CurrentStamina >= MaxStamina ) return;
if (lastRegenCheck.Relative >= StaminaRecoveryAfterSeconds && delayBeforeRegen.Relative >= DelayBeforeStaminaRecovery)
{
RegainStamina( StaminaRecoveryAmount );
}
}
public void RegainStamina( float stamina )
{
float currentStamina = CurrentStamina;
CurrentStamina = Math.Clamp( CurrentStamina + stamina, 0, MaxStamina );
lastRegenCheck = 0;
OnStaminaRegenerated?.Invoke( stamina );
}
public void ConsumeStamina( float amountOfStaminaToConsume )
{
delayBeforeRegen = 0;
if (CurrentStamina <= 0 )
{
return;
}
CurrentStamina = Math.Clamp( CurrentStamina - amountOfStaminaToConsume, 0, MaxStamina );
lastRegenCheck = 0;
OnStaminaConsumed?.Invoke( amountOfStaminaToConsume );
}
private void DrawDebugHud()
{
if ( Scene.Camera is null )
return;
float staminaPercentage = (float)CurrentStamina / MaxStamina;
float lineHeight = Screen.Height * staminaPercentage;
var hud = Scene.Camera.Hud;
hud.DrawText( new TextRendering.Scope( CurrentStamina.ToString(), Color.Red, 32 ), new Vector2(Screen.Width * 0.5f,Screen.Height * 0.95f) );
hud.DrawLine(new Vector2(0, Screen.Height ), new Vector2( lineHeight * 2, Screen.Height ) , 4f, Color.Green );
}
}