tgr/
lib.rs

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(); // Извлекаем объект по имени
264            let obj_b = self.objects.get(b).unwrap(); // Извлекаем объект по имени
265            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    // Начальная и конечная скорость контролируются tension
344    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}