]> git.lizzy.rs Git - nothing.git/blob - src/game/level/player/dying_rect.c
f206ffce34508b16375bcac92ec299ce7df63675
[nothing.git] / src / game / level / player / dying_rect.c
1 #include <SDL2/SDL.h>
2 #include <assert.h>
3
4 #include "dying_rect.h"
5 #include "math/rand.h"
6 #include "system/error.h"
7 #include "system/lt.h"
8
9 #define DYING_RECT_PIECE_COUNT 20
10 #define DYING_RECT_PIECE_SIZE 20.0f
11
12 typedef struct piece_t {
13     point_t position;
14     float angle;
15     float angle_velocity;
16     vec_t direction;
17     triangle_t body;
18 } piece_t;
19
20 struct dying_rect_t
21 {
22     lt_t *lt;
23
24     vec_t position;
25     vec_t size;
26     color_t color;
27     float duration;
28     float time_passed;
29     piece_t *pieces;
30 };
31
32 dying_rect_t *create_dying_rect(rect_t rect,
33                                 color_t color,
34                                 float duration)
35 {
36     lt_t *lt = create_lt();
37     if (lt == NULL) {
38         return NULL;
39     }
40
41     dying_rect_t *dying_rect = PUSH_LT(lt, malloc(sizeof(dying_rect_t)), free);
42     if (dying_rect == NULL) {
43         throw_error(ERROR_TYPE_LIBC);
44         RETURN_LT(lt, NULL);
45     }
46
47     dying_rect->lt = lt;
48     dying_rect->position = vec(rect.x, rect.y);
49     dying_rect->size = vec(rect.w, rect.h);
50     dying_rect->color = color;
51     dying_rect->duration = duration;
52     dying_rect->time_passed = 0;
53
54     dying_rect->pieces = PUSH_LT(lt, malloc(sizeof(piece_t) * DYING_RECT_PIECE_COUNT), free);
55     if (dying_rect->pieces == NULL) {
56         throw_error(ERROR_TYPE_LIBC);
57         RETURN_LT(lt, NULL);
58     }
59
60     for (size_t i = 0; i < DYING_RECT_PIECE_COUNT; ++i) {
61         dying_rect->pieces[i].position = dying_rect->position;
62         dying_rect->pieces[i].angle = rand_float(2 * PI);
63         dying_rect->pieces[i].angle_velocity = rand_float(8.0f);
64         dying_rect->pieces[i].body = random_triangle(DYING_RECT_PIECE_SIZE);
65         dying_rect->pieces[i].direction = vec_from_polar(
66             rand_float_range(-PI, 0.0f),
67             rand_float_range(100.0f, 300.0f));
68     }
69
70     return dying_rect;
71 }
72
73 void destroy_dying_rect(dying_rect_t *dying_rect)
74 {
75     assert(dying_rect);
76     RETURN_LT0(dying_rect->lt);
77 }
78
79 /* TODO(#109): Dying Rect animation is too boring */
80 int dying_rect_render(const dying_rect_t *dying_rect,
81                       const camera_t *camera)
82 {
83     assert(dying_rect);
84     assert(camera);
85
86     for (size_t i = 0; i < DYING_RECT_PIECE_COUNT; ++i) {
87         color_t color = dying_rect->color;
88         color.a = fminf(1.0f, 4.0f - (float) dying_rect->time_passed / (float) dying_rect->duration * 4.0f);
89
90         if (camera_fill_triangle(
91                 camera,
92                 triangle_mat3x3_product(
93                     dying_rect->pieces[i].body,
94                     mat3x3_product(
95                         trans_mat(dying_rect->pieces[i].position.x,
96                                   dying_rect->pieces[i].position.y),
97                         rot_mat(dying_rect->pieces[i].angle))),
98                 color) < 0) {
99             return -1;
100         }
101     }
102
103     return 0;
104 }
105
106 int dying_rect_update(dying_rect_t *dying_rect,
107                       float delta_time)
108 {
109     assert(dying_rect);
110     assert(delta_time > 0.0f);
111
112     if (dying_rect_is_dead(dying_rect)) {
113         return 0;
114     }
115
116     dying_rect->time_passed = dying_rect->time_passed + delta_time;
117
118     for (size_t i = 0; i < DYING_RECT_PIECE_COUNT; ++i) {
119         vec_add(
120             &dying_rect->pieces[i].position,
121             vec_scala_mult(
122                 dying_rect->pieces[i].direction,
123                 delta_time));
124         dying_rect->pieces[i].angle = fmodf(
125             dying_rect->pieces[i].angle + dying_rect->pieces[i].angle_velocity * delta_time,
126             2.0f * PI);
127     }
128
129     return 0;
130 }
131
132 int dying_rect_is_dead(const dying_rect_t *dying_rect)
133 {
134     assert(dying_rect);
135     return dying_rect->time_passed >= dying_rect->duration;
136 }