1use std::{
4 collections::HashMap,
5 hash::Hash
6};
7use sdl2::{
8 event::Event,
9 rect::Rect,
10 render::{
11 Canvas, TextureCreator
12 }, video::{
13 Window, WindowContext
14 }
15};
16use crate::{
17 collision::CollisionShape,
18 res::{
19 Font, Image, Sound
20 }, IndexRestriction
21};
22
23#[derive(Clone)]
32pub struct GameObjectState<Img, Spr, Data> where
33 Spr: IndexRestriction,
34 Img: IndexRestriction,
35 Data: Clone {
36 pub name: String,
37 pub pos: (f64, f64),
38 pub collider: CollisionShape,
39 pub cur_spr: Spr,
40 pub sprs: HashMap<Spr, Sprite<Img>>,
41 pub custom: Data
42}
43
44pub trait GameObjectBehavior<Img, Snd, Fnt, Spr, Rm, Data>:
55 GameObjectBehaviorClone<Img, Snd, Fnt, Spr, Rm, Data> where
56 Spr: IndexRestriction,
57 Img: IndexRestriction,
58 Snd: IndexRestriction,
59 Fnt: IndexRestriction,
60 Rm: IndexRestriction,
61 Data: Clone {
62 fn state(&self) -> GameObjectState<Img, Spr, Data>;
63
64 fn set_state(&mut self, new_state: &GameObjectState<Img, Spr, Data>);
65
66 fn on_reset(&mut self) -> bool;
69
70 fn update(
73 &mut self, _delta: f64,
74 _ctl_objs: &Vec<Box<dyn ControlObjectBehavior<Img, Snd, Fnt, Spr, Rm, Data>>>,
75 _others: &Vec<Box<dyn GameObjectBehavior<Img, Snd, Fnt, Spr, Rm, Data>>>) -> (
76 Option<Rm>, Vec<Box<dyn GameObjectBehavior<Img, Snd, Fnt, Spr, Rm, Data>>>
77 ) {
78 (None, vec![])
79 }
80
81 fn handle_sdl_event(&mut self, _event: &Event) {}
82
83 fn on_collision(
84 &mut self,
85 _other: &Box<dyn GameObjectBehavior<Img, Snd, Fnt, Spr, Rm, Data>>) {}
86
87 fn render(
88 &mut self, cnv: &mut Canvas<Window>,
89 imgs: &HashMap<Img, Image>, _snds: &HashMap<Snd, Sound>,
90 _fonts: &HashMap<Fnt, Font>, _creator: &TextureCreator<WindowContext>,
91 elapsed: f64) -> Result<(), String> {
92 let mut state = self.state().clone();
93 let GameObjectState { ref mut sprs, ref mut cur_spr, pos, .. } = state;
94 if let Some(spr) = sprs.get_mut(cur_spr) {
95 spr.update(elapsed);
96 spr.render(cnv, imgs, (pos.0 as i32, pos.1 as i32))?;
97 }
98 self.set_state(&state);
99 Ok(())
100 }
101
102 fn should_remove(&self) -> bool {
103 false
104 }
105}
106
107pub trait GameObjectBehaviorClone<Img, Snd, Fnt, Spr, Rm, Data> where
109 Spr: IndexRestriction,
110 Img: IndexRestriction,
111 Snd: IndexRestriction,
112 Fnt: IndexRestriction,
113 Rm: IndexRestriction,
114 Data: Clone {
115 fn clone_box(&self) -> Box<dyn GameObjectBehavior<Img, Snd, Fnt, Spr, Rm, Data>>;
116}
117
118impl<Img, Snd, Fnt, Spr, Rm, Data, T>
119 GameObjectBehaviorClone<Img, Snd, Fnt, Spr, Rm, Data> for T where
120 T: 'static + GameObjectBehavior<Img, Snd, Fnt, Spr, Rm, Data> + Clone,
121 Spr: IndexRestriction,
122 Img: IndexRestriction,
123 Snd: IndexRestriction,
124 Fnt: IndexRestriction,
125 Rm: IndexRestriction,
126 Data: Clone {
127 fn clone_box(&self) -> Box<dyn GameObjectBehavior<Img, Snd, Fnt, Spr, Rm, Data>> {
128 Box::new(self.clone())
129 }
130}
131
132impl<Img, Snd, Fnt, Spr, Rm, Data> Clone
133 for Box<dyn GameObjectBehavior<Img, Snd, Fnt, Spr, Rm, Data>> where
134 Spr: IndexRestriction,
135 Img: IndexRestriction,
136 Snd: IndexRestriction,
137 Fnt: IndexRestriction,
138 Rm: IndexRestriction,
139 Data: Clone {
140 fn clone(&self) -> Self {
141 self.clone_box()
142 }
143}
144
145pub trait ControlObjectBehavior<Img, Snd, Fnt, Spr, Rm, Data>:
148 ControlObjectBehaviorClone<Img, Snd, Fnt, Spr, Rm, Data> where
149 Spr: IndexRestriction,
150 Img: IndexRestriction,
151 Snd: IndexRestriction,
152 Fnt: IndexRestriction,
153 Rm: IndexRestriction,
154 Data: Clone {
155 fn data(&self) -> Data;
156
157 fn handle_sdl_event(&mut self, _event: &Event) {}
158
159 fn update(
160 &mut self, _delta: f64, _cur_room: &Rm,
161 _others: &Vec<Box<dyn ControlObjectBehavior<Img, Snd, Fnt, Spr, Rm, Data>>>,
162 _room_objs: &Vec<Box<dyn GameObjectBehavior<Img, Snd, Fnt, Spr, Rm, Data>>>) -> (
163 Option<Rm>, Vec<Box<dyn GameObjectBehavior<Img, Snd, Fnt, Spr, Rm, Data>>>
164 ) {
165 (None, vec![])
166 }
167
168 fn render(
169 &mut self, _cnv: &mut Canvas<Window>, _cur_room: &Rm,
170 _imgs: &HashMap<Img, Image>, _snds: &HashMap<Snd, Sound>,
171 _fonts: &HashMap<Fnt, Font>, _creator: &TextureCreator<WindowContext>,
172 _elapsed: f64) -> Result<(), String> {
173 Ok(())
174 }
175}
176
177pub trait ControlObjectBehaviorClone<Img, Snd, Fnt, Spr, Rm, Data> where
178 Spr: IndexRestriction,
179 Img: IndexRestriction,
180 Snd: IndexRestriction,
181 Fnt: IndexRestriction,
182 Rm: IndexRestriction,
183 Data: Clone {
184 fn clone_box(&self) -> Box<dyn ControlObjectBehavior<Img, Snd, Fnt, Spr, Rm, Data>>;
185}
186
187impl<Img, Snd, Fnt, Spr, Rm, Data, T>
188 ControlObjectBehaviorClone<Img, Snd, Fnt, Spr, Rm, Data> for T where
189 T: 'static + ControlObjectBehavior<Img, Snd, Fnt, Spr, Rm, Data> + Clone,
190 Spr: IndexRestriction,
191 Img: IndexRestriction,
192 Snd: IndexRestriction,
193 Fnt: IndexRestriction,
194 Rm: IndexRestriction,
195 Data: Clone {
196 fn clone_box(&self) -> Box<dyn ControlObjectBehavior<Img, Snd, Fnt, Spr, Rm, Data>> {
197 Box::new(self.clone())
198 }
199}
200
201impl<Img, Snd, Fnt, Spr, Rm, Data> Clone
202 for Box<dyn ControlObjectBehavior<Img, Snd, Fnt, Spr, Rm, Data>> where
203 Spr: IndexRestriction,
204 Img: IndexRestriction,
205 Snd: IndexRestriction,
206 Fnt: IndexRestriction,
207 Rm: IndexRestriction,
208 Data: Clone {
209 fn clone(&self) -> Self {
210 self.clone_box()
211 }
212}
213
214#[derive(Clone, Copy)]
218pub struct Frame<ImgId> where ImgId: Hash + Eq + Clone + Copy {
219 src: ImgId,
220 clip: Rect,
221 size: (i32, i32)
222}
223
224impl<ImgId> Frame<ImgId> where ImgId: Hash + Eq + Clone + Copy {
225 pub fn new(src: ImgId, clip: Rect, size: (i32, i32)) -> Self {
226 Self {
227 src,
228 clip,
229 size
230 }
231 }
232
233 pub fn render(
234 &self, cnv: &mut Canvas<Window>, imgs: &HashMap<ImgId, Image>,
235 pos: (i32, i32), origin: (i32, i32), scale: (f64, f64),
236 angle: f64, flip: (bool, bool)) -> Result<(), String> {
237 let base_scale = (
238 self.size.0 as f64 / self.clip.w as f64,
239 self.size.1 as f64 / self.clip.h as f64
240 );
241 let dest = Rect::new(
242 (pos.0 as f64 - origin.0 as f64 * base_scale.0 * scale.0) as i32,
243 (pos.1 as f64 - origin.1 as f64 * base_scale.1 * scale.1) as i32,
244 (self.size.0 as f64 * scale.0) as u32,
245 (self.size.1 as f64 * scale.1) as u32
246 );
247 imgs[&self.src].render(cnv, &self.clip, &dest, angle, flip)
248 }
249}
250
251#[derive(Clone)]
253pub struct Sprite<Img> where Img: IndexRestriction {
254 pub frames: Vec<Frame<Img>>,
255 pub anim_spd: f64,
256 pub origin: (i32, i32),
257 pub anim_idx: usize,
258 pub anim_idx_smooth: f64,
259 pub scale: (f64, f64),
260 pub angle: f64,
261 pub flip: (bool, bool)
262}
263
264impl<Img> Sprite<Img> where Img: IndexRestriction {
265 pub fn new(frames: Vec<Frame<Img>>, anim_spd: f64, origin: (i32, i32)) -> Self {
266 Self {
267 frames: frames.clone(),
268 anim_spd,
269 origin,
270 anim_idx: 0,
271 anim_idx_smooth: 0.0,
272 scale: (1.0, 1.0),
273 angle: 0.0,
274 flip: (false, false)
275 }
276 }
277
278 pub fn update(&mut self, elapsed: f64) {
279 self.anim_idx_smooth += elapsed * self.anim_spd;
280 if self.anim_idx_smooth > 1.0 {
281 if self.anim_idx + 1 >= self.frames.len() {
282 self.anim_idx = 0;
283 } else {
284 self.anim_idx += 1;
285 }
286 self.anim_idx_smooth = 0.0;
287 }
288 }
289
290 pub fn render(
291 &self, cnv: &mut Canvas<Window>, imgs: &HashMap<Img, Image>,
292 pos: (i32, i32)) -> Result<(), String> {
293 self.frames[self.anim_idx].render(
294 cnv, imgs, pos, self.origin, self.scale, self.angle, self.flip
295 )
296 }
297}
298