]> git.lizzy.rs Git - nothing.git/blob - src/game/level/explosion.c
(#819) Integrate LevelEditor Regions with Level
[nothing.git] / src / game / level / explosion.c
1 #include <SDL.h>
2 #include "system/stacktrace.h"
3
4 #include "explosion.h"
5 #include "math/rand.h"
6 #include "system/lt.h"
7 #include "system/nth_alloc.h"
8
9 #define EXPLOSION_PIECE_COUNT 20
10 #define EXPLOSION_PIECE_SIZE 20.0f
11
12 typedef struct Piece {
13     Point position;
14     float angle;
15     float angle_velocity;
16     Vec direction;
17     Triangle body;
18 } Piece;
19
20 struct Explosion
21 {
22     Lt *lt;
23
24     Vec position;
25     Color color;
26     float duration;
27     float time_passed;
28     Piece *pieces;
29 };
30
31 Explosion *create_explosion(Color color,
32                             float duration)
33 {
34     Lt *lt = create_lt();
35
36     Explosion *explosion = PUSH_LT(lt, nth_calloc(1, sizeof(Explosion)), free);
37     if (explosion == NULL) {
38         RETURN_LT(lt, NULL);
39     }
40
41     explosion->lt = lt;
42     explosion->position = vec(0.0f, 0.0f);
43     explosion->color = color;
44     explosion->duration = duration;
45     explosion->time_passed = duration;
46
47     explosion->pieces = PUSH_LT(lt, nth_calloc(1, sizeof(Piece) * EXPLOSION_PIECE_COUNT), free);
48     if (explosion->pieces == NULL) {
49         RETURN_LT(lt, NULL);
50     }
51
52     return explosion;
53 }
54
55 void destroy_explosion(Explosion *explosion)
56 {
57     trace_assert(explosion);
58     RETURN_LT0(explosion->lt);
59 }
60
61 int explosion_render(const Explosion *explosion,
62                      Camera *camera)
63 {
64     trace_assert(explosion);
65     trace_assert(camera);
66
67     for (size_t i = 0; i < EXPLOSION_PIECE_COUNT; ++i) {
68         Color color = explosion->color;
69         color.a = fminf(1.0f, 4.0f - (float) explosion->time_passed / (float) explosion->duration * 4.0f);
70
71         if (camera_fill_triangle(
72                 camera,
73                 triangle_mat3x3_product(
74                     explosion->pieces[i].body,
75                     mat3x3_product(
76                         trans_mat(explosion->pieces[i].position.x,
77                                   explosion->pieces[i].position.y),
78                         rot_mat(explosion->pieces[i].angle))),
79                 color) < 0) {
80             return -1;
81         }
82     }
83
84     return 0;
85 }
86
87 int explosion_update(Explosion *explosion,
88                      float delta_time)
89 {
90     trace_assert(explosion);
91     trace_assert(delta_time > 0.0f);
92
93     if (explosion_is_done(explosion)) {
94         return 0;
95     }
96
97     explosion->time_passed = explosion->time_passed + delta_time;
98
99     for (size_t i = 0; i < EXPLOSION_PIECE_COUNT; ++i) {
100         vec_add(
101             &explosion->pieces[i].position,
102             vec_scala_mult(
103                 explosion->pieces[i].direction,
104                 delta_time));
105         explosion->pieces[i].angle = fmodf(
106             explosion->pieces[i].angle + explosion->pieces[i].angle_velocity * delta_time,
107             2.0f * PI);
108     }
109
110     return 0;
111 }
112
113 int explosion_is_done(const Explosion *explosion)
114 {
115     trace_assert(explosion);
116     return explosion->time_passed >= explosion->duration;
117 }
118
119 void explosion_start(Explosion *explosion,
120                      Vec position)
121 {
122     explosion->position = position;
123     explosion->time_passed = 0;
124
125     for (size_t i = 0; i < EXPLOSION_PIECE_COUNT; ++i) {
126         explosion->pieces[i].position = explosion->position;
127         explosion->pieces[i].angle = rand_float(2 * PI);
128         explosion->pieces[i].angle_velocity = rand_float(8.0f);
129         explosion->pieces[i].body = random_triangle(EXPLOSION_PIECE_SIZE);
130         explosion->pieces[i].direction = vec_from_polar(
131             rand_float_range(-PI, 0.0f),
132             rand_float_range(100.0f, 300.0f));
133     }
134 }