Sprint using stamina

Haytam95

Active member
Hi I wanted to share with you the first ability that i wrote, it's called "Sprint".

It extends from SpeedChange, I wanted to start with something simple, but connecting other components like the AttributeManager and trying Coroutines.

So, this new Ability allows the character to run until he/she runs out of stamina (declared by dev). Also it's possible to prevent the character start running again after minimal regeneration, using "MinimalStaminaStart" variable.

Here is the Ability:

C#:
using System;
using System.Collections;
using Opsive.UltimateCharacterController.Character.Abilities;
using Opsive.UltimateCharacterController.Traits;
using UnityEngine;
using Attribute = Opsive.UltimateCharacterController.Traits.Attribute;

[Serializable]
[DefaultInputName("Change Speeds")]
[DefaultStartType(AbilityStartType.ButtonDownContinuous)]
[DefaultStopType(AbilityStopType.ButtonUp)]
public class Sprint : SpeedChange {
 
    [Tooltip("Minimal stamina to start ability")]
    [SerializeField] protected float m_MinimalStaminaStart = 20;
 
    [Tooltip("When stamina value is below this number, the ability will stop.")]
    [SerializeField] protected float m_MinimalStaminaExecute = 1;
 
    [Tooltip("Rate of consumption of stamina")]
    [SerializeField] protected float m_ConsumptionRate = 1;
 
    [Tooltip("Amount of stamina consumed in each rate")]
    [SerializeField] protected float m_ConsumptionAmount = 1;

    public float MinimalStaminaStart { get { return m_MinimalStaminaStart; } set { m_MinimalStaminaStart = value; } }
    public float MinimalStaminaExecute { get { return m_MinimalStaminaExecute; } set { m_MinimalStaminaExecute = value; } }
    public float ConsumptionRate { get { return m_ConsumptionRate; } set { m_ConsumptionRate = value; } }
    public float ConsumptionAmount { get { return m_ConsumptionAmount; } set { m_ConsumptionAmount = value; } }
 
 
    private Attribute m_AttributeStamina;
    private Coroutine m_ConsumptionCoroutine;
    private AttributeManager m_AttributeManager;
 
    public override void Awake() {
        base.Awake();
     
        m_AttributeManager = GetComponent<AttributeManager>();
        m_AttributeStamina = m_AttributeManager.GetAttribute("Stamina");
    }
 
 
 
    public override bool CanStartAbility() {
        if (!base.CanStartAbility()) return false;
     
        return m_AttributeStamina.Value > m_MinimalStaminaStart;
    }

    protected override void AbilityStarted() {
        m_ConsumptionCoroutine = m_AttributeManager.StartCoroutine(ConsumptionCoroutine());
        base.AbilityStarted();
    }

    protected override void AbilityStopped(bool force) {
        if(m_ConsumptionCoroutine != null) m_AttributeManager.StopCoroutine(m_ConsumptionCoroutine);
        base.AbilityStopped(force);
    }

    private IEnumerator ConsumptionCoroutine() {
        while (IsActive) {
            m_AttributeStamina.Value = m_AttributeStamina.Value - m_ConsumptionAmount;

            if (m_AttributeStamina.Value < m_MinimalStaminaExecute) StopAbility(true);
         
            yield return new WaitForSeconds(m_ConsumptionRate);
        }
    }
}

And here is how the AttributeManager was configured, so the Stamina can be regenerated automatically.

1569969443350.png

Feel free to play with this or use it for whatever you want, I just coded it to practice extending the controller


Last but not least, about the Coroutine i had to use the AttributeManager, because i couldn't start it from Ability. If someone knows a better way of doing this, i'm all ears!
 
Last edited:

Justin

Administrator
Staff member
Thanks for your contribution! There was actually a bug in the attribute system which prevented you from being able to do this without needing a new ability. This post has the fix:

 

Haytam95

Active member
Thanks Justin, actually i didn't saw that Speed Change ability had that! (And it was kind of excuse to try coding a custom ability)
 

nathanj

Member
If I understand correctly this script is not necessary anymore. It is however and extremely useful script to study!

Big thanks to the OP
 
I'm trying out this code with UCC 2.2.3 on Unity 2019.3.9f1.

Code:
Assets\Custom\Sprint.cs(9,2): error CS0246: The type or namespace name 'AllowMultipleAbilityTypesAttribute' could not be found (are you missing a using directive or an assembly reference?)
Code:
Assets\Custom\Sprint.cs(9,2): error CS0246: The type or namespace name 'AllowMultipleAbilityTypes' could not be found (are you missing a using directive or an assembly reference?)
 
Thank you for that. That worked. By any chance do you have the Agility add-on? I would like to modify the roll ability to use stamina as well.
 

Haytam95

Active member
Nope, but if you want to achieve that, the easist way is like I did:

Extend from the Ability you want and override this methods:

CanStartAbility:

You should check if your character have enought stamina to start the ability

OnAbilityStart:

Perform the stamina consumption.
 
I noticed a bug where the stamina keeps draining after the sprint has stopped and I think it happens when after I use the roll ability. Basically I'm sprinting and roll at the same time the stamina keeping draining.
 
Last edited:

Haytam95

Active member
That shouldn't happen. Are you sure that the trouble is in the sprint ability and not with the roll ability? This sprint ability have two ways to protect that:

During ability stopped:

C#:
protected override void AbilityStopped(bool force) {
        if(m_ConsumptionCoroutine != null) m_AttributeManager.StopCoroutine(m_ConsumptionCoroutine);
        base.AbilityStopped(force);
    }
(Stops the coroutine from drain stamina)



Also the coroutine kills itself if the ability isn't active:

C#:
private IEnumerator ConsumptionCoroutine() {
        while (IsActive) { // here


Anyway: You should configure the Sprint ability to require that the character is moving in the inspector and when the roll ability starts, make sure that the sprint ability stops.
 
Top