playdate_rs/
sprite.rs

1use core::cell::RefCell;
2
3use alloc::boxed::Box;
4use alloc::vec::Vec;
5use playdate_rs_sys::LCDPattern;
6
7use crate::{
8    graphics::Bitmap,
9    math::{Rect, SideOffsets, Vec2},
10    util::Ref,
11    PLAYDATE,
12};
13
14pub use sys::SpriteCollisionResponseType;
15
16pub struct PlaydateSprite {
17    handle: *const sys::playdate_sprite,
18}
19
20impl PlaydateSprite {
21    pub(crate) fn new(handle: *const sys::playdate_sprite) -> Self {
22        Self { handle }
23    }
24
25    /// When flag is set to 1, the given sprite will always redraw.
26    pub fn set_always_redraw(&self, flag: bool) {
27        unsafe {
28            (*self.handle).setAlwaysRedraw.unwrap()(flag as i32);
29        }
30    }
31
32    /// Marks the given dirtyRect (in screen coordinates) as needing a redraw. Graphics drawing functions now call this automatically, adding their drawn areas to the sprite’s dirty list, so there’s usually no need to call this manually.
33    pub fn add_dirty_rect(&self, dirty_rect: SideOffsets<i32>) {
34        unsafe {
35            (*self.handle).addDirtyRect.unwrap()(dirty_rect.into());
36        }
37    }
38
39    /// Draws every sprite in the display list.
40    pub fn draw_sprites(&self) {
41        unsafe {
42            (*self.handle).drawSprites.unwrap()();
43        }
44    }
45
46    /// Updates and draws every sprite in the display list.
47    pub fn update_and_draw_sprites(&self) {
48        unsafe {
49            (*self.handle).updateAndDrawSprites.unwrap()();
50        }
51    }
52
53    /// Adds the given sprite to the display list, so that it is drawn in the current scene.
54    pub fn add_sprite(&self, sprite: impl AsRef<Sprite>) {
55        unsafe {
56            (*self.handle).addSprite.unwrap()(sprite.as_ref().handle);
57        }
58    }
59
60    /// Removes the given sprite from the display list.
61    pub fn remove_sprite(&self, sprite: impl AsRef<Sprite>) {
62        unsafe {
63            (*self.handle).removeSprite.unwrap()(sprite.as_ref().handle);
64        }
65    }
66
67    /// Removes the given count sized array of sprites from the display list.
68    pub fn remove_sprites(&self, sprites: &[&Sprite]) {
69        let mut sprites: Vec<_> = sprites.iter().map(|s| s.handle).collect();
70        unsafe {
71            (*self.handle).removeSprites.unwrap()(sprites.as_mut_ptr(), sprites.len() as i32);
72        }
73    }
74
75    /// Removes all sprites from the display list.
76    pub fn remove_all_sprites(&self) {
77        unsafe {
78            (*self.handle).removeAllSprites.unwrap()();
79        }
80    }
81
82    /// Returns the total number of sprites in the display list.
83    pub fn get_sprite_count(&self) -> usize {
84        unsafe { (*self.handle).getSpriteCount.unwrap()() as _ }
85    }
86
87    /// Sets the clipping rectangle for all sprites with a Z index within startZ and endZ inclusive.
88    pub fn set_clip_rects_in_range(&self, clip_rect: SideOffsets<i32>, start_z: i32, end_z: i32) {
89        unsafe {
90            (*self.handle).setClipRectsInRange.unwrap()(clip_rect.into(), start_z, end_z);
91        }
92    }
93
94    /// Clears the clipping rectangle for all sprites with a Z index within startZ and endZ inclusive.
95    pub fn clear_clip_rects_in_range(&self, start_z: i32, end_z: i32) {
96        unsafe {
97            (*self.handle).clearClipRectsInRange.unwrap()(start_z, end_z);
98        }
99    }
100
101    /// Frees and reallocates internal collision data, resetting everything to its default state.
102    pub fn reset_collision_world(&self) {
103        unsafe {
104            (*self.handle).resetCollisionWorld.unwrap()();
105        }
106    }
107
108    pub fn query_sprites_at_point(&self, pos: Vec2<f32>) -> Vec<Ref<Sprite>> {
109        let mut len = 0;
110        let sprites =
111            unsafe { (*self.handle).querySpritesAtPoint.unwrap()(pos.x, pos.y, &mut len) };
112        let mut result = Vec::new();
113        for i in 0..len {
114            let sprite = unsafe { sprites.offset(i as isize).as_ref().unwrap() };
115            result.push(Sprite::from_ref(*sprite));
116        }
117        PLAYDATE.system.realloc(sprites as _, 0);
118        result
119    }
120
121    pub fn query_sprites_in_rect(&self, rect: Rect<f32>) -> Vec<Ref<Sprite>> {
122        let mut len = 0;
123        let sprites = unsafe {
124            (*self.handle).querySpritesInRect.unwrap()(
125                rect.x,
126                rect.y,
127                rect.width,
128                rect.height,
129                &mut len,
130            )
131        };
132        let mut result = Vec::new();
133        for i in 0..len {
134            let sprite = unsafe { sprites.offset(i as isize).as_ref().unwrap() };
135            result.push(Sprite::from_ref(*sprite));
136        }
137        PLAYDATE.system.realloc(sprites as _, 0);
138        result
139    }
140
141    pub fn query_sprites_along_line(&self, x1: f32, y1: f32, x2: f32, y2: f32) -> Vec<Ref<Sprite>> {
142        let mut len = 0;
143        let sprites =
144            unsafe { (*self.handle).querySpritesAlongLine.unwrap()(x1, y1, x2, y2, &mut len) };
145        let mut result = Vec::new();
146        for i in 0..len {
147            let sprite = unsafe { sprites.offset(i as isize).as_ref().unwrap() };
148            result.push(Sprite::from_ref(*sprite));
149        }
150        PLAYDATE.system.realloc(sprites as _, 0);
151        result
152    }
153
154    pub fn query_sprite_info_along_line(
155        &self,
156        x1: f32,
157        y1: f32,
158        x2: f32,
159        y2: f32,
160    ) -> Vec<SpriteQueryInfo> {
161        let mut len = 0;
162        let info =
163            unsafe { (*self.handle).querySpriteInfoAlongLine.unwrap()(x1, y1, x2, y2, &mut len) };
164        let mut result = Vec::new();
165        for i in 0..len {
166            let info = unsafe { info.offset(i as isize).as_ref().unwrap() };
167            result.push(SpriteQueryInfo::new(info));
168        }
169        PLAYDATE.system.realloc(info as _, 0);
170        result
171    }
172
173    /// Returns an array of all sprites that have collide rects that are currently overlapping. Each consecutive pair of sprites is overlapping (eg. 0 & 1 overlap, 2 & 3 overlap, etc).
174    pub fn all_overlapping_sprites(&self) -> Vec<Ref<Sprite>> {
175        let mut len = 0;
176        let sprites = unsafe { (*self.handle).allOverlappingSprites.unwrap()(&mut len) };
177        let mut result = Vec::new();
178        for i in 0..len {
179            let sprite = unsafe { sprites.offset(i as isize).as_ref().unwrap() };
180            result.push(Sprite::from_ref(*sprite));
181        }
182        PLAYDATE.system.realloc(sprites as _, 0);
183        result
184    }
185}
186
187#[derive(Debug)]
188pub struct Sprite {
189    handle: *mut sys::LCDSprite,
190}
191
192impl PartialEq for Sprite {
193    fn eq(&self, other: &Self) -> bool {
194        self.handle == other.handle
195    }
196}
197
198impl Eq for Sprite {}
199
200unsafe impl Sync for Sprite {}
201unsafe impl Send for Sprite {}
202
203impl Default for Sprite {
204    fn default() -> Self {
205        Self::new()
206    }
207}
208
209type DataCell<F> = RefCell<Option<F>>;
210type UpdateFn = Box<dyn Fn(&Sprite)>;
211type DrawFn = Box<dyn Fn(&Sprite, Rect<f32>, Rect<f32>)>;
212type CollisionResponseFn = Box<dyn Fn(&Sprite, &Sprite) -> SpriteCollisionResponseType>;
213
214#[derive(Default)]
215struct SpriteData {
216    update_fn: DataCell<UpdateFn>,
217    draw_fn: DataCell<DrawFn>,
218    collision_response_fn: DataCell<CollisionResponseFn>,
219}
220
221impl Sprite {
222    pub(crate) fn from(handle: *mut sys::LCDSprite) -> Self {
223        Self { handle }
224    }
225
226    pub(crate) fn from_ref<'a>(handle: *mut sys::LCDSprite) -> Ref<'a, Self> {
227        Ref::new(Self { handle })
228    }
229
230    /// Allocates and returns a new Sprite.
231    pub fn new() -> Self {
232        Self::from(unsafe { (*PLAYDATE.sprite.handle).newSprite.unwrap()() })
233    }
234
235    /// Gets x and y to the current position of sprite. This is the position of the sprite rectangle’s center.
236    pub fn get_position(&self) -> Vec2<f32> {
237        let mut x = 0.0;
238        let mut y = 0.0;
239        unsafe {
240            (*PLAYDATE.sprite.handle).getPosition.unwrap()(self.handle, &mut x, &mut y);
241        }
242        Vec2::new(x, y)
243    }
244
245    /// Sets the bounds of the given sprite with bounds. This is the position of the sprite rectangle’s center.
246    pub fn set_bounds(&self, bounds: Rect<f32>) {
247        unsafe { (*PLAYDATE.sprite.handle).setBounds.unwrap()(self.handle, bounds.into()) }
248    }
249
250    /// Returns the bounds of the given sprite as an PDRect;
251    /// The (x, y) refers to the top-left corner of the sprite rectangle.
252    pub fn get_bounds(&self) -> Rect<f32> {
253        unsafe { (*PLAYDATE.sprite.handle).getBounds.unwrap()(self.handle).into() }
254    }
255
256    /// Moves the given sprite to x, y and resets its bounds based on the bitmap dimensions and center.
257    pub fn move_to(&self, pos: Vec2<f32>) {
258        unsafe { (*PLAYDATE.sprite.handle).moveTo.unwrap()(self.handle, pos.x, pos.y) }
259    }
260
261    /// Moves the given sprite to by offsetting its current position by dx, dy.
262    pub fn move_by(&self, delta: Vec2<f32>) {
263        unsafe { (*PLAYDATE.sprite.handle).moveBy.unwrap()(self.handle, delta.x, delta.y) }
264    }
265
266    /// Sets the given sprite's image to the given bitmap.
267    pub fn set_image(&self, image: Bitmap, flip: sys::LCDBitmapFlip) {
268        // drop old image
269        if let Some(old_image) = self.get_image() {
270            let _boxed = Bitmap::from(old_image.handle);
271        }
272        // set new image. pass the ownership to the system
273        unsafe {
274            (*PLAYDATE.sprite.handle).setImage.unwrap()(self.handle, image.as_ref().handle, flip)
275        };
276        // forget image so it doesn't get dropped
277        core::mem::forget(image);
278    }
279
280    /// Returns the LCDBitmap currently assigned to the given sprite.
281    pub fn get_image(&self) -> Option<Ref<Bitmap>> {
282        let ptr = unsafe { (*PLAYDATE.sprite.handle).getImage.unwrap()(self.handle) };
283        if ptr.is_null() {
284            None
285        } else {
286            Some(Bitmap::from_ref(ptr))
287        }
288    }
289
290    /// Sets the size. The size is used to set the sprite’s bounds when calling moveTo().
291    pub fn set_size(&self, width: f32, height: f32) {
292        unsafe { (*PLAYDATE.sprite.handle).setSize.unwrap()(self.handle, width, height) }
293    }
294
295    /// Sets the Z order of the given sprite. Higher Z sprites are drawn on top of those with lower Z order.
296    pub fn set_z_index(&self, z_index: i16) {
297        unsafe { (*PLAYDATE.sprite.handle).setZIndex.unwrap()(self.handle, z_index) }
298    }
299
300    /// Returns the Z index of the given sprite.
301    pub fn get_z_index(&self) -> i16 {
302        unsafe { (*PLAYDATE.sprite.handle).getZIndex.unwrap()(self.handle) }
303    }
304
305    /// Sets the mode for drawing the sprite’s bitmap.
306    pub fn set_draw_mode(&self, mode: sys::LCDBitmapDrawMode) {
307        unsafe { (*PLAYDATE.sprite.handle).setDrawMode.unwrap()(self.handle, mode) }
308    }
309
310    /// Flips the bitmap.
311    pub fn set_image_flip(&self, flip: sys::LCDBitmapFlip) {
312        unsafe { (*PLAYDATE.sprite.handle).setImageFlip.unwrap()(self.handle, flip) }
313    }
314
315    /// Returns the flip setting of the sprite’s bitmap.
316    pub fn get_image_flip(&self) -> sys::LCDBitmapFlip {
317        unsafe { (*PLAYDATE.sprite.handle).getImageFlip.unwrap()(self.handle) }
318    }
319
320    /// Specifies a stencil image to be set on the frame buffer before the sprite is drawn.
321    pub fn set_stencil(&self, stencil: impl AsRef<Bitmap>) {
322        unsafe {
323            (*PLAYDATE.sprite.handle).setStencil.unwrap()(self.handle, stencil.as_ref().handle)
324        };
325    }
326
327    /// Sets the clipping rectangle for sprite drawing.
328    pub fn set_clip_rect(&self, clip_rect: SideOffsets<i32>) {
329        unsafe { (*PLAYDATE.sprite.handle).setClipRect.unwrap()(self.handle, clip_rect.into()) };
330    }
331
332    /// Clears the sprite’s clipping rectangle.
333    pub fn clear_clip_rect(&self) {
334        unsafe { (*PLAYDATE.sprite.handle).clearClipRect.unwrap()(self.handle) };
335    }
336
337    /// Set the updatesEnabled flag of the given sprite (determines whether the sprite has its update function called).
338    pub fn set_updates_enabled(&self, flag: bool) {
339        unsafe { (*PLAYDATE.sprite.handle).setUpdatesEnabled.unwrap()(self.handle, flag as _) };
340    }
341
342    /// Get the updatesEnabled flag of the given sprite.
343    pub fn updates_enabled(&self) -> bool {
344        unsafe { (*PLAYDATE.sprite.handle).updatesEnabled.unwrap()(self.handle) == 1 }
345    }
346
347    /// Set the collisionsEnabled flag of the given sprite (along with the collideRect, this determines whether the sprite participates in collisions). Set to true by default.
348    pub fn set_collisions_enabled(&self, flag: bool) {
349        unsafe { (*PLAYDATE.sprite.handle).setCollisionsEnabled.unwrap()(self.handle, flag as _) };
350    }
351
352    /// Get the collisionsEnabled flag of the given sprite.
353    pub fn collisions_enabled(&self) -> bool {
354        unsafe { (*PLAYDATE.sprite.handle).collisionsEnabled.unwrap()(self.handle) == 1 }
355    }
356
357    /// Set the visible flag of the given sprite (determines whether the sprite has its draw function called).
358    pub fn set_visible(&self, flag: bool) {
359        unsafe { (*PLAYDATE.sprite.handle).setVisible.unwrap()(self.handle, flag as _) };
360    }
361
362    /// Get the visible flag of the given sprite.
363    pub fn is_visible(&self) -> bool {
364        unsafe { (*PLAYDATE.sprite.handle).isVisible.unwrap()(self.handle) == 1 }
365    }
366
367    /// Marking a sprite opaque tells the sprite system that it doesn’t need to draw anything underneath the sprite, since it will be overdrawn anyway. If you set an image without a mask/alpha channel on the sprite, it automatically sets the opaque flag.
368    pub fn set_opaque(&self, flag: bool) {
369        unsafe { (*PLAYDATE.sprite.handle).setOpaque.unwrap()(self.handle, flag as _) };
370    }
371
372    /// Forces the given sprite to redraw.
373    pub fn mark_dirty(&self) {
374        unsafe { (*PLAYDATE.sprite.handle).markDirty.unwrap()(self.handle) };
375    }
376
377    /// Sets the tag of the given sprite. This can be useful for identifying sprites or types of sprites when using the collision API.
378    pub fn set_tag(&self, tag: u8) {
379        unsafe { (*PLAYDATE.sprite.handle).setTag.unwrap()(self.handle, tag) }
380    }
381
382    /// Returns the tag of the given sprite.
383    pub fn get_tag(&self) -> u8 {
384        unsafe { (*PLAYDATE.sprite.handle).getTag.unwrap()(self.handle) }
385    }
386
387    /// When flag is set to 1, the sprite will draw in screen coordinates, ignoring the currently-set drawOffset.
388    ///
389    /// This only affects drawing, and should not be used on sprites being used for collisions, which will still happen in world-space.
390    pub fn set_ignores_draw_offset(&self, flag: i32) {
391        unsafe { (*PLAYDATE.sprite.handle).setIgnoresDrawOffset.unwrap()(self.handle, flag) };
392    }
393
394    /// Sets the update function for the given sprite.
395    pub fn set_update_function(&self, func: impl Fn(&Sprite) + 'static) {
396        *self.get_userdata().update_fn.borrow_mut() = Some(Box::new(func));
397        extern "C" fn callback(sprite: *mut sys::LCDSprite) {
398            let sprite = Sprite::from_ref(sprite);
399            let func = sprite.get_userdata().update_fn.borrow();
400            let func = &func.as_ref().unwrap();
401            func(&sprite)
402        }
403        unsafe {
404            (*PLAYDATE.sprite.handle).setUpdateFunction.unwrap()(self.handle, Some(callback))
405        };
406    }
407
408    /// Sets the draw function for the given sprite.
409    pub fn set_draw_function(&self, func: impl Fn(&Sprite, Rect<f32>, Rect<f32>) + 'static) {
410        *self.get_userdata().draw_fn.borrow_mut() = Some(Box::new(func));
411        extern "C" fn callback(
412            sprite: *mut sys::LCDSprite,
413            bounds: sys::PDRect,
414            drawrect: sys::PDRect,
415        ) {
416            let sprite = Sprite::from_ref(sprite);
417            let func = sprite.get_userdata().draw_fn.borrow();
418            let func = &func.as_ref().unwrap();
419            func(&sprite, bounds.into(), drawrect.into())
420        }
421        unsafe { (*PLAYDATE.sprite.handle).setDrawFunction.unwrap()(self.handle, Some(callback)) };
422    }
423
424    /// Marks the area of the given sprite, relative to its bounds, to be checked for collisions with other sprites' collide rects.
425    pub fn set_collide_rect(&self, collide_rect: Rect<f32>) {
426        unsafe {
427            (*PLAYDATE.sprite.handle).setCollideRect.unwrap()(self.handle, collide_rect.into());
428        }
429    }
430
431    /// Returns the given sprite’s collide rect.
432    pub fn get_collide_rect(&self) -> Rect<f32> {
433        unsafe { (*PLAYDATE.sprite.handle).getCollideRect.unwrap()(self.handle).into() }
434    }
435
436    /// Clears the given sprite’s collide rect.
437    pub fn clear_collide_rect(&self) {
438        unsafe { (*PLAYDATE.sprite.handle).clearCollideRect.unwrap()(self.handle) };
439    }
440
441    /// Set a callback that returns a SpriteCollisionResponseType for a collision between sprite and other.
442    pub fn set_collision_response_function(
443        &self,
444        func: impl Fn(&Sprite, &Sprite) -> SpriteCollisionResponseType + 'static,
445    ) {
446        *self.get_userdata().collision_response_fn.borrow_mut() = Some(Box::new(func));
447        extern "C" fn callback(
448            sprite: *mut sys::LCDSprite,
449            other: *mut sys::LCDSprite,
450        ) -> SpriteCollisionResponseType {
451            let sprite = Sprite::from_ref(sprite);
452            let other = Sprite::from_ref(other);
453            let func = sprite.get_userdata().collision_response_fn.borrow();
454            let func = &func.as_ref().unwrap();
455            func(&sprite, &other)
456        }
457        unsafe {
458            (*PLAYDATE.sprite.handle)
459                .setCollisionResponseFunction
460                .unwrap()(self.handle, Some(callback));
461        }
462    }
463
464    /// Sets the sprite’s stencil to the given pattern.
465    pub fn set_stencil_pattern(&self, mut pattern: LCDPattern) {
466        unsafe {
467            (*PLAYDATE.sprite.handle).setStencilPattern.unwrap()(self.handle, pattern.as_mut_ptr())
468        };
469    }
470
471    /// Clears the sprite’s stencil.
472    pub fn clear_stencil(&self) {
473        unsafe { (*PLAYDATE.sprite.handle).clearStencil.unwrap()(self.handle) };
474    }
475
476    /// Gets the sprite’s userdata, an arbitrary pointer used for associating the sprite with other data.
477    fn get_userdata(&self) -> &SpriteData {
478        let ptr = unsafe { (*PLAYDATE.sprite.handle).getUserdata.unwrap()(self.handle) };
479        if ptr.is_null() {
480            let ptr = Box::into_raw(Box::<SpriteData>::default());
481            unsafe { (*PLAYDATE.sprite.handle).setUserdata.unwrap()(self.handle, ptr as _) };
482        }
483        let ptr = unsafe { (*PLAYDATE.sprite.handle).getUserdata.unwrap()(self.handle) };
484        unsafe { &*(ptr as *mut SpriteData) }
485    }
486
487    fn drop_userdata(&self) {
488        let ptr = unsafe { (*PLAYDATE.sprite.handle).getUserdata.unwrap()(self.handle) };
489        if !ptr.is_null() {
490            let _boxed = unsafe { Box::from_raw(ptr as *mut SpriteData) };
491        }
492    }
493
494    /// Specifies a stencil image to be set on the frame buffer before the sprite is drawn. If tile is set, the stencil will be tiled. Tiled stencils must have width evenly divisible by 32.
495    pub fn set_stencil_image(&self, stencil: impl AsRef<Bitmap>, tile: i32) {
496        unsafe {
497            (*PLAYDATE.sprite.handle).setStencilImage.unwrap()(
498                self.handle,
499                stencil.as_ref().handle,
500                tile,
501            )
502        };
503    }
504
505    /// Returns the same values as playdate->sprite->moveWithCollisions() but does not actually move the sprite.
506    pub fn check_collisions(&self, move_goal: Vec2<f32>) -> Vec<SpriteCollisionInfo> {
507        let mut actual_x = 0.0;
508        let mut actual_y = 0.0;
509        let mut len = 0;
510        let info = unsafe {
511            (*PLAYDATE.sprite.handle).checkCollisions.unwrap()(
512                self.handle,
513                move_goal.x,
514                move_goal.y,
515                &mut actual_x,
516                &mut actual_y,
517                &mut len,
518            )
519        };
520        let mut result = Vec::new();
521        for i in 0..len {
522            let info = unsafe { info.offset(i as isize).as_ref().unwrap() };
523            result.push(SpriteCollisionInfo::new(info));
524        }
525        // caller is responsible for freeing memory of array returned by moveWithCollisions()
526        PLAYDATE.system.realloc(info as _, 0);
527        result
528    }
529
530    /// Moves the given sprite towards goalX, goalY taking collisions into account and returns an array of SpriteCollisionInfo. len is set to the size of the array and actualX, actualY are set to the sprite’s position after collisions. If no collisions occurred, this will be the same as goalX, goalY.
531    pub fn move_with_collisions(&self, goal: Vec2<f32>) -> (Vec2<f32>, Vec<SpriteCollisionInfo>) {
532        let mut actual_x = 0.0;
533        let mut actual_y = 0.0;
534        let mut len = 0;
535        let info = unsafe {
536            (*PLAYDATE.sprite.handle).moveWithCollisions.unwrap()(
537                self.handle,
538                goal.x,
539                goal.y,
540                &mut actual_x,
541                &mut actual_y,
542                &mut len,
543            )
544        };
545        let mut result = Vec::new();
546        for i in 0..len {
547            let info = unsafe { info.offset(i as isize).as_ref().unwrap() };
548            result.push(SpriteCollisionInfo::new(info));
549        }
550        // caller is responsible for freeing memory of array returned by moveWithCollisions()
551        PLAYDATE.system.realloc(info as _, 0);
552        (vec2!(actual_x, actual_y), result)
553    }
554
555    /// Returns an array of sprites that have collide rects that are currently overlapping the given sprite’s collide rect.
556    pub fn overlapping_sprites(&self) -> Vec<Ref<Sprite>> {
557        let mut len = 0;
558        let sprites =
559            unsafe { (*PLAYDATE.sprite.handle).overlappingSprites.unwrap()(self.handle, &mut len) };
560        let mut result = Vec::new();
561        for i in 0..len {
562            let sprite = unsafe { sprites.offset(i as isize).as_ref().unwrap() };
563            result.push(Sprite::from_ref(*sprite));
564        }
565        PLAYDATE.system.realloc(sprites as _, 0);
566        result
567    }
568}
569
570impl AsRef<Self> for Sprite {
571    fn as_ref(&self) -> &Self {
572        self
573    }
574}
575
576impl Drop for Sprite {
577    fn drop(&mut self) {
578        // FIXME: Remove from display list?
579        self.drop_userdata();
580        unsafe { (*PLAYDATE.sprite.handle).freeSprite.unwrap()(self.handle) };
581    }
582}
583
584impl Clone for Sprite {
585    fn clone(&self) -> Self {
586        let handle = unsafe { (*PLAYDATE.sprite.handle).copy.unwrap()(self.handle) };
587        Self { handle }
588    }
589}
590
591#[derive(Debug, Clone, PartialEq)]
592pub struct SpriteCollisionInfo<'a> {
593    pub sprite: Ref<'a, Sprite>,
594    pub other: Ref<'a, Sprite>,
595    pub response_type: SpriteCollisionResponseType,
596    pub overlaps: u8,
597    pub ti: f32,
598    pub move_: Vec2<f32>,
599    pub normal: Vec2<i32>,
600    pub touch: Vec2<f32>,
601    pub sprite_rect: Rect<f32>,
602    pub other_rect: Rect<f32>,
603}
604
605impl<'a> SpriteCollisionInfo<'a> {
606    fn new(info: &sys::SpriteCollisionInfo) -> Self {
607        Self {
608            sprite: Sprite::from_ref(info.sprite),
609            other: Sprite::from_ref(info.other),
610            response_type: info.responseType,
611            overlaps: info.overlaps,
612            ti: info.ti,
613            move_: info.move_.into(),
614            normal: info.normal.into(),
615            touch: info.touch.into(),
616            sprite_rect: info.spriteRect.into(),
617            other_rect: info.otherRect.into(),
618        }
619    }
620}
621
622#[derive(Debug, Clone, PartialEq)]
623pub struct SpriteQueryInfo<'a> {
624    pub sprite: Ref<'a, Sprite>,
625    pub ti1: f32,
626    pub ti2: f32,
627    pub entry_point: Vec2<f32>,
628    pub exit_point: Vec2<f32>,
629}
630
631impl<'a> SpriteQueryInfo<'a> {
632    fn new(info: &sys::SpriteQueryInfo) -> Self {
633        Self {
634            sprite: Sprite::from_ref(info.sprite),
635            ti1: info.ti1,
636            ti2: info.ti2,
637            entry_point: info.entryPoint.into(),
638            exit_point: info.exitPoint.into(),
639        }
640    }
641}