/****************************************************************************** * Spine Runtimes License Agreement * Last updated April 5, 2025. Replaces all prior versions. * * Copyright (c) 2013-2025, Esoteric Software LLC * * Integration of the Spine Runtimes into software or otherwise creating * derivative works of the Spine Runtimes is permitted under the terms and * conditions of Section 2 of the Spine Editor License Agreement: * http://esotericsoftware.com/spine-editor-license * * Otherwise, it is permitted to integrate the Spine Runtimes into software * or otherwise create derivative works of the Spine Runtimes (collectively, * "Products"), provided that each user of the Products must obtain their own * Spine Editor license and redistribution of the Products in any form must * include this license and copyright notice. * * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "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 LLC BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) 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 * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ import Foundation import SpineCppLite public typealias AnimationStateListener = (_ type: EventType, _ entry: TrackEntry, _ event: Event?) -> Void /// Wrapper class around ``AnimationState``. Applies animations over time, queues animations for later playback, mixes (crossfading) between animations, and applies /// multiple animations on top of each other (layering). /// /// See [Applying Animations](http://esotericsoftware.com/spine-applying-animations/) in the Spine Runtimes Guide. @objc(SpineAnimationStateWrapper) @objcMembers public final class AnimationStateWrapper: NSObject { public let animationState: AnimationState public let aninationStateEvents: AnimationStateEvents private var trackEntryListeners = [spine_track_entry: AnimationStateListener]() private var stateListener: AnimationStateListener? public init(animationState: AnimationState, aninationStateEvents: AnimationStateEvents) { self.animationState = animationState self.aninationStateEvents = aninationStateEvents super.init() } /// The listener for events generated by the provided ``TrackEntry``, or nil. /// /// A track entry returned from ``AnimationState/setAnimation(trackIndex:animation:loop:)`` is already the current animation /// for the track, so the track entry listener will not be called for ``EventType`` `SPINE_EVENT_TYPE_START`. public func setTrackEntryListener(entry: TrackEntry, listener: AnimationStateListener?) { if let listener { trackEntryListeners[entry.wrappee] = listener } else { trackEntryListeners.removeValue(forKey: entry.wrappee) } } /// Increments each track entry ``TrackEntry/trackTime``, setting queued animations as current if needed. public func update(delta: Float) { animationState.update(delta: delta) let numEvents = spine_animation_state_events_get_num_events(aninationStateEvents.wrappee) for i in 0..