@@ -128,8 +128,15 @@ extension Animate3DGraphicView {
128128 @Published private( set) var cameraPropertyTexts : [ CameraProperty : String ] = [ : ]
129129
130130 init ( ) {
131- // Set up the mission and the graphics .
131+ // Set up the mission, graphics, and animation .
132132 updateMission ( )
133+
134+ let displayLink = CADisplayLink ( target: self , selector: #selector( updatePositions) )
135+ animation. setup ( displayLink: displayLink)
136+ }
137+
138+ deinit {
139+ Task { await animation. displayLink? . invalidate ( ) }
133140 }
134141
135142 // MARK: Methods
@@ -155,24 +162,6 @@ extension Animate3DGraphicView {
155162 }
156163 }
157164
158- /// Starts a new animation by creating a timer used to move the graphics.
159- func startAnimation( ) {
160- // Stop any previous on going animation.
161- animation. stop ( )
162- animation. isPlaying = true
163-
164- // Create a new timer to update the graphics' position each iteration.
165- let interval = 1 / Double( animation. speed)
166- animation. timer = Timer . scheduledTimer (
167- timeInterval: interval,
168- target: self ,
169- selector: #selector( updatePositions) ,
170- userInfo: nil ,
171- repeats: true
172- )
173- RunLoop . current. add ( animation. timer!, forMode: . common)
174- }
175-
176165 /// Updates the text associated with a given camera controller property.
177166 /// - Parameters:
178167 /// - property: The camera controller property associated with the text to update.
@@ -223,14 +212,18 @@ extension Animate3DGraphicView {
223212
224213 /// A struct containing data for an animation.
225214 struct Animation {
226- /// The timer for the animation used to loop through the animation frames.
227- var timer : Timer ?
215+ /// The timer used to loop through the animation frames.
216+ private ( set ) var displayLink : CADisplayLink ?
228217
229- /// The speed of the animation used to set the timer's time interval .
230- var speed = 50.0
218+ /// The speed of the animation.
219+ var speed = AnimationSpeed . medium
231220
232- /// A Boolean that indicates whether the animation is currently playing.
233- var isPlaying = false
221+ /// A Boolean value indicating whether the animation is currently playing.
222+ var isPlaying = false {
223+ didSet {
224+ displayLink? . isPaused = !isPlaying
225+ }
226+ }
234227
235228 /// The current frame of the animation.
236229 var currentFrame : Frame {
@@ -255,26 +248,31 @@ extension Animate3DGraphicView {
255248 /// The index of the current frame in the frames list.
256249 private var currentFrameIndex = 0
257250
258- /// Stops the animation by invalidating the timer.
259- mutating func stop( ) {
260- timer? . invalidate ( )
261- isPlaying = false
251+ /// Sets up the animation using a given display link.
252+ /// - Parameter displayLink: The display link used to run the animation.
253+ mutating func setup( displayLink: CADisplayLink ) {
254+ // Add the display link to main thread common mode run loop,
255+ // so it is not effected by UI events.
256+ displayLink. add ( to: . main, forMode: . common)
257+ displayLink. preferredFramesPerSecond = 60
258+ self . displayLink = displayLink
262259 }
263260
264261 /// Resets the animation to the beginning.
265262 mutating func reset( ) {
266- stop ( )
263+ isPlaying = false
267264 currentFrameIndex = 0
268265 }
269266
270- /// Increments the animation to the next frame.
267+ /// Increments the animation to the next frame based on the speed .
271268 mutating func nextFrame( ) {
272- if currentFrameIndex >= framesCount - 1 {
269+ // Increment the frame index using the current speed.
270+ let nextFrameIndex = currentFrameIndex + speed. rawValue
271+ if frames. indices. contains ( nextFrameIndex) {
272+ currentFrameIndex = nextFrameIndex
273+ } else {
273274 // Reset the animation when it has reached the end.
274275 reset ( )
275- } else {
276- // Move the index to point to the next frame.
277- currentFrameIndex += 1
278276 }
279277 }
280278
@@ -359,6 +357,13 @@ extension Animate3DGraphicView {
359357 }
360358 }
361359 }
360+
361+ /// An enumeration representing the speed of the animation.
362+ enum AnimationSpeed : Int , CaseIterable {
363+ case slow = 1
364+ case medium = 2
365+ case fast = 4
366+ }
362367}
363368
364369private extension FormatStyle where Self == FloatingPointFormatStyle < Double > {
0 commit comments