Finish overhauling animation module to support waiting states

• ISRU Animation module now will optionally wait for the current looping animation to complete before changing states, making transitions look more seamless
• Better looping animation handling, instead of manually refreshing animations
• Better documentation
• Remove some debug code in HeatEffects
pull/653/head
Andrew Cassidy 5 years ago
parent cf585360cb
commit f5b81532bb
No known key found for this signature in database
GPG Key ID: 963017B38FD477A1

@ -75,6 +75,7 @@
activeAnimationName = Run activeAnimationName = Run
retractAnimationName = Retract retractAnimationName = Retract
needsEC = true needsEC = true
waitForComplete = true
} }
MODULE MODULE

@ -59,7 +59,6 @@ namespace Restock
public void Start() public void Start()
{ {
Debug.Log("Start()");
if (base.vessel == null) return; if (base.vessel == null) return;
if (enableHeatEmissive) if (enableHeatEmissive)
@ -101,9 +100,6 @@ namespace Restock
{ {
if (HighLogic.LoadedSceneIsEditor || HighLogic.LoadedSceneIsFlight) return; if (HighLogic.LoadedSceneIsEditor || HighLogic.LoadedSceneIsFlight) return;
Debug.Log("OnLoad()");
Debug.Log(node.ToString());
renderers = base.part.FindModelComponents<Renderer>(); renderers = base.part.FindModelComponents<Renderer>();
if (node.HasValue("excludedRenderer")) if (node.HasValue("excludedRenderer"))

@ -15,7 +15,7 @@ namespace Restock
// name of the active animation to use // name of the active animation to use
[KSPField] public string activeAnimationName = ""; [KSPField] public string activeAnimationName = "";
// name of the inactive animation to use // name of the inactive animation to use
[KSPField] public string inactiveAnimationName = ""; [KSPField] public string inactiveAnimationName = "";
@ -28,16 +28,20 @@ namespace Restock
// does this module need electric charge to be enabled? // does this module need electric charge to be enabled?
[KSPField] public bool needsEC = false; [KSPField] public bool needsEC = false;
public bool IsDeployed // should the module wait until a current looping animation completes before changing state?
{ [KSPField] public bool waitForComplete = false;
get { return (CurrentState == State.Active || CurrentState == State.Deploying); }
} public bool IsDeployed => (CurrentState == State.InactiveWaiting ||
CurrentState == State.Active ||
CurrentState == State.Deploying);
private enum State private enum State
{ {
Inactive, Inactive,
InactiveWaiting,
Deploying, Deploying,
Active, Active,
ActiveWaiting,
Retracting Retracting
} }
@ -47,12 +51,12 @@ namespace Restock
private Animation InactiveAnimation { get; set; } private Animation InactiveAnimation { get; set; }
private State CurrentState { get; set; } private State CurrentState { get; set; }
private bool _deployAnimationPresent = false; private bool _deployAnimationPresent = false;
private bool _retractAnimationPresent = false; private bool _retractAnimationPresent = false;
private bool _activeAnimationPresent = false; private bool _activeAnimationPresent = false;
private bool _inactiveAnimationPresent = false; private bool _inactiveAnimationPresent = false;
private List<BaseConverter> _modules; private List<BaseConverter> _modules;
public void Start() public void Start()
@ -63,78 +67,85 @@ namespace Restock
_retractAnimationPresent = (retractAnimationName != string.Empty); _retractAnimationPresent = (retractAnimationName != string.Empty);
_activeAnimationPresent = (activeAnimationName != string.Empty); _activeAnimationPresent = (activeAnimationName != string.Empty);
_inactiveAnimationPresent = (inactiveAnimationName != string.Empty); _inactiveAnimationPresent = (inactiveAnimationName != string.Empty);
DeployAnimation = ((_deployAnimationPresent) ? base.part.FindModelAnimators(deployAnimationName)[0] : null); DeployAnimation = ((_deployAnimationPresent) ?
RetractAnimation = ((_retractAnimationPresent) ? base.part.FindModelAnimators(retractAnimationName)[0] : null); base.part.FindModelAnimators(deployAnimationName)[0] : null);
ActiveAnimation = ((_activeAnimationPresent) ? base.part.FindModelAnimators(activeAnimationName)[0] : null); RetractAnimation = ((_retractAnimationPresent) ?
InactiveAnimation = ((_inactiveAnimationPresent) ? base.part.FindModelAnimators(inactiveAnimationName)[0] : null); base.part.FindModelAnimators(retractAnimationName)[0] : null);
ActiveAnimation = ((_activeAnimationPresent) ?
CurrentState = State.Inactive; base.part.FindModelAnimators(activeAnimationName)[0] : null);
InactiveAnimation = ((_inactiveAnimationPresent)?
base.part.FindModelAnimators(inactiveAnimationName)[0] : null);
foreach (var a in base.part.FindModelAnimators()) a.Stop(); foreach (var a in base.part.FindModelAnimators()) a.Stop();
}
public override void OnLoad(ConfigNode node) if (!HighLogic.LoadedSceneIsFlight) return;
{
if (!HighLogic.LoadedSceneIsFlight || base.vessel == null) if (ConvertersEnabled())
{
CurrentState = State.Inactive;
return;
}
if (IsDeployed)
{ {
DeployEnd(); DeployStart(1000f);
} }
else else
{ {
RetractEnd(); RetractStart(1000f);
} }
} }
public override void OnLoad(ConfigNode node)
{
}
public void Update() public void Update()
{ {
if (!HighLogic.LoadedSceneIsFlight) return; if (!HighLogic.LoadedSceneIsFlight) return;
try try
{ {
if (needsEC && !CheatOptions.InfiniteElectricity)
{
var ecHash = PartResourceLibrary.ElectricityHashcode;
base.vessel.GetConnectedResourceTotals(ecHash, out var ecAmount, out _, true);
if (ecAmount < 0.1)
{
if (IsDeployed) RetractStart();
return;
}
}
int enabledCount = 0;
foreach (var m in _modules)
{
if (m.ModuleIsActive()) enabledCount++;
}
switch (CurrentState) switch (CurrentState)
{ {
case State.Active: // System is inactive, and playing the inactive animation if present
if (enabledCount == 0) case State.Inactive:
if (ConvertersEnabled())
{ {
DeployStart(); if (waitForComplete)
{
DeployWait();
}
else
{
DeployStart();
}
} }
else if (_activeAnimationPresent && !ActiveAnimation.IsPlaying(activeAnimationName))
break;
// System is inactive, but waiting for the animation to end before deploying
case State.InactiveWaiting:
if (!waitForComplete || !_inactiveAnimationPresent)
{
this.LogError(
"Invalid state! waitForComplete not enabled or inactive animation not present.");
CurrentState = State.Inactive;
}
else if (!ConvertersEnabled())
{
RetractEnd();
}
else if (!InactiveAnimation.IsPlaying(inactiveAnimationName))
{ {
PlayAnimation(ActiveAnimation, activeAnimationName); DeployStart();
} }
break; break;
// System is deploying
case State.Deploying: case State.Deploying:
if (!_deployAnimationPresent) if (!_deployAnimationPresent)
{ {
this.LogError("Invalid state!"); this.LogError("Invalid state! Deploying without an animation present.");
CurrentState = State.Active; CurrentState = State.Active;
} }
if (enabledCount == 0) else if (!ConvertersEnabled())
{ {
RetractStart(); RetractStart();
} }
@ -142,26 +153,51 @@ namespace Restock
{ {
DeployEnd(); DeployEnd();
} }
break; break;
case State.Inactive: // System is active, and playing the active animation if present
if (enabledCount != 0) case State.Active:
if (!ConvertersEnabled())
{ {
DeployStart(); if (waitForComplete)
{
RetractWait();
}
else
{
RetractStart();
}
}
break;
// System is active, but waiting for the animation to finish before retracting
case State.ActiveWaiting:
if (!waitForComplete || !_activeAnimationPresent)
{
this.LogError("Invalid state! waitForComplete not enabled or active animation not present.");
CurrentState = State.Active;
} }
else if (_inactiveAnimationPresent && !InactiveAnimation.IsPlaying(inactiveAnimationName)) else if (ConvertersEnabled())
{ {
PlayAnimation(InactiveAnimation, inactiveAnimationName); DeployEnd();
} }
else if (!ActiveAnimation.IsPlaying(activeAnimationName))
{
RetractStart();
}
break; break;
// System is retracting
case State.Retracting: case State.Retracting:
if (!_retractAnimationPresent && !_deployAnimationPresent) if (!_retractAnimationPresent && !_deployAnimationPresent)
{ {
this.LogError("Invalid state!"); this.LogError("Invalid state! Retracting without an animation present.");
CurrentState = State.Inactive; CurrentState = State.Inactive;
} }
if (enabledCount != 0) else if (ConvertersEnabled())
{ {
DeployStart(); DeployStart();
} }
@ -169,8 +205,9 @@ namespace Restock
{ {
RetractEnd(); RetractEnd();
} }
break; break;
default: default:
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
} }
@ -181,12 +218,28 @@ namespace Restock
} }
} }
private void DeployStart() private void DeployWait()
{
if (_inactiveAnimationPresent){
CurrentState = State.InactiveWaiting;
PlayAnimation(InactiveAnimation, inactiveAnimationName, loop: false);
}
else
{
DeployStart();
}
}
private void DeployStart(float speed = 1f)
{ {
if (_deployAnimationPresent) if (_deployAnimationPresent)
{ {
if (_retractAnimationPresent && RetractAnimation.IsPlaying(retractAnimationName))
{
RetractAnimation.Stop(retractAnimationName);
}
CurrentState = State.Deploying; CurrentState = State.Deploying;
PlayAnimation(DeployAnimation, deployAnimationName, deploySpeed); PlayAnimation(DeployAnimation, deployAnimationName, speed * deploySpeed);
} }
else else
{ {
@ -197,22 +250,41 @@ namespace Restock
private void DeployEnd() private void DeployEnd()
{ {
CurrentState = State.Active; CurrentState = State.Active;
if (_activeAnimationPresent) if (_activeAnimationPresent)
{ {
PlayAnimation(ActiveAnimation, activeAnimationName); PlayAnimation(ActiveAnimation, activeAnimationName, loop: true);
} }
} }
private void RetractStart() private void RetractWait()
{
if (_activeAnimationPresent)
{
CurrentState = State.ActiveWaiting;
PlayAnimation(ActiveAnimation, activeAnimationName, loop: false);
}
else
{
RetractStart();
}
}
private void RetractStart(float speed = 1f)
{ {
if (_retractAnimationPresent) if (_retractAnimationPresent)
{ {
if (_deployAnimationPresent && DeployAnimation.IsPlaying(deployAnimationName))
{
DeployAnimation.Stop(deployAnimationName);
}
CurrentState = State.Retracting; CurrentState = State.Retracting;
PlayAnimation(RetractAnimation, retractAnimationName, retractSpeed); PlayAnimation(RetractAnimation, retractAnimationName, speed * retractSpeed);
} else if (_deployAnimationPresent) }
else if (_deployAnimationPresent)
{ {
CurrentState = State.Retracting; CurrentState = State.Retracting;
PlayAnimation(DeployAnimation, deployAnimationName, retractSpeed * -1); PlayAnimation(DeployAnimation, deployAnimationName, speed * retractSpeed * -1);
} }
else else
{ {
@ -223,26 +295,57 @@ namespace Restock
private void RetractEnd() private void RetractEnd()
{ {
CurrentState = State.Inactive; CurrentState = State.Inactive;
if (_inactiveAnimationPresent) if (_inactiveAnimationPresent)
{ {
PlayAnimation(InactiveAnimation, inactiveAnimationName); PlayAnimation(InactiveAnimation, inactiveAnimationName, loop: true);
} }
} }
private void PlayAnimation(Animation anim, string name, float speed = 1f) private bool ConvertersEnabled()
{ {
var animState = anim[name]; if (needsEC && !CheatOptions.InfiniteElectricity)
if (speed < 0 && animState.time < Mathf.Epsilon) {
var ecHash = PartResourceLibrary.ElectricityHashcode;
base.vessel.GetConnectedResourceTotals(ecHash, out var ecAmount, out _, true);
if (ecAmount < 0.1)
{
return false;
}
}
foreach (var m in _modules)
{ {
animState.time = animState.length; if (m.ModuleIsActive())
{
return true;
}
} }
else if (speed > 0 && animState.time > animState.length - Mathf.Epsilon)
return false;
}
private static void PlayAnimation(Animation anim, string name, float speed = 1f, bool loop = false)
{
var animState = anim[name];
if (animState.wrapMode != WrapMode.Loop)
{ {
animState.time = 0.0f; if (speed < 0 && animState.time < Mathf.Epsilon)
{
animState.time = animState.length;
}
else if (speed > 0 && animState.time > animState.length - Mathf.Epsilon)
{
animState.time = 0.0f;
}
} }
animState.speed = speed; animState.speed = speed;
anim.Play(name); animState.wrapMode = loop ? WrapMode.Loop : WrapMode.Once;
//if (!anim.IsPlaying(name))
anim.Play(name);
} }
} }
} }
Loading…
Cancel
Save