Skip to content

Commit

Permalink
Merge pull request #165 from boozook/api/sprite-handler-inprove
Browse files Browse the repository at this point in the history
Dramatically simplify sprite `update`/`draw`/`collision` typed handlers
  • Loading branch information
boozook authored Oct 6, 2023
2 parents 8c2d09c + 504ef2f commit 8601322
Show file tree
Hide file tree
Showing 9 changed files with 58 additions and 89 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion api/sprite/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "playdate-sprite"
version = "0.2.5"
version = "0.2.6"
readme = "README.md"
description = "High-level sprite API built on-top of Playdate API"
keywords = ["playdate", "sdk", "api", "gamedev"]
Expand Down
48 changes: 10 additions & 38 deletions api/sprite/examples/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,20 +94,25 @@ impl Update for Game {
/// Here is our "update sprite" behavior.
mod updater {
use core::ffi::c_float;
use core::marker::PhantomData;

use super::sprite;
use sys::ffi::{LCD_COLUMNS, LCD_ROWS};
use sys::traits::AsRaw;
use sprite::AnySprite;

use super::sprite;
use sprite::{AnySprite, SpriteType};
use sprite::prelude::*;
use sprite::callback::update::{Handle, SpriteUpdate};


pub struct Upd<UD = UpdState, T: AnySprite = SpriteRef>(Sprite<UD, T::Api, false>);
pub struct Upd<UD = UpdState, T: AnySprite = SpriteRef>(PhantomData<(UD, T::Api)>);

impl<T: AnySprite, UD> SpriteType for Upd<UD, T> {
type Api = <T as SpriteApi>::Api;
type Userdata = UD;
}

impl<T, UD> SpriteUpdate for Upd<UD, T>
where T: AnySprite,
Self: From<SpriteRef>,
Self::Userdata: AsMut<UpdState>
{
fn on_update(sprite: &Handle<false, SharedSprite<Self::Userdata, Self::Api>, Self>) {
Expand All @@ -121,46 +126,13 @@ mod updater {
if bounds.y < 0. || bounds.y + bounds.height > LCD_ROWS as _ {
velocity.y = -velocity.y;
}

// Move sprite
sprite.move_by(velocity.x, velocity.y);
}
}
}


mod impls_needed_to_combine_handlers {
use super::*;

impl<T: AnySprite, UD> AsRef<Sprite<UD, T::Api, false>> for Upd<UD, T> {
fn as_ref(&self) -> &Sprite<UD, T::Api, false> { &self.0 }
}

impl<T: AnySprite, UD> From<T> for Upd<UD, T> where Sprite<UD, T::Api, false>: From<T> {
fn from(ptr: T) -> Self { Self(Sprite::from(ptr)) }
}

impl<T: AnySprite, UD> TypedSprite for Upd<UD, T> {
type Userdata = UD;
const FREE_ON_DROP: bool = false;
}
impl<T: AnySprite, UD> AsRaw for Upd<UD, T> {
type Type = <T as AsRaw>::Type;
unsafe fn as_raw(&self) -> *mut Self::Type { self.0.as_raw() }
}
impl<T: AnySprite, UD> SpriteApi for Upd<UD, T> {
type Api = <T as SpriteApi>::Api;

fn api(&self) -> Self::Api
where Self::Api: Copy {
self.0.api()
}

fn api_ref(&self) -> &Self::Api { self.0.api_ref() }
}
}


#[derive(Default)]
pub struct UpdState {
velocity: Point<c_float>,
Expand Down
6 changes: 2 additions & 4 deletions api/sprite/src/callback/collision.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use core::ops::Deref;
use sys::ffi::{LCDSprite, SpriteCollisionResponseType};
use sys::traits::AsRaw;

use crate::{Sprite, SpriteApi, TypedSprite, SpriteRef, AnySprite, SharedSprite};
use crate::{Sprite, SpriteApi, TypedSprite, SpriteRef, AnySprite, SharedSprite, SpriteType};
use crate::api;


Expand All @@ -18,15 +18,13 @@ impl<UD, Api: api::Api, const FOD: bool> Sprite<UD, Api, FOD> {
}


pub trait SpriteCollisionResponse: Sized + TypedSprite
where Self: From<SpriteRef> {
pub trait SpriteCollisionResponse: Sized + SpriteType {
fn on_collision(sprite: &Handle<false, SharedSprite<Self::Userdata, Self::Api>, Self>,
other: SpriteRef)
-> SpriteCollisionResponseType;

unsafe extern "C" fn proxy(sprite: *mut LCDSprite, other: *mut LCDSprite) -> SpriteCollisionResponseType
where Self::Api: Default {
sys::println!("on_collision");
Self::on_collision(
&Handle::new_unchanged(SpriteRef::from(sprite).into()),
SpriteRef::from(other),
Expand Down
5 changes: 2 additions & 3 deletions api/sprite/src/callback/draw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use core::ops::Deref;
use sys::ffi::{LCDSprite, PDRect};
use sys::traits::AsRaw;

use crate::{Sprite, SpriteApi, TypedSprite, SpriteRef, AnySprite, SharedSprite};
use crate::{Sprite, SpriteApi, TypedSprite, SpriteRef, AnySprite, SharedSprite, SpriteType};
use crate::api::{self, Api};


Expand All @@ -22,8 +22,7 @@ impl<UD, Api: api::Api, const FOD: bool> Sprite<UD, Api, FOD> {
}


pub trait SpriteDraw: Sized + TypedSprite
where Self: From<SpriteRef> {
pub trait SpriteDraw: Sized + SpriteType {
fn on_draw(sprite: &Handle<false, SharedSprite<Self::Userdata, Self::Api>, Self>,
bounds: PDRect,
draw_rect: PDRect);
Expand Down
5 changes: 2 additions & 3 deletions api/sprite/src/callback/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use core::ops::Deref;
use sys::ffi::LCDSprite;
use sys::traits::AsRaw;

use crate::{Sprite, SpriteApi, TypedSprite, SpriteRef, AnySprite, SharedSprite};
use crate::{Sprite, SpriteApi, TypedSprite, SpriteRef, AnySprite, SharedSprite, SpriteType};
use crate::api::{self, Api};


Expand All @@ -18,8 +18,7 @@ impl<UD, Api: api::Api, const FOD: bool> Sprite<UD, Api, FOD> {
}


pub trait SpriteUpdate: Sized + TypedSprite
where Self: From<SpriteRef> {
pub trait SpriteUpdate: Sized + SpriteType {
fn on_update(sprite: &Handle<false, SharedSprite<Self::Userdata, Self::Api>, Self>);

unsafe extern "C" fn proxy(sprite: *mut LCDSprite)
Expand Down
21 changes: 20 additions & 1 deletion api/sprite/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,5 +272,24 @@ pub trait TypedSprite: AsRaw<Type = LCDSprite> + SpriteApi {
/// Associated user-data with sprite.
type Userdata;
/// Should be freed when sprite is dropped.
const FREE_ON_DROP: bool;
const FREE_ON_DROP: bool = true;
}


/// Represents strictly typed sprite, includes associated user-data and free-on-drop flag.
pub trait SpriteType {
/// Type of API access-point.
type Api: api::Api;

/// Associated user-data with sprite.
type Userdata;

/// Should be freed when sprite is dropped.
const FREE_ON_DROP: bool = false;
}

impl<T: TypedSprite> SpriteType for T {
type Api = <T as SpriteApi>::Api;
type Userdata = <T as TypedSprite>::Userdata;
const FREE_ON_DROP: bool = <T as TypedSprite>::FREE_ON_DROP;
}
2 changes: 1 addition & 1 deletion components/crank-indicator/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "playdate-ui-crank-indicator"
version = "0.1.0"
version = "0.1.1"
readme = "README.md"
description = "Crank Indicator UI component."
edition.workspace = true
Expand Down
54 changes: 18 additions & 36 deletions components/crank-indicator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ extern crate sys;

use core::ffi::c_int;
use core::ffi::c_uint;
use core::marker::PhantomData;

use display::DisplayScale;
use gfx::BitmapFlip;
Expand All @@ -14,6 +15,7 @@ use gfx::bitmap;
use gfx::bitmap::Bitmap;
use gfx::bitmap::table::BitmapTable;
use sprite::Sprite;
use sprite::SpriteType;
use sys::ffi::PDRect;
use sys::traits::AsRaw;

Expand Down Expand Up @@ -76,10 +78,22 @@ impl SpriteApi for CrankIndicator {
}
impl AnySprite for CrankIndicator {}

impl SpriteType for CrankIndicator {
type Api = <Self as SpriteApi>::Api;
type Userdata = <UpdateDraw as SpriteType>::Userdata;
}


pub struct UpdateDraw<T: AnySprite = SpriteRef>(Sprite<State, T::Api, false>);
pub struct UpdateDraw<T: AnySprite = SpriteRef>(PhantomData<T>);

impl<T: AnySprite> SpriteUpdate for UpdateDraw<T> where Self: From<SpriteRef> {
impl<T: AnySprite> SpriteType for UpdateDraw<T> {
type Api = <T as SpriteApi>::Api;
type Userdata = State;
const FREE_ON_DROP: bool = false;
}

impl<T: AnySprite> SpriteUpdate for UpdateDraw<T> {
#[inline(always)]
fn on_update(s: &update::Handle<false, SharedSprite<Self::Userdata, Self::Api>, Self>) {
if let Some(state) = s.userdata() {
if state.update() {
Expand All @@ -92,7 +106,8 @@ impl<T: AnySprite> SpriteUpdate for UpdateDraw<T> where Self: From<SpriteRef> {
}
}

impl<T: AnySprite> SpriteDraw for UpdateDraw<T> where Self: From<SpriteRef> {
impl<T: AnySprite> SpriteDraw for UpdateDraw<T> {
#[inline(always)]
fn on_draw(s: &draw::Handle<false, SharedSprite<Self::Userdata, Self::Api>, Self>, bounds: PDRect, _: PDRect) {
if let Some(state) = s.userdata() {
let gfx = state.gfx;
Expand Down Expand Up @@ -400,36 +415,3 @@ struct Size<T> {
impl<T> Size<T> {
const fn new(w: T, h: T) -> Size<T> { Self { w, h } }
}


mod impls_combine_handlers {
use sys::traits::AsRaw;
use super::*;

impl<T: AnySprite> AsRef<Sprite<State, T::Api, false>> for UpdateDraw<T> {
fn as_ref(&self) -> &Sprite<State, T::Api, false> { &self.0 }
}

impl<T: AnySprite> From<T> for UpdateDraw<T> where Sprite<State, T::Api, false>: From<T> {
fn from(ptr: T) -> Self { Self(Sprite::from(ptr)) }
}

impl<T: AnySprite> TypedSprite for UpdateDraw<T> {
type Userdata = State;
const FREE_ON_DROP: bool = false;
}
impl<T: AnySprite> AsRaw for UpdateDraw<T> {
type Type = <T as AsRaw>::Type;
unsafe fn as_raw(&self) -> *mut Self::Type { self.0.as_raw() }
}
impl<T: AnySprite> SpriteApi for UpdateDraw<T> {
type Api = <T as SpriteApi>::Api;

fn api(&self) -> Self::Api
where Self::Api: Copy {
self.0.api()
}

fn api_ref(&self) -> &Self::Api { self.0.api_ref() }
}
}

0 comments on commit 8601322

Please sign in to comment.