adjustments on cadence
This commit is contained in:
parent
998fd1e462
commit
c4e3723e07
@ -0,0 +1,85 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: f28542aec01041178adfbc30f7a2a82a, type: 3}
|
||||
m_Name: Sentinel Config
|
||||
m_EditorClassIdentifier: Assembly-CSharp::Intrepid.Gameplay.Entities.Player.Sentinel.SentinelConfig
|
||||
walk:
|
||||
speed: 5
|
||||
run:
|
||||
speed: 10
|
||||
dashImpulse:
|
||||
speed: 35
|
||||
durationMS: 150
|
||||
dashRecovery:
|
||||
speed: 10
|
||||
durationMS: 200
|
||||
dashMaxAngleFromForward: 90
|
||||
speedCurve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 1
|
||||
inSlope: -1
|
||||
outSlope: -1
|
||||
tangentMode: 34
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 1
|
||||
value: 0
|
||||
inSlope: -1
|
||||
outSlope: -1
|
||||
tangentMode: 34
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
dashLanding:
|
||||
durationMS: 100
|
||||
dashBreaking:
|
||||
speed: 10
|
||||
durationMS: 300
|
||||
speedCurve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 1
|
||||
inSlope: -1
|
||||
outSlope: -1
|
||||
tangentMode: 34
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 1
|
||||
value: 0
|
||||
inSlope: -1
|
||||
outSlope: -1
|
||||
tangentMode: 34
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
fallLanding:
|
||||
durationMS: 2000
|
||||
knockdown:
|
||||
knockoutTimeMultiplier: 0.1
|
||||
knockdownDurationMS: 100
|
||||
recoverDurationMS: 500
|
||||
maxKnockdownStrength: 15
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0805cd1ce642240f5abe420367e78b5e
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because one or more lines are too long
@ -2,23 +2,17 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.Cadence
|
||||
{
|
||||
public readonly struct CadenceEvaluation
|
||||
{
|
||||
public static CadenceEvaluation None = new(0f, 0f, CadenceBand.None, 0f, 0f);
|
||||
public static CadenceEvaluation None = new(CadenceBand.None, 0f, 0f);
|
||||
|
||||
public float T { get; }
|
||||
public float ElapsedAt { get; }
|
||||
public CadenceBand Band { get; }
|
||||
public float SettlementFactor { get; }
|
||||
public float Recovery { get; }
|
||||
|
||||
public CadenceEvaluation(
|
||||
float t,
|
||||
float elapsedAt,
|
||||
CadenceBand band,
|
||||
float settlementFactor,
|
||||
float recovery)
|
||||
{
|
||||
T = t;
|
||||
ElapsedAt = elapsedAt;
|
||||
Band = band;
|
||||
SettlementFactor = settlementFactor;
|
||||
Recovery = recovery;
|
||||
|
||||
@ -7,43 +7,19 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.Cadence
|
||||
[CreateAssetMenu(fileName = "Cadence Profile", menuName = "GON/Services/Cadence/Cadence Profile")]
|
||||
public sealed class CadenceProfile : ScriptableObject
|
||||
{
|
||||
[SerializeField, Min(1f)] private float totalTimeMS = 370f;
|
||||
[GroupConfigurations("Normalized Band End Points"), SerializeField, Range(0f, 1f)] private float strained;
|
||||
[GroupConfigurations("Normalized Band End Points"), SerializeField, Range(0f, 1f)] private float aligned;
|
||||
[GroupConfigurations("Normalized Band End Points"), SerializeField, Range(0f, 1f)] private float resonant;
|
||||
|
||||
[GroupConfigurations("Normalized Band End Points"), SerializeField, Range(0f, 1f)] private float strainedEndP = 0.25f;
|
||||
[GroupConfigurations("Normalized Band End Points"), SerializeField, Range(0f, 1f)] private float alignedEndP = 0.65f;
|
||||
[GroupConfigurations("Normalized Band End Points"), SerializeField, Range(0f, 1f)] private float resonantEndP = 1f;
|
||||
|
||||
[GroupConfigurations("Settlement"), SerializeField, Range(0f, 1f)] private float strainedSettlement = 1f;
|
||||
[GroupConfigurations("Settlement"), SerializeField, Range(0f, 1f)] private float alignedSettlement = 0.5f;
|
||||
[GroupConfigurations("Settlement"), SerializeField, Range(0f, 1f)] private float strainedSettlement;
|
||||
[GroupConfigurations("Settlement"), SerializeField, Range(0f, 1f)] private float alignedSettlement;
|
||||
[GroupConfigurations("Settlement"), SerializeField, Range(0f, 1f)] private float resonantSettlement;
|
||||
[GroupConfigurations("Settlement"), SerializeField, Range(0f, 1f)] private float lateSettlement = 1f;
|
||||
[GroupConfigurations("Settlement"), SerializeField, Range(0f, 1f)] private float lateSettlement;
|
||||
|
||||
[GroupConfigurations("Core Stability"), SerializeField, Range(0, 100)] private float maxCoreCost = 8f;
|
||||
[GroupConfigurations("Core Stability"), SerializeField, Range(0, 100)] private float resonantRecovery = 8f;
|
||||
|
||||
public float TotalTimeMS => totalTimeMS;
|
||||
|
||||
public float TotalTime => TotalTimeMS * 0.001f;
|
||||
|
||||
public float StrainedEndP => strainedEndP;
|
||||
public float AlignedEndP => alignedEndP;
|
||||
public float ResonantEndP => resonantEndP;
|
||||
|
||||
// public float StrainedEndTime => TotalTime * strainedEndP;
|
||||
// public float AlignedEndTime => TotalTime * alignedEndP;
|
||||
// public float ResonantEndTime => TotalTime * resonantEndP;
|
||||
//
|
||||
// public float StrainedEndMS => totalTimeMS * strainedEndP;
|
||||
// public float AlignedEndMS => totalTimeMS * alignedEndP;
|
||||
// public float ResonantEndMS => totalTimeMS * resonantEndP;
|
||||
|
||||
public float StrainedSettlement => strainedSettlement;
|
||||
public float AlignedSettlement => alignedSettlement;
|
||||
public float ResonantSettlement => resonantSettlement;
|
||||
public float LateSettlement => lateSettlement;
|
||||
[GroupConfigurations("Core Stability"), SerializeField, Range(0, 50)] private float maxCoreCost;
|
||||
[GroupConfigurations("Core Stability"), SerializeField, Range(0, 50)] private float resonantRecovery;
|
||||
|
||||
public float MaxCoreCost => maxCoreCost;
|
||||
public float ResonantRecovery => resonantRecovery;
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
@ -53,21 +29,12 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.Cadence
|
||||
[GroupDebug, Button(ButtonSizes.Medium)]
|
||||
private void Validate()
|
||||
{
|
||||
totalTimeMS = Mathf.Max(1f, totalTimeMS);
|
||||
strained = Mathf.Clamp01(strained);
|
||||
aligned = Mathf.Clamp01(aligned);
|
||||
resonant = Mathf.Clamp01(resonant);
|
||||
|
||||
strainedEndP = Mathf.Clamp01(strainedEndP);
|
||||
alignedEndP = Mathf.Clamp01(alignedEndP);
|
||||
resonantEndP = Mathf.Clamp01(resonantEndP);
|
||||
|
||||
if (alignedEndP < strainedEndP)
|
||||
{
|
||||
alignedEndP = strainedEndP;
|
||||
}
|
||||
|
||||
if (resonantEndP < alignedEndP)
|
||||
{
|
||||
resonantEndP = alignedEndP;
|
||||
}
|
||||
if (aligned < strained) aligned = strained;
|
||||
if (resonant < aligned) resonant = aligned;
|
||||
|
||||
strainedSettlement = Mathf.Clamp01(strainedSettlement);
|
||||
alignedSettlement = Mathf.Clamp01(alignedSettlement);
|
||||
@ -78,55 +45,32 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.Cadence
|
||||
resonantRecovery = Mathf.Max(0f, resonantRecovery);
|
||||
}
|
||||
|
||||
public CadenceEvaluation Evaluate(float elapsedTime)
|
||||
public CadenceEvaluation Evaluate(float t)
|
||||
{
|
||||
if (TotalTime <= 0f)
|
||||
{
|
||||
return CadenceEvaluation.None;
|
||||
if (t < strained) return StrainedEvaluation();
|
||||
if (t < aligned) return AlignedEvaluation();
|
||||
if (t < resonant) return ResonantEvaluation();
|
||||
return StrainedEvaluation();
|
||||
}
|
||||
|
||||
var t = Mathf.Clamp01(elapsedTime / TotalTime);
|
||||
|
||||
if (t < StrainedEndP)
|
||||
public CadenceEvaluation StrainedEvaluation()
|
||||
{
|
||||
return new CadenceEvaluation(
|
||||
t,
|
||||
elapsedTime,
|
||||
CadenceBand.Strained,
|
||||
StrainedSettlement,
|
||||
0f
|
||||
);
|
||||
return new CadenceEvaluation(CadenceBand.Strained, strainedSettlement, 0f);
|
||||
}
|
||||
|
||||
if (t < AlignedEndP)
|
||||
public CadenceEvaluation AlignedEvaluation()
|
||||
{
|
||||
return new CadenceEvaluation(
|
||||
t,
|
||||
elapsedTime,
|
||||
CadenceBand.Aligned,
|
||||
AlignedSettlement,
|
||||
0f
|
||||
);
|
||||
return new CadenceEvaluation(CadenceBand.Aligned, alignedSettlement, 0f);
|
||||
}
|
||||
|
||||
if (t < ResonantEndP)
|
||||
public CadenceEvaluation ResonantEvaluation()
|
||||
{
|
||||
return new CadenceEvaluation(
|
||||
t,
|
||||
elapsedTime,
|
||||
CadenceBand.Resonant,
|
||||
ResonantSettlement,
|
||||
ResonantRecovery
|
||||
);
|
||||
return new CadenceEvaluation(CadenceBand.Resonant, resonantSettlement, resonantRecovery);
|
||||
}
|
||||
|
||||
return new CadenceEvaluation(
|
||||
t,
|
||||
elapsedTime,
|
||||
CadenceBand.Late,
|
||||
LateSettlement,
|
||||
0f
|
||||
);
|
||||
public CadenceEvaluation LateEvaluation()
|
||||
{
|
||||
return new CadenceEvaluation(CadenceBand.Late, lateSettlement, 0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using Intrepid.Core.TimeControl;
|
||||
using Intrepid.Diagnostics;
|
||||
using Intrepid.Utilities;
|
||||
using UnityEngine;
|
||||
|
||||
@ -8,88 +10,87 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.Cadence
|
||||
[CreateAssetMenu(fileName = "Cadence Service", menuName = "GON/Services/Cadence/Cadence Service")]
|
||||
public class CadenceService : SingletonScriptableObject<CadenceService>
|
||||
{
|
||||
private Timer CadenceTimer { get; set; } = new();
|
||||
private Timer CadenceProfileTimer { get; set; } = new();
|
||||
private Timer CadenceTotalTimer { get; set; } = new();
|
||||
private CadenceProfile CurrentProfile { get; set; }
|
||||
private float TargetTime { get; set; }
|
||||
private float StartedProfileAt { get; set; }
|
||||
|
||||
public bool IsCadenceRunning => CadenceTimer.IsRunning;
|
||||
public float CadenceElapsedTime => (float)CadenceTimer.ElapsedTime;
|
||||
public bool IsCadenceRunning => CadenceProfileTimer.IsRunning;
|
||||
private float CadenceProfileElapsedTime => (float)CadenceProfileTimer.ElapsedTime; // elapsed time since a single cadence began
|
||||
public float TotalCadenceElapsedTime => (float)CadenceTotalTimer.ElapsedTime; // elapsed time since first cadence began
|
||||
|
||||
private float _startedAt;
|
||||
|
||||
protected override void WhenInstantiate(CadenceService s)
|
||||
{
|
||||
base.WhenInstantiate(s);
|
||||
ResetCadence();
|
||||
ResetCadenceProfile();
|
||||
CadenceTotalTimer.Stop();
|
||||
}
|
||||
|
||||
public void BeginCadence(CadenceProfile profile, float elapsedTime)
|
||||
public void BeginCadence(CadenceProfile profile, float targetTime)
|
||||
{
|
||||
if (profile is null)
|
||||
if (profile is null || targetTime <= 0)
|
||||
{
|
||||
ResetCadence();
|
||||
DLogger.LogError($"profile should not be null: (is null? {profile.IsNull()}); targetTime should be > 0: {targetTime}");
|
||||
ResetCadenceProfile();
|
||||
return;
|
||||
}
|
||||
|
||||
_startedAt = elapsedTime;
|
||||
StartedProfileAt = TimeSimulation.Instance.ScaledElapsedTime;
|
||||
CurrentProfile = profile;
|
||||
CadenceTimer.Start();
|
||||
TargetTime = targetTime;
|
||||
CadenceProfileTimer.Start();
|
||||
if (CadenceTotalTimer.IsNotRunning) CadenceTotalTimer.Start();
|
||||
}
|
||||
|
||||
public CadenceEvaluation EvaluateAndConsumeAt(float inputTimeAt)
|
||||
public CadenceEvaluation EndCadence()
|
||||
{
|
||||
CadenceTotalTimer.Stop();
|
||||
|
||||
if (!IsCadenceRunning || CurrentProfile is null) // if cadence was already ended
|
||||
{
|
||||
return CadenceEvaluation.None;
|
||||
}
|
||||
|
||||
var cadenceEvaluation = CurrentProfile.LateEvaluation();
|
||||
ResetCadenceProfile();
|
||||
|
||||
return cadenceEvaluation;
|
||||
}
|
||||
|
||||
public CadenceEvaluation TryEndCadenceProfileWithInputAt(float inputAt)
|
||||
{
|
||||
if (!IsCadenceRunning || CurrentProfile is null)
|
||||
{
|
||||
return CadenceEvaluation.None;
|
||||
}
|
||||
|
||||
var elapsedAtInput = Mathf.Max(0f, inputTimeAt - _startedAt);
|
||||
var evaluation = CurrentProfile.Evaluate(elapsedAtInput);
|
||||
ResetCadence();
|
||||
var elapsedAtInput = Mathf.Max(0f, inputAt - StartedProfileAt);
|
||||
var evaluation = CurrentProfile.Evaluate(elapsedAtInput / TargetTime);
|
||||
ResetCadenceProfile();
|
||||
|
||||
return evaluation;
|
||||
}
|
||||
|
||||
public CadenceEvaluation EvaluateAndConsume()
|
||||
public bool UpdateCadence(float deltaTime)
|
||||
{
|
||||
if (!IsCadenceRunning || CurrentProfile is null)
|
||||
{
|
||||
return CadenceEvaluation.None;
|
||||
}
|
||||
|
||||
var evaluation = CurrentProfile.Evaluate(CadenceElapsedTime);
|
||||
|
||||
ResetCadence();
|
||||
|
||||
return evaluation;
|
||||
}
|
||||
|
||||
public bool UpdateCadence(out CadenceEvaluation autoSettlement)
|
||||
{
|
||||
autoSettlement = CadenceEvaluation.None;
|
||||
|
||||
if (!IsCadenceRunning || CurrentProfile is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CadenceTimer.Update(Timer.ScaledTime);
|
||||
|
||||
if (!CadenceTimer.Check(CurrentProfile.TotalTime))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
autoSettlement = CurrentProfile.Evaluate(CadenceElapsedTime);
|
||||
|
||||
ResetCadence();
|
||||
CadenceProfileTimer.Update(deltaTime);
|
||||
CadenceTotalTimer.Update(deltaTime);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ResetCadence()
|
||||
public void ResetCadenceProfile()
|
||||
{
|
||||
CadenceTimer.Stop();
|
||||
CadenceProfileTimer.Stop();
|
||||
CurrentProfile = null;
|
||||
TargetTime = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,3 @@
|
||||
using Intrepid.Gameplay.Entities.Player.Sentinel.Inputs;
|
||||
using Intrepid.Utilities;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
@ -15,12 +14,18 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.Cadence.UI
|
||||
[GroupInjections, SerializeField] private Slider effective;
|
||||
[GroupInjections, SerializeField] private Slider projection;
|
||||
|
||||
private string _lastCadenceTimer;
|
||||
private string _lastCadenceConnectedCounter;
|
||||
|
||||
private void Update()
|
||||
{
|
||||
cadenceTimer.text = CadenceService.Instance.IsCadenceRunning
|
||||
? CadenceService.Instance.CadenceElapsedTime.ToString("F2")
|
||||
: "--";
|
||||
btnElapsedTimes.text = controls.CadenceConnectedCounter.ToString();
|
||||
if (CadenceService.Instance.IsCadenceRunning)
|
||||
{
|
||||
_lastCadenceTimer = $"{CadenceService.Instance.TotalCadenceElapsedTime * 1000f:F2}ms";
|
||||
_lastCadenceConnectedCounter = $"{controls.CadenceConnectedCounter}";
|
||||
}
|
||||
cadenceTimer.text = _lastCadenceTimer;
|
||||
btnElapsedTimes.text = _lastCadenceConnectedCounter;
|
||||
effective.value = CoreStabilityService.Instance.EffectiveStabilityP;
|
||||
projection.value = CoreStabilityService.Instance.ProjectedStabilityP;
|
||||
}
|
||||
|
||||
@ -1,24 +1,20 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Intrepid.Core;
|
||||
using Intrepid.Core.Camera;
|
||||
using Intrepid.Core.Entities;
|
||||
using Intrepid.Core.Entities.Messages;
|
||||
using Intrepid.Core.Grounding;
|
||||
using Intrepid.Core.TimeControl;
|
||||
using Intrepid.Gameplay.Entities.Player.ActionBelt;
|
||||
using Intrepid.Gameplay.Entities.Player.Sentinel;
|
||||
using Intrepid.Gameplay.Entities.Player.Sentinel.Cadence;
|
||||
using Intrepid.Gameplay.Entities.Player.Sentinel.StateMachine;
|
||||
using Intrepid.Structures;
|
||||
using Intrepid.Utilities;
|
||||
using Unity.Cinemachine;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Intrepid.Gameplay.Entities.Player.Sentinel
|
||||
{
|
||||
public class SentinelBrain : EntityBrain
|
||||
{
|
||||
[GroupInjections, SerializeField] private SentinelConfig config;
|
||||
[GroupInjections, SerializeField] private PlayerInputResolver inputResolver;
|
||||
[GroupInjections, SerializeField] private SentinelControls controls;
|
||||
[GroupInjections, SerializeField] private ActionBeltManager actionBeltManager;
|
||||
@ -29,6 +25,7 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel
|
||||
|
||||
public SentinelEntity Entity => RootEntity as SentinelEntity;
|
||||
public SentinelStateType CurrentState => StateMachine.CurrentImplementation.GetStateKey();
|
||||
public SentinelConfig Config => config;
|
||||
public PlayerInputResolver InputResolver => inputResolver;
|
||||
public SentinelControls Controls => controls;
|
||||
public ActionBeltManager ActionBeltManager => actionBeltManager;
|
||||
@ -84,19 +81,7 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel
|
||||
StateMachine.CurrentImplementation.RunOnUpdate();
|
||||
StateMachine.CurrentImplementation.RunAfterUpdate();
|
||||
|
||||
if (CadenceService.Instance.UpdateCadence(out var evaluation))
|
||||
{
|
||||
// DLogger.LogDebug(
|
||||
// $"CADENCE EXPIRED: {evaluation.Band} " +
|
||||
// $"t={evaluation.T * 100f}% " +
|
||||
// $"elapsedAt={evaluation.ElapsedAt * 1000f}ms " +
|
||||
// $"set={evaluation.SettlementFactor} " +
|
||||
// $"rec={evaluation.Recovery}"
|
||||
// );
|
||||
Controls.ExpireCadence();
|
||||
CoreStabilityService.Instance.Settle(evaluation);
|
||||
}
|
||||
|
||||
CadenceService.Instance.UpdateCadence(Timer.ScaledTime);
|
||||
CoreStabilityService.Instance.UpdateCore(Timer.ScaledTime);
|
||||
|
||||
// state machine could take this responsibility in the future...
|
||||
|
||||
@ -0,0 +1,117 @@
|
||||
using System;
|
||||
using Intrepid.Utilities;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Intrepid.Gameplay.Entities.Player.Sentinel
|
||||
{
|
||||
[Serializable, HideLabel, GroupConfigurations("Walk")]
|
||||
public class WalkConfig
|
||||
{
|
||||
[SerializeField, Range(0, 100)] private float speed = 5;
|
||||
|
||||
public float Speed => speed;
|
||||
}
|
||||
|
||||
[Serializable, HideLabel, GroupConfigurations("Run")]
|
||||
public class RunConfig
|
||||
{
|
||||
[SerializeField, Range(0, 100)] private float speed = 10;
|
||||
|
||||
public float Speed => speed;
|
||||
}
|
||||
|
||||
[Serializable, HideLabel, GroupConfigurations("Dash Impulse")]
|
||||
public class DashImpulseConfig
|
||||
{
|
||||
[SerializeField, Range(0, 50)] private float speed = 35f;
|
||||
[SerializeField, Range(0, 5000)] private float durationMS = 150f;
|
||||
|
||||
public float Speed => speed;
|
||||
public float Duration => durationMS * 0.001f;
|
||||
}
|
||||
|
||||
[Serializable, HideLabel, GroupConfigurations("Dash Recovery")]
|
||||
public class DashRecoveryConfig
|
||||
{
|
||||
[SerializeField, Range(0, 30)] private float speed = 10;
|
||||
[SerializeField, Range(0, 5000)] private float durationMS = 200f;
|
||||
[SerializeField, Range(15, 90)] private float dashMaxAngleFromForward = 90f;
|
||||
[SerializeField] private AnimationCurve speedCurve;
|
||||
|
||||
public float Speed => speed;
|
||||
public float Duration => durationMS * 0.001f;
|
||||
public float DashMaxAngleFromForward => dashMaxAngleFromForward;
|
||||
public AnimationCurve SpeedCurve => speedCurve;
|
||||
}
|
||||
|
||||
[Serializable, HideLabel, GroupConfigurations("Dash Landing")]
|
||||
public class DashLandingConfig
|
||||
{
|
||||
[SerializeField, Range(0, 500)] private float durationMS = 100f;
|
||||
|
||||
public float Duration => durationMS * 0.001f;
|
||||
}
|
||||
|
||||
[Serializable, HideLabel, GroupConfigurations("Dash Breaking")]
|
||||
public class DashBreakingConfig
|
||||
{
|
||||
[SerializeField, Range(5, 30)] private float speed = 10;
|
||||
[SerializeField, Range(0, 500)] private float durationMS = 300f;
|
||||
[SerializeField] private AnimationCurve speedCurve;
|
||||
|
||||
public float Speed => speed;
|
||||
public float Duration => durationMS * 0.001f;
|
||||
public AnimationCurve SpeedCurve => speedCurve;
|
||||
}
|
||||
|
||||
[Serializable, HideLabel, GroupConfigurations("Fall Landing")]
|
||||
public class FallLandingConfig
|
||||
{
|
||||
[SerializeField, Range(0, 5000)] private float durationMS = 2000f;
|
||||
|
||||
public float Duration => durationMS * 0.001f;
|
||||
}
|
||||
|
||||
[Serializable, HideLabel, GroupConfigurations("Knockdown")]
|
||||
public class KnockdownConfig
|
||||
{
|
||||
[SerializeField] private float knockoutTimeMultiplier = 0.1f;
|
||||
[SerializeField, Range(0, 3000)] private float knockdownDurationMS = 100f;
|
||||
[SerializeField, Range(0, 3000)] private float recoverDurationMS = 500f;
|
||||
[SerializeField] private float maxKnockdownStrength = 15f;
|
||||
|
||||
public float KnockoutTimeMultiplier => knockoutTimeMultiplier;
|
||||
public float KnockdownDuration => knockdownDurationMS * 0.001f;
|
||||
public float RecoverDuration => recoverDurationMS * 0.001f;
|
||||
public float MaxKnockdownStrength => maxKnockdownStrength;
|
||||
}
|
||||
|
||||
[CreateAssetMenu(fileName = "Sentinel Config", menuName = "GON/Services/Sentinel/Config")]
|
||||
public class SentinelConfig : ScriptableObject
|
||||
{
|
||||
[SerializeField] private WalkConfig walk;
|
||||
[SerializeField] private RunConfig run;
|
||||
|
||||
[SerializeField] private DashImpulseConfig dashImpulse;
|
||||
[SerializeField] private DashRecoveryConfig dashRecovery;
|
||||
[SerializeField] private DashLandingConfig dashLanding;
|
||||
[SerializeField] private DashBreakingConfig dashBreaking;
|
||||
|
||||
[SerializeField] private FallLandingConfig fallLanding;
|
||||
|
||||
[SerializeField] private KnockdownConfig knockdown;
|
||||
|
||||
public WalkConfig Walk => walk;
|
||||
public RunConfig Run => run;
|
||||
|
||||
public DashImpulseConfig DashImpulse => dashImpulse;
|
||||
public DashRecoveryConfig DashRecovery => dashRecovery;
|
||||
public DashLandingConfig DashLanding => dashLanding;
|
||||
public DashBreakingConfig DashBreaking => dashBreaking;
|
||||
|
||||
public FallLandingConfig FallLanding => fallLanding;
|
||||
|
||||
public KnockdownConfig Knockdown => knockdown;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f28542aec01041178adfbc30f7a2a82a
|
||||
timeCreated: 1781369939
|
||||
@ -74,27 +74,16 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.StateMachine
|
||||
}
|
||||
}
|
||||
|
||||
protected void BeginCadencedActionAt(CadenceProfile profile, float actionTimeAt)
|
||||
{
|
||||
LogAndProjectCadence(profile, CadenceService.Instance.EvaluateAndConsumeAt(actionTimeAt));
|
||||
}
|
||||
|
||||
protected void BeginCadencedAction(CadenceProfile profile)
|
||||
{
|
||||
LogAndProjectCadence(profile, CadenceService.Instance.EvaluateAndConsume());
|
||||
}
|
||||
|
||||
private void LogAndProjectCadence(CadenceProfile profile, CadenceEvaluation previousEvaluation)
|
||||
protected void KeepCadenceWithInputAt(CadenceProfile nextProfile, float targetTime, float inputAt)
|
||||
{
|
||||
var previousEvaluation = CadenceService.Instance.TryEndCadenceProfileWithInputAt(inputAt);
|
||||
if (previousEvaluation.Band != CadenceBand.None)
|
||||
{
|
||||
// DLogger.LogDebug(
|
||||
// $"CADENCE CONNECTED: {previousEvaluation.Band} " +
|
||||
// $"t={previousEvaluation.T * 100f}% " +
|
||||
// $"elapsedAt={previousEvaluation.ElapsedAt * 1000f}ms " +
|
||||
// $"set={previousEvaluation.SettlementFactor} " +
|
||||
// $"rec={previousEvaluation.Recovery}"
|
||||
// );
|
||||
DLogger.LogDebug(
|
||||
$"CADENCE CONNECTED: {previousEvaluation.Band} " +
|
||||
$"set={previousEvaluation.SettlementFactor} " +
|
||||
$"rec={previousEvaluation.Recovery}"
|
||||
);
|
||||
|
||||
Brain.Controls.CadenceConnectedCounterInc();
|
||||
CoreStabilityService.Instance.Settle(previousEvaluation);
|
||||
@ -104,8 +93,20 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.StateMachine
|
||||
Brain.Controls.ExpireCadence();
|
||||
}
|
||||
|
||||
CoreStabilityService.Instance.ProjectCost(profile.MaxCoreCost);
|
||||
CadenceService.Instance.BeginCadence(profile, TimeSimulation.Instance.ScaledElapsedTime);
|
||||
CoreStabilityService.Instance.ProjectCost(nextProfile.MaxCoreCost);
|
||||
CadenceService.Instance.BeginCadence(nextProfile, targetTime);
|
||||
}
|
||||
|
||||
protected void EndCadence()
|
||||
{
|
||||
var evaluation = CadenceService.Instance.EndCadence();
|
||||
DLogger.LogDebug(
|
||||
$"CADENCE ENDED: {evaluation.Band} " +
|
||||
$"set={evaluation.SettlementFactor} " +
|
||||
$"rec={evaluation.Recovery}"
|
||||
);
|
||||
CoreStabilityService.Instance.Settle(evaluation);
|
||||
Brain.Controls.ExpireCadence();
|
||||
}
|
||||
|
||||
protected bool TryConsumeDash()
|
||||
@ -113,7 +114,8 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.StateMachine
|
||||
if (Brain.InputResolver.Sentinel.TryConsumeDash(out var dashTimeAt)) // dash with no ground: this could be a feature to be unlocked
|
||||
//if (Brain.Entity.IsGrounded && Brain.InputResolver.TryConsumeDash(out var dashTimeAt))
|
||||
{
|
||||
BeginCadencedActionAt(Brain.Cadences.DashProfile, dashTimeAt);
|
||||
var targetTime = Brain.Config.DashImpulse.Duration + Brain.Config.DashRecovery.Duration;
|
||||
KeepCadenceWithInputAt(Brain.Cadences.DashProfile, targetTime, dashTimeAt);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@ -7,12 +7,8 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.StateMachine.States
|
||||
public class SentinelStateDashBreaking : SentinelState
|
||||
{
|
||||
[GroupConfigurations, SerializeField] private AnimationClip dashBreaking;
|
||||
[GroupConfigurations, SerializeField, Range(5, 30)] private float speed = 10;
|
||||
[GroupConfigurations, SerializeField, Range(0, 500)] private float extraTimeMS = 300f;
|
||||
[GroupConfigurations, SerializeField] private AnimationCurve speedCurve;
|
||||
|
||||
private Timer Timer { get; } = new();
|
||||
private float ExtraTime => extraTimeMS * 0.001f;
|
||||
|
||||
public override SentinelStateType GetStateKey()
|
||||
{
|
||||
@ -25,6 +21,7 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.StateMachine.States
|
||||
|
||||
protected override void RunOnEnter(ParameterStore parameterStore)
|
||||
{
|
||||
EndCadence();
|
||||
Brain.Controls.ResetDash();
|
||||
Brain.Entity.ModelAnimation.Play(dashBreaking);
|
||||
Timer.Stop();
|
||||
@ -49,14 +46,15 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.StateMachine.States
|
||||
}
|
||||
else
|
||||
{
|
||||
Brain.Entity.DesiredVelocity = Brain.Entity.Forward * speed;
|
||||
Brain.Entity.DesiredVelocity = Brain.Entity.Forward * Brain.Config.DashBreaking.Speed;
|
||||
}
|
||||
|
||||
if (Timer.IsNotRunning) return;
|
||||
Timer.Update(Time.deltaTime);
|
||||
var evaluation = speedCurve.Evaluate((float) Timer.ElapsedTime / ExtraTime);
|
||||
Brain.Entity.DesiredVelocity = Brain.Entity.Forward * (speed * evaluation);
|
||||
if (Timer.Check(ExtraTime))
|
||||
var speedCurve = Brain.Config.DashBreaking.SpeedCurve;
|
||||
var evaluation = speedCurve.Evaluate((float) Timer.ElapsedTime / Brain.Config.DashBreaking.Duration);
|
||||
Brain.Entity.DesiredVelocity = Brain.Entity.Forward * (Brain.Config.DashBreaking.Speed * evaluation);
|
||||
if (Timer.Check(Brain.Config.DashBreaking.Duration))
|
||||
{
|
||||
Timer.Stop();
|
||||
Brain.ChangeState(SentinelStateType.Idle);
|
||||
|
||||
@ -8,10 +8,6 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.StateMachine.States
|
||||
public class SentinelStateDashImpulse : SentinelState
|
||||
{
|
||||
[GroupConfigurations, SerializeField] private AnimationClip dash;
|
||||
[GroupConfigurations, SerializeField, Range(0, 100)] private float speed = 35;
|
||||
[GroupConfigurations, SerializeField, Range(0, 5000)] private float targetTimeMS = 100f;
|
||||
|
||||
public float TargetTime => targetTimeMS * 0.001f;
|
||||
|
||||
private Timer Timer { get; } = new();
|
||||
|
||||
@ -52,9 +48,9 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.StateMachine.States
|
||||
{
|
||||
Timer.Update(Time.deltaTime);
|
||||
|
||||
Brain.Entity.DesiredVelocity = Brain.Entity.Forward * speed;
|
||||
Brain.Entity.DesiredVelocity = Brain.Entity.Forward * Brain.Config.DashImpulse.Speed;
|
||||
|
||||
if (!Timer.Check(TargetTime))
|
||||
if (!Timer.Check(Brain.Config.DashImpulse.Duration))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@ -7,10 +7,8 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.StateMachine.States
|
||||
public class SentinelStateDashLanding : SentinelState
|
||||
{
|
||||
[GroupConfigurations, SerializeField] private AnimationClip dashLanding;
|
||||
[GroupConfigurations, SerializeField, Range(0, 500)] private float landingTimeMS = 100f;
|
||||
|
||||
private Timer Timer { get; } = new();
|
||||
private float LandingTime => landingTimeMS * 0.001f;
|
||||
|
||||
public override SentinelStateType GetStateKey()
|
||||
{
|
||||
@ -23,6 +21,7 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.StateMachine.States
|
||||
|
||||
protected override void RunOnEnter(ParameterStore parameterStore)
|
||||
{
|
||||
EndCadence();
|
||||
Brain.Controls.ResetDash();
|
||||
Brain.Entity.DesiredVelocity = Vector2.zero;
|
||||
Brain.Entity.ModelAnimation.CrossFade(dashLanding, .1f);
|
||||
@ -39,7 +38,7 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.StateMachine.States
|
||||
{
|
||||
if (Timer.IsNotRunning) return;
|
||||
Timer.Update(Timer.ScaledTime);
|
||||
if (Timer.Check(LandingTime))
|
||||
if (Timer.Check(Brain.Config.DashLanding.Duration))
|
||||
{
|
||||
Timer.Stop();
|
||||
Brain.ChangeState(SentinelStateType.Idle);
|
||||
|
||||
@ -8,12 +8,7 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.StateMachine.States
|
||||
public class SentinelStateDashRecovery : SentinelState
|
||||
{
|
||||
[GroupConfigurations, SerializeField] private AnimationClip dashRecovery;
|
||||
[GroupConfigurations, SerializeField, Range(0, 30)] private float speed = 10;
|
||||
[GroupConfigurations, SerializeField, Range(15, 90)] private float dashMaxAngleFromForward = 60f;
|
||||
[GroupConfigurations, SerializeField, Range(0, 5000)] private float targetTimeMS = 200f;
|
||||
[GroupConfigurations, SerializeField] private AnimationCurve speedCurve;
|
||||
|
||||
public float TargetTime => targetTimeMS * 0.001f;
|
||||
private Timer Timer { get; } = new();
|
||||
|
||||
public override SentinelStateType GetStateKey()
|
||||
@ -55,7 +50,7 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.StateMachine.States
|
||||
var movement = Brain.InputResolver.Sentinel.Movement();
|
||||
var forward = Brain.Entity.Forward;
|
||||
var direction = GonFunctions
|
||||
.ConstrainDirectionToForwardCone(movement, forward, dashMaxAngleFromForward);
|
||||
.ConstrainDirectionToForwardCone(movement, forward, Brain.Config.DashRecovery.DashMaxAngleFromForward);
|
||||
Brain.Entity.ChangeOrientation(direction);
|
||||
return;
|
||||
}
|
||||
@ -72,14 +67,15 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.StateMachine.States
|
||||
return;
|
||||
}
|
||||
Timer.Update(Time.deltaTime);
|
||||
if (Timer.Check(TargetTime))
|
||||
if (Timer.Check(Brain.Config.DashRecovery.Duration))
|
||||
{
|
||||
Timer.Stop();
|
||||
return;
|
||||
}
|
||||
|
||||
var speedFactor = 1f + speedCurve.Evaluate((float)Timer.ElapsedTime / TargetTime);
|
||||
Brain.Entity.DesiredVelocity = Brain.Entity.Forward * (speed * speedFactor);
|
||||
var speedCurve = Brain.Config.DashRecovery.SpeedCurve;
|
||||
var speedFactor = 1f + speedCurve.Evaluate((float)Timer.ElapsedTime / Brain.Config.DashRecovery.Duration);
|
||||
Brain.Entity.DesiredVelocity = Brain.Entity.Forward * (Brain.Config.DashRecovery.Speed * speedFactor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -26,6 +26,7 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.StateMachine.States
|
||||
|
||||
protected override void RunOnEnter(ParameterStore ps)
|
||||
{
|
||||
EndCadence();
|
||||
Brain.Controls.ResetDash();
|
||||
Brain.Entity.ModelAnimation.CrossFade(fall, .1f);
|
||||
Brain.Entity.DesiredVelocity = Vector2.zero;
|
||||
|
||||
@ -7,7 +7,6 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.StateMachine.States
|
||||
public class SentinelStateFallLanding : SentinelState
|
||||
{
|
||||
[GroupConfigurations, SerializeField] private AnimationClip fallLanding;
|
||||
[GroupConfigurations, SerializeField, Range(0, 5)] private float fallLandingDuration = 2f;
|
||||
|
||||
private Timer Timer { get; } = new();
|
||||
|
||||
@ -36,7 +35,7 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.StateMachine.States
|
||||
{
|
||||
if (Timer.IsNotRunning) return;
|
||||
Timer.Update(Timer.ScaledTime);
|
||||
if (!Timer.Check(fallLandingDuration)) return;
|
||||
if (!Timer.Check(Brain.Config.FallLanding.Duration)) return;
|
||||
Timer.Stop();
|
||||
Brain.ChangeState(SentinelStateType.Idle);
|
||||
}
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
using Intrepid.Diagnostics;
|
||||
using Intrepid.Structures;
|
||||
using Intrepid.Utilities;
|
||||
using UnityEngine;
|
||||
@ -9,10 +8,6 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.StateMachine.States
|
||||
{
|
||||
[GroupConfigurations, SerializeField] private AnimationClip knockdown;
|
||||
[GroupConfigurations, SerializeField] private AnimationClip knockout;
|
||||
[GroupConfigurations, SerializeField] private float KnockoutTimeMultiplier = 0.1f;
|
||||
[GroupConfigurations, SerializeField, Range(0, 3)] private float knockdownTime = .1f;
|
||||
[GroupConfigurations, SerializeField, Range(0, 3)] private float recoverTime = .5f;
|
||||
[GroupConfigurations, SerializeField] private float maxKnockdown = 15f;
|
||||
|
||||
private Vector2 KnockdownForce { get; set; }
|
||||
private float KnockoutTime { get; set; }
|
||||
@ -34,8 +29,8 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.StateMachine.States
|
||||
Brain.Entity.ModelAnimation.CrossFade(knockdown, 0.1f);
|
||||
KnockdownForce = ps.Get<Vector2>(SentinelConstants.Parameters.KnockdownForce);
|
||||
Brain.Entity.ChangeOrientation(-KnockdownForce.normalized);
|
||||
KnockoutTime = KnockdownForce.sqrMagnitude * KnockoutTimeMultiplier;
|
||||
Brain.Entity.DesiredVelocity = Vector2.ClampMagnitude(KnockdownForce, maxKnockdown);
|
||||
KnockoutTime = KnockdownForce.sqrMagnitude * Brain.Config.Knockdown.KnockoutTimeMultiplier;
|
||||
Brain.Entity.DesiredVelocity = Vector2.ClampMagnitude(KnockdownForce, Brain.Config.Knockdown.MaxKnockdownStrength);
|
||||
KnockdownTimer.Start();
|
||||
KnockoutTimer.Stop();
|
||||
RecoverTimer.Stop();
|
||||
@ -50,7 +45,7 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.StateMachine.States
|
||||
if (RecoverTimer.IsRunning)
|
||||
{
|
||||
RecoverTimer.Update(Timer.ScaledTime);
|
||||
if (RecoverTimer.Check(recoverTime))
|
||||
if (RecoverTimer.Check(Brain.Config.Knockdown.RecoverDuration))
|
||||
{
|
||||
RecoverTimer.Stop();
|
||||
Brain.ChangeState(SentinelStateType.Idle);
|
||||
@ -62,7 +57,7 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.StateMachine.States
|
||||
if (KnockoutTimer.IsRunning)
|
||||
{
|
||||
KnockoutTimer.Update(Timer.ScaledTime);
|
||||
if (KnockoutTimer.Check(recoverTime))
|
||||
if (KnockoutTimer.Check(Brain.Config.Knockdown.RecoverDuration))
|
||||
{
|
||||
KnockoutTimer.Stop();
|
||||
RecoverTimer.Start();
|
||||
@ -86,7 +81,7 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.StateMachine.States
|
||||
}
|
||||
|
||||
KnockdownTimer.Update(Timer.ScaledTime);
|
||||
if (KnockdownTimer.Check(knockdownTime))
|
||||
if (KnockdownTimer.Check(Brain.Config.Knockdown.KnockdownDuration))
|
||||
{
|
||||
KnockdownTimer.Stop();
|
||||
Brain.Entity.ModelAnimation.CrossFade(knockout, 0.1f);
|
||||
|
||||
@ -7,8 +7,7 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.StateMachine.States
|
||||
public class SentinelStateRun : SentinelState
|
||||
{
|
||||
[GroupConfigurations, SerializeField] private AnimationClip run;
|
||||
[GroupConfigurations, SerializeField, Range(0, 100)] private float speed = 10;
|
||||
[GroupConfigurations, SerializeField, Range(0, 10)] private float animationSpeed = 1.2f;
|
||||
[GroupConfigurations, SerializeField, Range(0, 10)] private float animationSpeed = 3f;
|
||||
|
||||
private Vector2 Movement { get; set; }
|
||||
|
||||
@ -43,7 +42,7 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.StateMachine.States
|
||||
return;
|
||||
}
|
||||
if (CheckMovement()) return;
|
||||
Brain.Entity.DesiredVelocity = Movement * speed;
|
||||
Brain.Entity.DesiredVelocity = Movement * Brain.Config.Run.Speed;
|
||||
}
|
||||
|
||||
private bool CheckMovement()
|
||||
|
||||
@ -7,8 +7,7 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.StateMachine.States
|
||||
public class SentinelStateWalk : SentinelState
|
||||
{
|
||||
[GroupConfigurations, SerializeField] private AnimationClip walk;
|
||||
[GroupConfigurations, SerializeField, Range(0, 100)] private float speed = 5;
|
||||
[GroupConfigurations, SerializeField, Range(0, 100)] private float animationSpeed = 3;
|
||||
[GroupConfigurations, SerializeField, Range(0, 100)] private float animationSpeed = 2;
|
||||
|
||||
private Vector2 Movement { get; set; }
|
||||
|
||||
@ -43,7 +42,7 @@ namespace Intrepid.Gameplay.Entities.Player.Sentinel.StateMachine.States
|
||||
return;
|
||||
}
|
||||
if (CheckMovement()) return;
|
||||
Brain.Entity.DesiredVelocity = Movement * speed;
|
||||
Brain.Entity.DesiredVelocity = Movement * Brain.Config.Walk.Speed;
|
||||
}
|
||||
|
||||
private bool CheckMovement()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user