Skip to content

Instantly share code, notes, and snippets.

@pharan
Created June 6, 2016 21:43
Show Gist options
  • Save pharan/20e895d225cf53f5d3b151f1c030572a to your computer and use it in GitHub Desktop.
Save pharan/20e895d225cf53f5d3b151f1c030572a to your computer and use it in GitHub Desktop.
A hyper-simplified version of Spine's AnimationState.cs

Spine.AnimationState - Water Flavor

/******************************************************************************
* Spine Runtimes Software License
* Version 2.3
*
* Copyright (c) 2013-2015, Esoteric Software
* All rights reserved.
*
* You are granted a perpetual, non-exclusive, non-sublicensable and
* non-transferable license to use, install, execute and perform the Spine
* Runtimes Software (the "Software") and derivative works solely for personal
* or internal use. Without the written permission of Esoteric Software (see
* Section 2 of the Spine Software License Agreement), you may not (a) modify,
* translate, adapt or otherwise create derivative works, improvements of the
* Software or develop new applications using the Software or (b) remove,
* delete, alter or obscure any trademarks or any copyright, trademark, patent
* or other intellectual property or proprietary rights notices on or in the
* Software, including any copy thereof. Redistributions in binary or source
* form must include this license and terms.
*
* THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/
using System;
namespace Spine {
public class AnimationState {
readonly ExposedList<Event> events = new ExposedList<Event>();
public delegate void EventDelegate (AnimationState state, int trackIndex, Event e);
public event EventDelegate Event;
Spine.AnimationStateData data;
Spine.TrackEntry trackEntry;
public AnimationState (AnimationStateData data) {
if (data == null) throw new ArgumentNullException("data");
this.data = data;
}
public void Update (float delta) {
if (trackEntry == null) return;
// THIS IS THE MAIN PURPOSE OF AnimationState.Update(delta). This advances the time of the tracks by the given delta seconds(delta).
trackEntry.time += delta;
// Step 2. Clear the track if animation is done (according to TrackEntry.endTime).
bool notLoopingAnimation = !trackEntry.loop;
bool wasDone = trackEntry.lastTime >= trackEntry.endTime;
if (!notLoopingAnimation && wasDone)
ClearTrack(0);
}
public void Apply (Skeleton skeleton) {
if (trackEntry == null) return;
// Now we use data from TrackEntry.
Spine.Animation animation = trackEntry.animation;
bool loop = trackEntry.loop;
float endTime = trackEntry.endTime;
float lastTime = trackEntry.lastTime;
float time = trackEntry.time;
if (!loop) time = Math.Min(time, endTime);
// THIS IS THE MAIN PURPOSE OF AnimationState.Apply(Skeleton). This applies the current animation to the skeleton at the stored time (which was updated in Update).
events.Clear();
animation.Apply(skeleton, lastTime, time, loop, events);
// Animation.Apply above stores Spine events between lastTime and time into a list (events).
// This will generate the callback for those events.
if (this.Event != null)
foreach (Spine.Event e in events) this.Event(this, 0, e);
// lastTime means "time of the TrackEntry when it was last applied". The current time will be stored there for a future loop.
trackEntry.lastTime = trackEntry.time;
}
public TrackEntry SetAnimation (int trackIndex, String animationName, bool loop) {
Animation animation = data.skeletonData.FindAnimation(animationName);
if (animation == null) throw new ArgumentException("Animation not found: " + animationName);
return SetAnimation(trackIndex, animation, loop);
}
public TrackEntry SetAnimation (int trackIndex, Animation animation, bool loop) {
if (animation == null) throw new ArgumentNullException("animation");
trackEntry = new TrackEntry {
animation = animation,
loop = loop,
time = 0,
endTime = animation.duration
};
// The method also returns the new TrackEntry so ouside code can modify things like the start time (time), or the end time (endTime).
return trackEntry;
}
/// <summary>With multiple tracks, this method would return the currently playing entry in a specific track.</summary>
public TrackEntry GetCurrent (int trackIndex) {
return trackEntry;
}
/// <summary>With multiple tracks, this method would clear a specific track.</summary>
public void ClearTrack (int trackIndex) {
trackEntry = null;
}
/// <summary>With multiple tracks, this method would clear all tracks.</summary>
public void ClearTracks () {
trackEntry = null;
}
override public String ToString () {
return trackEntry == null ? "<none>" : trackEntry.animation.ToString();
}
}
public class TrackEntry {
public float time, lastTime = -1;
public Animation animation;
public float endTime;
public bool loop;
public float Time { get { return time; } }
public float LastTime { get { return lastTime; } }
public Animation Animation { get { return animation; } }
public float EndTime { get { return endTime; } }
public bool Loop { get { return loop; } }
public float Mix { get { return 1f; } }
// This is just so the YieldInstruction module doesn't break. This is nonfunctional.
public delegate void CompleteDelegate (AnimationState state, int trackIndex, int loopCount);
public CompleteDelegate Complete;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment