1use macroquad::{input::*, miniquad::TextureParams, prelude::*};
2use std::collections::HashMap;
3
4pub const WHITE1: Color = color_u8!(236, 236, 236, 255);
5pub const WHITE2: Color = color_u8!(204, 204, 204, 255);
6pub const BLACK1: Color = color_u8!(24, 24, 24, 255);
7pub const BLACK2: Color = color_u8!(31, 31, 31, 255);
8
9pub struct D2 {
10 w: f32,
11 h: f32,
12 pub background: Color,
13 screen_w: f32,
14 screen_h: f32,
15 pub objects: HashMap<String, GObject>,
16 sorted_objects: Vec<String>,
17 object_z: f32,
18 touched: HashMap<u64, (String, Vec2, TouchPhase)>,
19}
20
21impl D2 {
22 pub fn new(w: f32, h: f32) -> Self {
23 simulate_mouse_with_touch(false);
24 Self {
25 w: w,
26 h: h,
27 background: BLACK1,
28 screen_w: screen_width(),
29 screen_h: screen_height(),
30 objects: HashMap::new(),
31 sorted_objects: Vec::new(),
32 object_z: 0.,
33 touched: HashMap::new(),
34 }
35 }
36
37 pub fn update(&mut self) {
38 self.screen_w = screen_width();
39 self.screen_h = screen_height();
40
41 self.touched
42 .retain(|_, (_, _, phase)| *phase != TouchPhase::Ended);
43
44 for touch in touches() {
45 match touch.phase {
46 TouchPhase::Started => {
47 self.in_touch(touch.id, touch.position.x, touch.position.y);
48 }
49 TouchPhase::Moved | TouchPhase::Stationary => {
50 if let Some(s) = self.touched.get_mut(&touch.id) {
51 s.1 = touch.position;
52 s.2 = touch.phase;
53 }
54 }
55 TouchPhase::Ended | TouchPhase::Cancelled => {
56 if let Some(s) = self.touched.get_mut(&touch.id) {
57 s.2 = TouchPhase::Ended;
58 }
59 }
60 }
61 }
62
63 if is_mouse_button_pressed(MouseButton::Left) {
64 self.in_touch(0, mouse_position().0, mouse_position().1);
65 } else if is_mouse_button_released(MouseButton::Left) {
66 if let Some(s) = self.touched.get_mut(&0) {
67 s.2 = TouchPhase::Ended;
68 }
69 } else if is_mouse_button_down(MouseButton::Left) {
70 if let Some(s) = self.touched.get_mut(&0) {
71 s.1 = vec2(mouse_position().0, mouse_position().1);
72 s.2 = TouchPhase::Moved;
73 }
74 }
75 }
76
77 pub fn draw(&mut self) {
78 clear_background(self.background);
79
80 let t = get_time();
81
82 for s in &self.sorted_objects {
83 if let Some(obj) = self.objects.get_mut(s) {
84 if obj.anim {
85 if t < obj.anim_time_start + obj.anim_time_end {
86 obj.x = obj.anim_start.x
87 + (obj.anim_end.x
88 * curve(
89 ((t - obj.anim_time_start) / obj.anim_time_end) as f32,
90 obj.anim_curve,
91 ));
92 obj.y = obj.anim_start.y
93 + (obj.anim_end.y
94 * curve(
95 ((t - obj.anim_time_start) / obj.anim_time_end) as f32,
96 obj.anim_curve,
97 ));
98 } else {
99 println!(
100 "{} {}",
101 obj.anim_start.x + obj.anim_end.x,
102 obj.anim_start.y + obj.anim_end.y
103 );
104 obj.anim = false;
105 obj.x = obj.anim_start.x + obj.anim_end.x;
106 obj.y = obj.anim_start.y + obj.anim_end.y;
107 }
108 }
109 }
110 if let Some(obj) = self.objects.get(s) {
111 if obj.visible {
112 match &obj.object_type {
113 GOType::Circle(r) => draw_circle(
114 self.x(obj.x + (r * obj.sx)),
115 self.y(obj.y + (r * obj.sy)),
116 self.s(*r),
117 obj.color,
118 ),
119 GOType::Rect(w, h) => draw_rectangle(
120 self.x((obj.x + ((w / 2.) * obj.sx)) - (w / 2.)),
121 self.y((obj.y + ((h / 2.) * obj.sy)) - (h / 2.)),
122 self.s(*w),
123 self.s(*h),
124 obj.color,
125 ),
126 GOType::RoundedRect(w, h, r) => draw_rounded_rect(
127 self.x((obj.x + ((w / 2.) * obj.sx)) - (w / 2.)),
128 self.y((obj.y + ((h / 2.) * obj.sy)) - (h / 2.)),
129 self.s(*w),
130 self.s(*h),
131 self.s(*r),
132 obj.color,
133 ),
134 GOType::Text(t, f, s) => {
135 let c = get_text_center(&t, f.as_ref(), self.s(*s) as u16, 1.0, 0.0);
136 draw_text_ex(
137 &t,
138 (self.x(obj.x) + (c.x * obj.sx)) - c.x,
139 (self.y(obj.y) + (c.y * obj.sy)) - c.y,
140 TextParams {
141 font: f.as_ref(),
142 font_size: self.s(*s) as u16,
143 color: obj.color,
144 ..Default::default()
145 },
146 );
147 }
148 GOType::Texture(t, w, h) => {
149 draw_texture_ex(t,
150 self.x((obj.x + ((w / 2.) * obj.sx)) - (w / 2.)),
151 self.y((obj.y + ((h / 2.) * obj.sy)) - (h / 2.)),
152 obj.color,
153 DrawTextureParams {
154 dest_size: Some(Vec2 { x: self.s(*w), y: self.s(*h) }),
155 ..Default::default()
156 });
157 }
158 }
159 }
160 }
161 }
162 }
163
164 pub fn is_touch_pressed(&self, name: &str) -> Option<Vec2> {
165 for (_, (obj_name, position, phase)) in &self.touched {
166 if obj_name == name && *phase == TouchPhase::Started {
167 println!("preess {}", obj_name);
168 return Some(*position);
169 }
170 }
171 None
172 }
173
174 pub fn is_touch_released(&mut self, name: &str) -> bool {
175 for (_, (obj_name, _, phase)) in &self.touched {
176 if obj_name == name && *phase == TouchPhase::Ended {
177 return true;
178 }
179 }
180 false
181 }
182
183 pub fn is_touch_down(&self, name: &str) -> Option<Vec2> {
184 for (_, (obj_name, position, phase)) in &self.touched {
185 if obj_name == name && (*phase == TouchPhase::Moved || *phase == TouchPhase::Stationary)
186 {
187 return Some(*position);
188 }
189 }
190 None
191 }
192
193 pub fn anim(&mut self, name: &str, curve: f32, x: f32, y: f32, time: f64) {
194 if let Some(obj) = self.objects.get_mut(name) {
195 if obj.x != x || obj.y != y {
196 obj.anim = true;
197 obj.anim_curve = curve;
198 obj.anim_start = vec2(obj.x, obj.y);
199 obj.anim_end = vec2(x - obj.anim_start.x, y - obj.anim_start.y);
200 obj.anim_time_start = get_time();
201 obj.anim_time_end = time;
202 }
203 }
204 }
205
206 pub fn add(&mut self, name: &str, obj: GObject) {
207 self.objects.insert(name.to_string(), obj);
208 self.sorted_objects.push(name.to_string());
209
210 self.go_sort();
211
212 if let Some(objs) = self.objects.get_mut(name) {
213 objs.z = self.object_z;
214 self.object_z += 0.001;
215 }
216 }
217
218 pub fn del(&mut self, name: &str) {
219 self.objects.remove(name);
220 self.sorted_objects.retain(|obj_name| obj_name != name);
221 }
222
223 fn in_touch(&mut self, touch_id: u64, x: f32, y: f32) {
224 for s in self.sorted_objects.iter().rev() {
225 if let Some(obj) = self.objects.get(s) {
226 if obj.visible {
227 if match &obj.object_type {
228 GOType::Circle(r) => {
229 ((x - self.x(obj.x + (r * obj.sx))).powi(2)
230 + (y - self.y(obj.y + (r * obj.sy))).powi(2))
231 .sqrt()
232 < self.s(*r)
233 }
234 GOType::Rect(w, h) => {
235 (x - self.x(obj.x + ((w / 2.) * obj.sx))).abs() < self.s(w / 2.)
236 && (y - self.y(obj.y + ((h / 2.) * obj.sy))).abs() < self.s(h / 2.)
237 }
238 GOType::RoundedRect(w, h, _) => {
239 (x - self.x(obj.x + ((w / 2.) * obj.sx))).abs() < self.s(w / 2.)
240 && (y - self.y(obj.y + ((h / 2.) * obj.sy))).abs() < self.s(h / 2.)
241 }
242 GOType::Text(t, f, s) => {
243 let c = get_text_center(&t, f.as_ref(), self.s(*s) as u16, 1.0, 0.0);
244 (x - (self.x(obj.x) + (c.x * obj.sx))).abs() < c.x.abs()
245 && (y - (self.y(obj.y) + (c.y * obj.sy))).abs() < c.y.abs()
246 }
247 GOType::Texture(t, w, h) => {
248 (x - self.x(obj.x + ((w / 2.) * obj.sx))).abs() < self.s(w / 2.)
249 && (y - self.y(obj.y + ((h / 2.) * obj.sy))).abs() < self.s(h / 2.)
250 }
251 } {
252 self.touched
253 .insert(touch_id, (s.to_string(), vec2(x, y), TouchPhase::Started));
254 break;
255 }
256 }
257 }
258 }
259 }
260
261 fn go_sort(&mut self) {
262 self.sorted_objects.sort_by(|a, b| {
263 let obj_a = self.objects.get(a).unwrap(); let obj_b = self.objects.get(b).unwrap(); obj_a
266 .z
267 .partial_cmp(&obj_b.z)
268 .unwrap_or(std::cmp::Ordering::Equal)
269 });
270 }
271
272 fn x(&self, x: f32) -> f32 {
273 (self.screen_w / 2.)
274 + ((x / (self.w / 2.)) * (self.screen_w.min((self.w / self.h) * self.screen_h) / 2.))
275 }
276
277 fn y(&self, y: f32) -> f32 {
278 (self.screen_h / 2.)
279 + ((y / (self.h / 2.)) * (self.screen_h.min((self.h / self.w) * self.screen_w) / 2.))
280 }
281
282 fn s(&self, s: f32) -> f32 {
283 (s / self.w) * self.screen_w.min((self.w / self.h) * self.screen_h)
284 }
285}
286
287pub struct GObject {
288 pub object_type: GOType,
289 pub x: f32,
290 pub y: f32,
291 pub z: f32,
292 pub color: Color,
293 pub visible: bool,
294 pub sx: f32,
295 pub sy: f32,
296 pub anim: bool,
297 pub anim_curve: f32,
298 pub anim_start: Vec2,
299 pub anim_end: Vec2,
300 pub anim_time_start: f64,
301 pub anim_time_end: f64,
302}
303
304impl GObject {
305 pub fn new(gt: GOType, x: f32, y: f32) -> Self {
306 Self {
307 object_type: gt,
308 x: x,
309 y: y,
310 z: 0.,
311 color: WHITE1,
312 visible: true,
313 sx: 0.,
314 sy: 0.,
315 anim: false,
316 anim_curve: 0.,
317 anim_start: Vec2 { x: 0., y: 0. },
318 anim_end: Vec2 { x: 0., y: 0. },
319 anim_time_start: 0.,
320 anim_time_end: 0.,
321 }
322 }
323}
324
325pub enum GOType {
326 Circle(f32),
327 Rect(f32, f32),
328 RoundedRect(f32, f32, f32),
329 Text(String, Option<Font>, f32),
330 Texture(Texture2D, f32, f32),
331}
332
333#[inline(always)]
334fn curve(t: f32, tension: f32) -> f32 {
335 let t2 = t * t;
336 let t3 = t2 * t;
337
338 let h00 = 2.0 * t3 - 3.0 * t2 + 1.0;
339 let h10 = t3 - 2.0 * t2 + t;
340 let h01 = -2.0 * t3 + 3.0 * t2;
341 let h11 = t3 - t2;
342
343 let m0 = tension;
345 let m1 = tension;
346
347 h00 + h10 * m0 + h01 + h11 * m1
348}
349
350pub fn draw_rounded_rect(x: f32, y: f32, w: f32, h: f32, r: f32, color: Color) {
351 draw_rectangle(x + r, y, w - 2.0 * r, h, color);
352 draw_rectangle(x, y + r, w, h - 2.0 * r, color);
353
354 draw_circle(x + r, y + r, r, color);
355 draw_circle(x + w - r, y + r, r, color);
356 draw_circle(x + r, y + h - r, r, color);
357 draw_circle(x + w - r, y + h - r, r, color);
358}
359
360pub fn draw_rounded_line(x: f32, y: f32, x2: f32, y2: f32, r: f32, color: Color) {
361 draw_line(x, y, x2, y2, r, color);
362
363 draw_circle(x, y, r/2., color);
364 draw_circle(x2, y2, r/2., color);
365}