From 8b72e7416808cde313dcff2ebf49413a5beb874c Mon Sep 17 00:00:00 2001 From: Finn Voorhees Date: Thu, 28 Mar 2024 17:44:05 +0000 Subject: [PATCH] Move update/draw callback to open method --- Sources/PlaydateKit/Core/Sprite.swift | 158 ++++++++++++++++---------- 1 file changed, 97 insertions(+), 61 deletions(-) diff --git a/Sources/PlaydateKit/Core/Sprite.swift b/Sources/PlaydateKit/Core/Sprite.swift index 1046d541..6ee7974d 100644 --- a/Sources/PlaydateKit/Core/Sprite.swift +++ b/Sources/PlaydateKit/Core/Sprite.swift @@ -6,56 +6,50 @@ public import CPlaydate /// or the enemies that chase after your player. Sprites animate efficiently, and offer collision detection and /// a host of other built-in functionality. public enum Sprite { - // MARK: Public - - public typealias CollisionResponseType = SpriteCollisionResponseType - - public class CollisionInfo { - // MARK: Lifecycle - - init(collisions: UnsafeBufferPointer, actual: Point) { - self.collisions = collisions - self.actual = actual - } - - deinit { collisions.deallocate() } - - // MARK: Public - - public let collisions: UnsafeBufferPointer - public let actual: Point - } + // MARK: Open - public class QueryInfo { - // MARK: Lifecycle - - init(info: UnsafeBufferPointer) { - self.info = info - } - - deinit { - info.deallocate() - } - - // MARK: Public - - public let info: UnsafeBufferPointer - } - - public class Sprite { + open class Sprite { // MARK: Lifecycle /// Allocates and returns a new Sprite. public init() { pointer = sprite.newSprite.unsafelyUnwrapped().unsafelyUnwrapped + userdata = unsafeBitCast(self, to: UnsafeMutableRawPointer.self) + setUpdateFunction { sprite in + let userdata = PlaydateKit.Sprite.getUserdata(sprite.unsafelyUnwrapped).unsafelyUnwrapped + let sprite = unsafeBitCast(userdata, to: Sprite.self) + sprite.update() + } + setDrawFunction { sprite, bounds, drawRect in + let userdata = PlaydateKit.Sprite.getUserdata(sprite.unsafelyUnwrapped).unsafelyUnwrapped + let sprite = unsafeBitCast(userdata, to: Sprite.self) + sprite.draw(bounds: Rect(bounds), drawRect: Rect(drawRect)) + } } init(pointer: OpaquePointer) { self.pointer = pointer + userdata = unsafeBitCast(self, to: UnsafeMutableRawPointer.self) + setUpdateFunction { sprite in + let userdata = PlaydateKit.Sprite.getUserdata(sprite.unsafelyUnwrapped).unsafelyUnwrapped + let sprite = unsafeBitCast(userdata, to: Sprite.self) + sprite.update() + } + setDrawFunction { sprite, bounds, drawRect in + let userdata = PlaydateKit.Sprite.getUserdata(sprite.unsafelyUnwrapped).unsafelyUnwrapped + let sprite = unsafeBitCast(userdata, to: Sprite.self) + sprite.draw(bounds: Rect(bounds), drawRect: Rect(drawRect)) + } } deinit { sprite.freeSprite.unsafelyUnwrapped(pointer) } + // MARK: Open + + open func update() {} + + open func draw(bounds _: Rect, drawRect _: Rect) {} + // MARK: Public /// The sprite's stencil bitmap, if set. @@ -125,12 +119,6 @@ public enum Sprite { set { sprite.setVisible.unsafelyUnwrapped(pointer, newValue ? 1 : 0) } } - /// Gets/sets the sprite’s userdata, an arbitrary pointer used for associating the sprite with other data. - public var userdata: UnsafeMutableRawPointer? { - get { sprite.getUserdata.unsafelyUnwrapped(pointer) } - set { sprite.setUserdata.unsafelyUnwrapped(pointer, newValue) } - } - /// Get/set the `collisionsEnabled` flag of the sprite (along with the `collideRect`, this /// determines whether the sprite participates in collisions). Set to true by default. public var collisionsEnabled: Bool { @@ -237,25 +225,6 @@ public enum Sprite { sprite.setIgnoresDrawOffset.unsafelyUnwrapped(pointer, ignoresDrawOffset ? 1 : 0) } - /// Sets the update function for the sprite. - public func setUpdateFunction( - _ updateFunction: (@convention(c) (_ sprite: OpaquePointer?) -> Void)? - ) { - sprite.setUpdateFunction.unsafelyUnwrapped(pointer, updateFunction) - } - - /// Sets the draw function for the sprite. Note that the callback is only called when the - /// sprite is on screen and has a size specified via ``setSize(width:height:)`` or ``bounds``. - public func setDrawFunction( - drawFunction: (@convention(c) ( - _ sprite: OpaquePointer?, - _ bounds: PDRect, - _ drawRect: PDRect - ) -> Void)? - ) { - sprite.setDrawFunction.unsafelyUnwrapped(pointer, drawFunction) - } - /// Adds the sprite to the display list, so that it is drawn in the current scene. public func addToDisplayList() { sprite.addSprite.unsafelyUnwrapped(pointer) @@ -317,6 +286,67 @@ public enum Sprite { // MARK: Internal let pointer: OpaquePointer + + /// Gets/sets the sprite’s userdata, an arbitrary pointer used for associating the sprite with other data. + var userdata: UnsafeMutableRawPointer? { + get { sprite.getUserdata.unsafelyUnwrapped(pointer) } + set { sprite.setUserdata.unsafelyUnwrapped(pointer, newValue) } + } + + /// Sets the draw function for the sprite. Note that the callback is only called when the + /// sprite is on screen and has a size specified via ``setSize(width:height:)`` or ``bounds``. + func setDrawFunction( + drawFunction: (@convention(c) ( + _ sprite: OpaquePointer?, + _ bounds: PDRect, + _ drawRect: PDRect + ) -> Void)? + ) { + sprite.setDrawFunction.unsafelyUnwrapped(pointer, drawFunction) + } + + /// Sets the update function for the sprite. + func setUpdateFunction( + _ updateFunction: (@convention(c) (_ sprite: OpaquePointer?) -> Void)? + ) { + sprite.setUpdateFunction.unsafelyUnwrapped(pointer, updateFunction) + } + } + + // MARK: Public + + public typealias CollisionResponseType = SpriteCollisionResponseType + + public class CollisionInfo { + // MARK: Lifecycle + + init(collisions: UnsafeBufferPointer, actual: Point) { + self.collisions = collisions + self.actual = actual + } + + deinit { collisions.deallocate() } + + // MARK: Public + + public let collisions: UnsafeBufferPointer + public let actual: Point + } + + public class QueryInfo { + // MARK: Lifecycle + + init(info: UnsafeBufferPointer) { + self.info = info + } + + deinit { + info.deallocate() + } + + // MARK: Public + + public let info: UnsafeBufferPointer } // MARK: - Properties @@ -438,6 +468,12 @@ public enum Sprite { return UnsafeBufferPointer(start: sprites, count: Int(length)) } + // MARK: Internal + + static func getUserdata(_ sprite: OpaquePointer) -> UnsafeMutableRawPointer? { + Self.sprite.getUserdata(sprite) + } + // MARK: Private private static var sprite: playdate_sprite { Playdate.playdateAPI.sprite.pointee }