/// ---------------------------------------------
/// Ultimate Character Controller
/// Copyright (c) Opsive. All Rights Reserved.
/// https://www.opsive.com
/// ---------------------------------------------
namespace Opsive.UltimateCharacterController.Character.Abilities
{
using Opsive.Shared.Game;
using UnityEngine;
///
/// Plays a random idle animation based off of the AbilityFloatData animator parameter.
///
[DefaultStopType(AbilityStopType.Automatic)]
public class Idle : Ability
{
[Tooltip("Specifies how long the ability should wait until it is started.")]
[SerializeField] protected float m_StartDelay = 15;
[Tooltip("The maximum AbilityFloatData animator parameter.")]
[SerializeField] protected float m_MaxAbilityFloatDataValue;
[Tooltip("Should a random int between 0 and MaxAbilityFloatDataValue be used? If false AbilityFloatData will be increased sequentially.")]
[SerializeField] protected bool m_RandomValue = true;
[Tooltip("The minimum amount of time that the current AbilityFloatData value should be set.")]
[SerializeField] protected float m_MinDuration = 5;
[Tooltip("The maximum amount of time that the current AbilityFloatData value should be set.")]
[SerializeField] protected float m_MaxDuration = 10;
public float MaxAbilityFloatDataValue { get { return m_MaxAbilityFloatDataValue; } set { m_MaxAbilityFloatDataValue = value; } }
public bool RandomValue { get { return m_RandomValue; } set { m_RandomValue = value; } }
public float MinDuration { get { return m_MinDuration; } set { m_MinDuration = value; } }
public float MaxDuration { get { return m_MaxDuration; } set { m_MaxDuration = value; } }
private float m_CanStartTime = -1;
private float m_AbilityFloatDataValue;
private ScheduledEventBase m_FloatChangeEvent;
public override float AbilityFloatData { get { return m_AbilityFloatDataValue; } }
///
/// Called when the ablity is tried to be started. If false is returned then the ability will not be started.
///
/// True if the ability can be started.
public override bool CanStartAbility()
{
// An attribute may prevent the ability from starting.
if (!base.CanStartAbility()) {
return false;
}
// The ability can be started when the character is not moving and is on the ground.
if (!m_CharacterLocomotion.Moving && m_CharacterLocomotion.Grounded) {
if (m_CanStartTime == -1) {
m_CanStartTime = Time.time;
return false;
}
// A delay can be added to prevent the more extreme idle animations from playing immediately.
return m_CanStartTime + m_StartDelay < Time.time;
}
if (m_CanStartTime != -1) {
m_CanStartTime = -1;
}
return false;
}
///
/// The ability has started.
///
protected override void AbilityStarted()
{
base.AbilityStarted();
// Determine a new AbilityFloatData.
DetermineAbilityFloatDataValue();
}
private void DetermineAbilityFloatDataValue()
{
if (m_RandomValue) {
m_AbilityFloatDataValue = Random.Range(0, (int)(m_MaxAbilityFloatDataValue + 1));
} else { // Sequence.
m_AbilityFloatDataValue = (int)(m_AbilityFloatDataValue + 1) % (int)(m_MaxAbilityFloatDataValue + 1);
}
m_CharacterLocomotion.UpdateAbilityAnimatorParameters();
// A new value should be chosen between the min and max duration.
m_FloatChangeEvent = Scheduler.ScheduleFixed(Random.Range(m_MinDuration, m_MaxDuration), DetermineAbilityFloatDataValue);
}
///
/// Can the ability be stopped?
///
/// True if the ability can be stopped.
public override bool CanStopAbility()
{
// The ability should be stopped when the character moves or is no longer grounded.
return m_CharacterLocomotion.Moving || !m_CharacterLocomotion.Grounded;
}
///
/// The ability has stopped running.
///
/// Was the ability force stopped?
protected override void AbilityStopped(bool force)
{
base.AbilityStopped(force);
m_CanStartTime = -1;
// DetermineAbilityFloatDataValue no longer needs to be called.
Scheduler.Cancel(m_FloatChangeEvent);
m_FloatChangeEvent = null;
}
}
}