playdate_sprite/callback/
collision.rs

1use core::marker::PhantomData;
2use core::ops::Deref;
3
4use sys::ffi::{LCDSprite, SpriteCollisionResponseType};
5use sys::traits::AsRaw;
6
7use crate::{Sprite, SpriteApi, TypedSprite, SpriteRef, AnySprite, SharedSprite, SpriteType};
8use crate::api;
9
10
11// This is mostly probably should be implemented for OwnedSprite only.
12impl<UD, Api: api::Api, const FOD: bool> Sprite<UD, Api, FOD> {
13	/// Sets the collision response function for the this sprite.
14	pub fn into_collision_response_handler<T: SpriteCollisionResponse<Userdata = UD>>(self) -> Handle<FOD, Self, T>
15		where T::Api: Default {
16		Handle::new(self)
17	}
18}
19
20
21pub trait SpriteCollisionResponse: Sized + SpriteType {
22	fn on_collision(sprite: &Handle<false, SharedSprite<Self::Userdata, Self::Api>, Self>,
23	                other: SpriteRef)
24	                -> SpriteCollisionResponseType;
25
26	unsafe extern "C" fn proxy(sprite: *mut LCDSprite, other: *mut LCDSprite) -> SpriteCollisionResponseType
27		where Self::Api: Default {
28		Self::on_collision(
29		                   &Handle::new_unchanged(SpriteRef::from(sprite).into()),
30		                   SpriteRef::from(other),
31		)
32	}
33}
34
35
36pub struct Handle<const FOD: bool, T, H>(pub(super) T, PhantomData<H>)
37	where T: TypedSprite + Sized,
38	      H: SpriteCollisionResponse;
39
40impl<const FOD: bool, T, H> AnySprite for Handle<FOD, T, H>
41	where T: TypedSprite + Sized,
42	      H: SpriteCollisionResponse,
43	      T: AnySprite
44{
45}
46impl<const FOD: bool, T, H> SpriteApi for Handle<FOD, T, H>
47	where T: TypedSprite + Sized,
48	      H: SpriteCollisionResponse,
49	      T: SpriteApi
50{
51	type Api = <T as SpriteApi>::Api;
52
53	fn api(&self) -> Self::Api
54		where Self::Api: Copy {
55		self.0.api()
56	}
57
58	fn api_ref(&self) -> &Self::Api { self.0.api_ref() }
59}
60
61impl<const FOD: bool, T, H> AsRaw for Handle<FOD, T, H>
62	where T: TypedSprite + Sized,
63	      H: SpriteCollisionResponse,
64	      T: AsRaw
65{
66	type Type = <T as AsRaw>::Type;
67	unsafe fn as_raw(&self) -> *mut Self::Type { self.0.as_raw() }
68}
69
70impl<const FOD: bool, T, H> Handle<FOD, T, H>
71	where T: TypedSprite + Sized,
72	      H: SpriteCollisionResponse
73{
74	/// - Unregister inner callback for sprite
75	/// - Unwrap, return the underlying sprite
76	/// - Remove the collision response handler
77	#[must_use = "Sprite"]
78	pub fn into_inner(self) -> T {
79		use api::Api;
80
81		let ptr = unsafe { self.0.as_raw() };
82		let f = self.0.api_ref().set_collision_response_function();
83		unsafe { f(ptr, None) };
84		self.0
85	}
86}
87
88
89impl<const FOD: bool, T, H> AsRef<Sprite<T::Userdata, T::Api, FOD>> for Handle<FOD, T, H>
90	where T: TypedSprite + AsRef<Sprite<T::Userdata, T::Api, FOD>>,
91	      H: SpriteCollisionResponse
92{
93	fn as_ref(&self) -> &Sprite<T::Userdata, T::Api, FOD> { self.0.as_ref() }
94}
95
96
97impl<const FOD: bool, T, H> AsMut<Sprite<T::Userdata, T::Api, FOD>> for Handle<FOD, T, H>
98	where T: TypedSprite + AsMut<Sprite<T::Userdata, T::Api, FOD>>,
99	      H: SpriteCollisionResponse
100{
101	fn as_mut(&mut self) -> &mut Sprite<T::Userdata, T::Api, FOD> { self.0.as_mut() }
102}
103
104
105impl<const FOD: bool, T, H> Deref for Handle<FOD, T, H>
106	where T: TypedSprite + AsRef<Sprite<T::Userdata, T::Api, FOD>>,
107	      H: SpriteCollisionResponse
108{
109	type Target = Sprite<T::Userdata, T::Api, FOD>;
110	fn deref(&self) -> &Self::Target { self.0.as_ref() }
111}
112
113
114impl<const FOD: bool, T, H> Handle<FOD, T, H>
115	where T: TypedSprite + SpriteApi,
116	      H: SpriteCollisionResponse
117{
118	pub(super) fn new(sprite: T) -> Self
119		where H::Api: Default {
120		use crate::api::Api;
121
122		let f = sprite.api_ref().set_collision_response_function();
123		unsafe { f(sprite.as_raw(), Some(H::proxy)) };
124		Self::new_unchanged(sprite)
125	}
126
127	fn new_unchanged(sprite: T) -> Self { Self(sprite, PhantomData::<H>) }
128}
129
130
131pub mod l2 {
132	use core::ops::Deref;
133	use core::marker::PhantomData;
134
135	use sys::traits::AsRaw;
136
137	use crate::AnySprite;
138	use crate::Sprite;
139	use crate::SpriteApi;
140	use crate::TypedSprite;
141	use crate::api;
142	use crate::callback::draw;
143	use crate::callback::update;
144
145	use super::SpriteCollisionResponse;
146
147
148	impl<UD, Api, const FOD: bool, H> update::Handle<FOD, Sprite<UD, Api, FOD>, H>
149		where Api: api::Api,
150		      H: update::SpriteUpdate
151	{
152		/// Sets the collision response function for the this sprite.
153		pub fn into_collision_response_handler<T: SpriteCollisionResponse<Userdata = UD>>(
154			self)
155			-> Handle<FOD, Sprite<UD, Api, FOD>, Self, T>
156			where T::Api: Default {
157			Handle::new(self)
158		}
159	}
160
161	impl<UD, Api, const FOD: bool, H> draw::Handle<FOD, Sprite<UD, Api, FOD>, H>
162		where Api: api::Api,
163		      H: draw::SpriteDraw
164	{
165		/// Sets the collision response function for the this sprite.
166		pub fn into_collision_response_handler<T: SpriteCollisionResponse<Userdata = UD>>(
167			self)
168			-> Handle<FOD, Sprite<UD, Api, FOD>, Self, T>
169			where T::Api: Default {
170			Handle::new(self)
171		}
172	}
173
174	impl<UD, Api, const FOD: bool, H, H0>
175		draw::l2::Handle<FOD, Sprite<UD, Api, FOD>, update::Handle<FOD, Sprite<UD, Api, FOD>, H0>, H>
176		where Api: api::Api,
177		      H: draw::SpriteDraw,
178		      H0: update::SpriteUpdate
179	{
180		/// Sets the collision response function for the this sprite.
181		pub fn into_collision_response_handler<T: SpriteCollisionResponse<Userdata = UD>>(
182			self)
183			-> Handle<FOD, Sprite<UD, Api, FOD>, Self, T>
184			where T::Api: Default {
185			Handle::new(self)
186		}
187	}
188
189	impl<UD, Api, const FOD: bool, H, H0>
190		update::l2::Handle<FOD, Sprite<UD, Api, FOD>, draw::Handle<FOD, Sprite<UD, Api, FOD>, H0>, H>
191		where Api: api::Api,
192		      H: update::SpriteUpdate,
193		      H0: draw::SpriteDraw
194	{
195		/// Sets the collision response function for the this sprite.
196		pub fn into_collision_response_handler<T: SpriteCollisionResponse<Userdata = UD>>(
197			self)
198			-> Handle<FOD, Sprite<UD, Api, FOD>, Self, T>
199			where T::Api: Default {
200			Handle::new(self)
201		}
202	}
203
204
205	pub struct Handle<const FOD: bool, Sp, T, H>(pub(super) T, PhantomData<Sp>, PhantomData<H>)
206		where T: Sized,
207		      Sp: TypedSprite,
208		      H: SpriteCollisionResponse;
209
210	impl<const FOD: bool, Sp, T, H> AnySprite for Handle<FOD, Sp, T, H>
211		where Sp: TypedSprite,
212		      T: AnySprite,
213		      H: SpriteCollisionResponse
214	{
215	}
216	impl<const FOD: bool, Sp, T, H> SpriteApi for Handle<FOD, Sp, T, H>
217		where Sp: TypedSprite,
218		      T: SpriteApi,
219		      H: SpriteCollisionResponse
220	{
221		type Api = <T as SpriteApi>::Api;
222
223		fn api(&self) -> Self::Api
224			where Self::Api: Copy {
225			self.0.api()
226		}
227
228		fn api_ref(&self) -> &Self::Api { self.0.api_ref() }
229	}
230
231	impl<const FOD: bool, Sp, T, H> AsRaw for Handle<FOD, Sp, T, H>
232		where Sp: TypedSprite,
233		      T: AsRaw,
234		      H: SpriteCollisionResponse
235	{
236		type Type = <T as AsRaw>::Type;
237		unsafe fn as_raw(&self) -> *mut Self::Type { self.0.as_raw() }
238	}
239
240
241	impl<const FOD: bool, Sp, T, H> Handle<FOD, Sp, T, H>
242		where T: AsRef<Sp>,
243		      Sp: TypedSprite,
244		      H: SpriteCollisionResponse
245	{
246		/// - Unregister inner callback for sprite
247		/// - Unwrap, return the underlying sprite
248		/// - Remove the collision response handler
249		#[must_use = "Sprite"]
250		pub fn into_inner(self) -> T {
251			use crate::api::Api;
252
253			let ptr = unsafe { self.0.as_ref().as_raw() };
254			let f = self.0.as_ref().api_ref().set_collision_response_function();
255			unsafe { f(ptr, None) };
256			self.0
257		}
258	}
259
260
261	impl<const FOD: bool, Sp, T, H> AsRef<Sprite<Sp::Userdata, Sp::Api, FOD>> for Handle<FOD, Sp, T, H>
262		where T: AsRef<Sprite<Sp::Userdata, Sp::Api, FOD>>,
263		      Sp: TypedSprite,
264		      H: SpriteCollisionResponse
265	{
266		fn as_ref(&self) -> &Sprite<Sp::Userdata, Sp::Api, FOD> { self.0.as_ref() }
267	}
268
269
270	impl<const FOD: bool, Sp, T, H> Deref for Handle<FOD, Sp, T, H>
271		where T: AsRef<Sprite<Sp::Userdata, Sp::Api, FOD>>,
272		      Sp: TypedSprite,
273		      H: SpriteCollisionResponse
274	{
275		type Target = Sprite<Sp::Userdata, Sp::Api, FOD>;
276		fn deref(&self) -> &Self::Target { self.0.as_ref() }
277	}
278
279
280	impl<const FOD: bool, Sp, T, H> Handle<FOD, Sp, T, H>
281		where T: AsRef<Sp>,
282		      Sp: TypedSprite + SpriteApi,
283		      H: SpriteCollisionResponse
284	{
285		pub(super) fn new(sprite: T) -> Self
286			where H::Api: Default {
287			use crate::api::Api;
288
289			let f = sprite.as_ref().api_ref().set_collision_response_function();
290			unsafe { f(sprite.as_ref().as_raw(), Some(H::proxy)) };
291			Self::new_unchanged(sprite)
292		}
293
294		fn new_unchanged(sprite: T) -> Self { Self(sprite, PhantomData::<Sp>, PhantomData::<H>) }
295	}
296}