11use pyo3:: prelude:: * ;
22
3+ pub trait NativeAdjustedPoints {
4+ fn get_adjusted_points_native ( & mut self ) -> & Vec < ( f32 , f32 ) > ;
5+ }
6+
37#[ derive( Clone ) ]
4- #[ pyclass( subclass , module = "arcade.hitbox.base" ) ]
8+ #[ pyclass( module = "arcade.hitbox.base" ) ]
59pub struct HitBox {
610 #[ pyo3( get, set) ]
711 pub points : Vec < ( f32 , f32 ) > ,
8- #[ pyo3( get, set ) ]
12+ #[ pyo3( get) ]
913 pub position : ( f32 , f32 ) ,
10- #[ pyo3( get, set ) ]
14+ #[ pyo3( get) ]
1115 pub scale : ( f32 , f32 ) ,
1216 pub angle : f32 ,
17+
18+ pub adjusted_cache : Vec < ( f32 , f32 ) > ,
19+ pub cache_dirty : bool ,
1320}
1421
1522#[ pymethods]
@@ -27,6 +34,8 @@ impl HitBox {
2734 position : final_position,
2835 scale : final_scale,
2936 angle : 0.0 ,
37+ adjusted_cache : vec ! [ ] ,
38+ cache_dirty : true ,
3039 }
3140 }
3241
@@ -48,90 +57,93 @@ impl HitBox {
4857 Ok ( adjustable)
4958 }
5059
51- fn get_adjusted_points ( self_ : PyRef < ' _ , Self > ) -> Vec < ( f32 , f32 ) > {
52- let mut new_points: Vec < ( f32 , f32 ) > = Vec :: with_capacity ( self_. points . len ( ) ) ;
53-
54- for point in self_. points . iter ( ) {
55- let x = ( point. 0 * self_. scale . 0 ) + self_. position . 0 ;
56- let y = ( point. 1 * self_. scale . 1 ) + self_. position . 1 ;
57- new_points. push ( ( x, y) ) ;
60+ pub fn get_adjusted_points ( & mut self ) -> Vec < ( f32 , f32 ) > {
61+ if self . cache_dirty {
62+ self . adjusted_cache = Vec :: with_capacity ( self . points . len ( ) ) ;
63+ for point in self . points . iter ( ) {
64+ let x = ( point. 0 * self . scale . 0 ) + self . position . 0 ;
65+ let y = ( point. 1 * self . scale . 1 ) + self . position . 1 ;
66+ self . adjusted_cache . push ( ( x, y) ) ;
67+ }
68+ self . cache_dirty = false ;
5869 }
5970
60- new_points
71+ self . adjusted_cache . to_vec ( )
72+ }
73+
74+ #[ setter]
75+ pub fn set_position ( & mut self , value : ( f32 , f32 ) ) -> PyResult < ( ) > {
76+ self . position = value;
77+ self . cache_dirty = true ;
78+ Ok ( ( ) )
79+ }
80+
81+ #[ setter]
82+ pub fn set_scale ( & mut self , value : ( f32 , f32 ) ) -> PyResult < ( ) > {
83+ self . scale = value;
84+ self . cache_dirty = true ;
85+ Ok ( ( ) )
6186 }
6287
6388 #[ getter]
64- pub fn left ( self_ : PyRef < ' _ , Self > ) -> PyResult < f32 > {
65- let mut converted = HitBox :: get_adjusted_points ( self_ ) ;
89+ pub fn left ( & mut self ) -> PyResult < f32 > {
90+ let mut converted: Vec < ( f32 , f32 ) > = self . get_adjusted_points_native ( ) . to_vec ( ) ;
6691 converted. sort_by ( |a, b| a. 0 . partial_cmp ( & b. 0 ) . unwrap ( ) ) ;
6792 Ok ( converted[ 0 ] . 0 )
6893 }
6994
7095 #[ getter]
71- pub fn right ( self_ : PyRef < ' _ , Self > ) -> PyResult < f32 > {
72- let mut converted: Vec < ( f32 , f32 ) > = HitBox :: get_adjusted_points ( self_ ) ;
96+ pub fn right ( & mut self ) -> PyResult < f32 > {
97+ let mut converted: Vec < ( f32 , f32 ) > = self . get_adjusted_points_native ( ) . to_vec ( ) ;
7398 converted. sort_by ( |a, b| b. 0 . partial_cmp ( & a. 0 ) . unwrap ( ) ) ;
7499 Ok ( converted[ 0 ] . 0 )
75100 }
76101
77102 #[ getter]
78- pub fn bottom ( self_ : PyRef < ' _ , Self > ) -> PyResult < f32 > {
79- let mut converted: Vec < ( f32 , f32 ) > = HitBox :: get_adjusted_points ( self_ ) ;
103+ pub fn bottom ( & mut self ) -> PyResult < f32 > {
104+ let mut converted: Vec < ( f32 , f32 ) > = self . get_adjusted_points_native ( ) . to_vec ( ) ;
80105 converted. sort_by ( |a, b| a. 1 . partial_cmp ( & b. 1 ) . unwrap ( ) ) ;
81106 Ok ( converted[ 0 ] . 1 )
82107 }
83108
84109 #[ getter]
85- pub fn top ( self_ : PyRef < ' _ , Self > ) -> PyResult < f32 > {
86- let mut converted: Vec < ( f32 , f32 ) > = HitBox :: get_adjusted_points ( self_ ) ;
110+ pub fn top ( & mut self ) -> PyResult < f32 > {
111+ let mut converted: Vec < ( f32 , f32 ) > = self . get_adjusted_points_native ( ) . to_vec ( ) ;
87112 converted. sort_by ( |a, b| b. 1 . partial_cmp ( & a. 1 ) . unwrap ( ) ) ;
88113 Ok ( converted[ 0 ] . 1 )
89114 }
90115}
91116
92- impl HitBox {
93- pub fn get_adjusted_points_native ( & self ) -> Vec < ( f32 , f32 ) > {
94- let mut new_points: Vec < ( f32 , f32 ) > = Vec :: with_capacity ( self . points . len ( ) ) ;
95-
96- for point in self . points . iter ( ) {
97- let x = ( point. 0 * self . scale . 0 ) + self . position . 0 ;
98- let y = ( point. 1 * self . scale . 1 ) + self . position . 1 ;
99- new_points. push ( ( x, y) ) ;
117+ impl NativeAdjustedPoints for HitBox {
118+ fn get_adjusted_points_native ( & mut self ) -> & Vec < ( f32 , f32 ) > {
119+ if self . cache_dirty {
120+ self . adjusted_cache = Vec :: with_capacity ( self . points . len ( ) ) ;
121+ for point in self . points . iter ( ) {
122+ let x = ( point. 0 * self . scale . 0 ) + self . position . 0 ;
123+ let y = ( point. 1 * self . scale . 1 ) + self . position . 1 ;
124+ self . adjusted_cache . push ( ( x, y) ) ;
125+ }
126+ self . cache_dirty = false ;
100127 }
101128
102- new_points
103- }
104-
105- pub fn left_native ( & self ) -> f32 {
106- let mut converted: Vec < ( f32 , f32 ) > = self . get_adjusted_points_native ( ) ;
107- converted. sort_by ( |a, b| a. 0 . partial_cmp ( & b. 0 ) . unwrap ( ) ) ;
108- converted[ 0 ] . 0
109- }
110-
111- pub fn right_native ( & self ) -> f32 {
112- let mut converted: Vec < ( f32 , f32 ) > = self . get_adjusted_points_native ( ) ;
113- converted. sort_by ( |a, b| b. 0 . partial_cmp ( & a. 0 ) . unwrap ( ) ) ;
114- converted[ 0 ] . 0
115- }
116-
117- pub fn bottom_native ( & self ) -> f32 {
118- let mut converted: Vec < ( f32 , f32 ) > = self . get_adjusted_points_native ( ) ;
119- converted. sort_by ( |a, b| a. 1 . partial_cmp ( & b. 1 ) . unwrap ( ) ) ;
120- converted[ 0 ] . 1
121- }
122-
123- pub fn top_native ( & self ) -> f32 {
124- let mut converted: Vec < ( f32 , f32 ) > = self . get_adjusted_points_native ( ) ;
125- converted. sort_by ( |a, b| b. 1 . partial_cmp ( & a. 1 ) . unwrap ( ) ) ;
126- converted[ 0 ] . 1
129+ & self . adjusted_cache
127130 }
128131}
129132
130133#[ derive( Clone ) ]
131- #[ pyclass( extends= HitBox , module = "arcade.hitbox.base" ) ]
134+ #[ pyclass( module = "arcade.hitbox.base" ) ]
132135pub struct RotatableHitBox {
133136 #[ pyo3( get, set) ]
134- angle : f32 ,
137+ pub points : Vec < ( f32 , f32 ) > ,
138+ #[ pyo3( get) ]
139+ pub position : ( f32 , f32 ) ,
140+ #[ pyo3( get) ]
141+ pub scale : ( f32 , f32 ) ,
142+ #[ pyo3( get) ]
143+ pub angle : f32 ,
144+
145+ pub adjusted_cache : Vec < ( f32 , f32 ) > ,
146+ pub cache_dirty : bool ,
135147}
136148
137149#[ pymethods]
@@ -142,59 +154,194 @@ impl RotatableHitBox {
142154 position : Option < ( f32 , f32 ) > ,
143155 scale : Option < ( f32 , f32 ) > ,
144156 angle : Option < f32 > ,
145- ) -> ( Self , HitBox ) {
157+ ) -> RotatableHitBox {
158+ let final_position = position. unwrap_or ( ( 0.0 , 0.0 ) ) ;
159+ let final_scale = scale. unwrap_or ( ( 1.0 , 1.0 ) ) ;
146160 let final_angle = angle. unwrap_or ( 0.0 ) ;
147- (
148- RotatableHitBox { angle : final_angle } ,
149- HitBox :: new ( points, position, scale) ,
161+ RotatableHitBox {
162+ points,
163+ position : final_position,
164+ scale : final_scale,
165+ angle : final_angle,
166+ adjusted_cache : vec ! [ ] ,
167+ cache_dirty : true ,
168+ }
169+ }
170+
171+ fn create_rotatable (
172+ self_ : PyRef < ' _ , Self > ,
173+ py : Python < ' _ > ,
174+ angle : Option < f32 > ,
175+ ) -> PyResult < Py < RotatableHitBox > > {
176+ let adjustable: Py < RotatableHitBox > = Py :: new (
177+ py,
178+ RotatableHitBox :: new (
179+ self_. points . to_vec ( ) ,
180+ Some ( self_. position ) ,
181+ Some ( self_. scale ) ,
182+ angle,
183+ ) ,
150184 )
185+ . unwrap ( ) ;
186+ Ok ( adjustable)
151187 }
152188
153- pub fn get_adjusted_points ( self_ : PyRef < ' _ , Self > ) -> Vec < ( f32 , f32 ) > {
154- let super_ : & HitBox = self_ . as_ref ( ) ;
155- let mut new_points : Vec < ( f32 , f32 ) > = Vec :: with_capacity ( super_ . points . len ( ) ) ;
189+ pub fn get_adjusted_points ( & mut self ) -> Vec < ( f32 , f32 ) > {
190+ if self . cache_dirty {
191+ self . adjusted_cache = Vec :: with_capacity ( self . points . len ( ) ) ;
156192
157- let rad = self_. angle . to_radians ( ) ;
158- let rad_cos = rad. cos ( ) ;
159- let rad_sin = rad. sin ( ) ;
160- for point in super_. points . iter ( ) {
161- let x = ( ( point. 0 * rad_cos + point. 1 * rad_sin) * super_. scale . 0 ) + super_. position . 0 ;
162- let y = ( ( -point. 0 * rad_sin + point. 1 * rad_cos) * super_. scale . 1 ) + super_. position . 1 ;
163- new_points. push ( ( x, y) ) ;
193+ let rad = self . angle . to_radians ( ) ;
194+ let rad_cos = rad. cos ( ) ;
195+ let rad_sin = rad. sin ( ) ;
196+ for point in self . points . iter ( ) {
197+ let x = ( ( point. 0 * rad_cos + point. 1 * rad_sin) * self . scale . 0 ) + self . position . 0 ;
198+ let y = ( ( -point. 0 * rad_sin + point. 1 * rad_cos) * self . scale . 1 ) + self . position . 1 ;
199+ self . adjusted_cache . push ( ( x, y) ) ;
200+ }
201+ self . cache_dirty = false ;
164202 }
165203
166- new_points
204+ self . adjusted_cache . to_vec ( )
205+ }
206+
207+ #[ setter]
208+ pub fn set_position ( & mut self , value : ( f32 , f32 ) ) -> PyResult < ( ) > {
209+ self . position = value;
210+ self . cache_dirty = true ;
211+ Ok ( ( ) )
212+ }
213+
214+ #[ setter]
215+ pub fn set_scale ( & mut self , value : ( f32 , f32 ) ) -> PyResult < ( ) > {
216+ self . scale = value;
217+ self . cache_dirty = true ;
218+ Ok ( ( ) )
219+ }
220+
221+ #[ setter]
222+ pub fn set_angle ( & mut self , value : f32 ) -> PyResult < ( ) > {
223+ self . angle = value;
224+ self . cache_dirty = true ;
225+ Ok ( ( ) )
167226 }
168227
169228 #[ getter]
170- fn left ( self_ : PyRef < ' _ , Self > ) -> PyResult < f32 > {
171- let mut converted: Vec < ( f32 , f32 ) > = RotatableHitBox :: get_adjusted_points ( self_ ) ;
229+ pub fn left ( & mut self ) -> PyResult < f32 > {
230+ let mut converted: Vec < ( f32 , f32 ) > = self . get_adjusted_points_native ( ) . to_vec ( ) ;
172231 converted. sort_by ( |a, b| a. 0 . partial_cmp ( & b. 0 ) . unwrap ( ) ) ;
173232 Ok ( converted[ 0 ] . 0 )
174233 }
175234
176235 #[ getter]
177- fn right ( self_ : PyRef < ' _ , Self > ) -> PyResult < f32 > {
178- let mut converted: Vec < ( f32 , f32 ) > = RotatableHitBox :: get_adjusted_points ( self_ ) ;
236+ pub fn right ( & mut self ) -> PyResult < f32 > {
237+ let mut converted: Vec < ( f32 , f32 ) > = self . get_adjusted_points_native ( ) . to_vec ( ) ;
179238 converted. sort_by ( |a, b| b. 0 . partial_cmp ( & a. 0 ) . unwrap ( ) ) ;
180239 Ok ( converted[ 0 ] . 0 )
181240 }
182241
183242 #[ getter]
184- fn bottom ( self_ : PyRef < ' _ , Self > ) -> PyResult < f32 > {
185- let mut converted: Vec < ( f32 , f32 ) > = RotatableHitBox :: get_adjusted_points ( self_ ) ;
243+ pub fn bottom ( & mut self ) -> PyResult < f32 > {
244+ let mut converted: Vec < ( f32 , f32 ) > = self . get_adjusted_points_native ( ) . to_vec ( ) ;
186245 converted. sort_by ( |a, b| a. 1 . partial_cmp ( & b. 1 ) . unwrap ( ) ) ;
187246 Ok ( converted[ 0 ] . 1 )
188247 }
189248
190249 #[ getter]
191- fn top ( self_ : PyRef < ' _ , Self > ) -> PyResult < f32 > {
192- let mut converted: Vec < ( f32 , f32 ) > = RotatableHitBox :: get_adjusted_points ( self_ ) ;
250+ pub fn top ( & mut self ) -> PyResult < f32 > {
251+ let mut converted: Vec < ( f32 , f32 ) > = self . get_adjusted_points_native ( ) . to_vec ( ) ;
193252 converted. sort_by ( |a, b| b. 1 . partial_cmp ( & a. 1 ) . unwrap ( ) ) ;
194253 Ok ( converted[ 0 ] . 1 )
195254 }
196255}
197256
257+ impl NativeAdjustedPoints for RotatableHitBox {
258+ fn get_adjusted_points_native ( & mut self ) -> & Vec < ( f32 , f32 ) > {
259+ if self . cache_dirty {
260+ self . adjusted_cache = Vec :: with_capacity ( self . points . len ( ) ) ;
261+
262+ let rad = self . angle . to_radians ( ) ;
263+ let rad_cos = rad. cos ( ) ;
264+ let rad_sin = rad. sin ( ) ;
265+ for point in self . points . iter ( ) {
266+ let x = ( ( point. 0 * rad_cos + point. 1 * rad_sin) * self . scale . 0 ) + self . position . 0 ;
267+ let y = ( ( -point. 0 * rad_sin + point. 1 * rad_cos) * self . scale . 1 ) + self . position . 1 ;
268+ self . adjusted_cache . push ( ( x, y) ) ;
269+ }
270+ self . cache_dirty = false ;
271+ }
272+
273+ & self . adjusted_cache
274+ }
275+ }
276+
277+ // #[derive(Clone)]
278+ // #[pyclass(extends=HitBox, module = "arcade.hitbox.base")]
279+ // pub struct RotatableHitBox {
280+ // #[pyo3(get, set)]
281+ // angle: f32,
282+ // }
283+
284+ // #[pymethods]
285+ // impl RotatableHitBox {
286+ // #[new]
287+ // fn new(
288+ // points: Vec<(f32, f32)>,
289+ // position: Option<(f32, f32)>,
290+ // scale: Option<(f32, f32)>,
291+ // angle: Option<f32>,
292+ // ) -> (Self, HitBox) {
293+ // let final_angle = angle.unwrap_or(0.0);
294+ // (
295+ // RotatableHitBox { angle: final_angle },
296+ // HitBox::new(points, position, scale),
297+ // )
298+ // }
299+
300+ // pub fn get_adjusted_points(self_: PyRef<'_, Self>) -> Vec<(f32, f32)> {
301+ // let super_: &HitBox = self_.as_ref();
302+ // let mut new_points: Vec<(f32, f32)> = Vec::with_capacity(super_.points.len());
303+
304+ // let rad = self_.angle.to_radians();
305+ // let rad_cos = rad.cos();
306+ // let rad_sin = rad.sin();
307+ // for point in super_.points.iter() {
308+ // let x = ((point.0 * rad_cos + point.1 * rad_sin) * super_.scale.0) + super_.position.0;
309+ // let y = ((-point.0 * rad_sin + point.1 * rad_cos) * super_.scale.1) + super_.position.1;
310+ // new_points.push((x, y));
311+ // }
312+
313+ // new_points
314+ // }
315+
316+ // #[getter]
317+ // fn left(self_: PyRef<'_, Self>) -> PyResult<f32> {
318+ // let mut converted: Vec<(f32, f32)> = RotatableHitBox::get_adjusted_points(self_);
319+ // converted.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
320+ // Ok(converted[0].0)
321+ // }
322+
323+ // #[getter]
324+ // fn right(self_: PyRef<'_, Self>) -> PyResult<f32> {
325+ // let mut converted: Vec<(f32, f32)> = RotatableHitBox::get_adjusted_points(self_);
326+ // converted.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap());
327+ // Ok(converted[0].0)
328+ // }
329+
330+ // #[getter]
331+ // fn bottom(self_: PyRef<'_, Self>) -> PyResult<f32> {
332+ // let mut converted: Vec<(f32, f32)> = RotatableHitBox::get_adjusted_points(self_);
333+ // converted.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap());
334+ // Ok(converted[0].1)
335+ // }
336+
337+ // #[getter]
338+ // fn top(self_: PyRef<'_, Self>) -> PyResult<f32> {
339+ // let mut converted: Vec<(f32, f32)> = RotatableHitBox::get_adjusted_points(self_);
340+ // converted.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
341+ // Ok(converted[0].1)
342+ // }
343+ // }
344+
198345// impl RotatableHitBox {
199346// pub fn get_adjusted_points_native(self) -> Vec<(f32, f32)> {
200347// let mut new_points: Vec<(f32, f32)> = Vec::with_capacity(self.parent.points.len());
0 commit comments