A game engine for top-down 2D RPG games.
rpg
game-engine
raylib
c99
1#include "keraforge/actor.h"
2#include <keraforge.h>
3#include <raylib.h>
4
5
6u64 kf_frame = 0;
7f64 kf_s = 0;
8f32 kf_dtms = 0;
9f32 kf_dts = 0;
10struct kf_window kf_window = {0};
11
12
13int kf_measuretext(int size, char *text)
14{
15 return MeasureTextEx(kf_window.font, text, size, 2).x;
16}
17
18void kf_drawtext(Color c, int x, int y, int size, char *text)
19{
20 DrawTextEx(kf_window.font, text, (Vector2){x, y}, size, 2, c);
21}
22
23void kf_drawtextshadowed(Color c, int x, int y, int size, char *text)
24{
25 kf_drawtext(BLACK, x+1, y+1, size, text);
26 kf_drawtext(c, x, y, size, text);
27}
28
29
30void kf_openwindow(char *title)
31{
32 kf_window.target_fps = 60;
33
34 SetTraceLogLevel(LOG_WARNING);
35 InitWindow(800, 600, title);
36 SetTargetFPS(kf_window.target_fps);
37 SetExitKey(KEY_NULL);
38
39 kf_window.font = GetFontDefault();
40 kf_window.fontsize = 20;
41
42 kf_loaddefaultbinds();
43 kf_ui_init();
44
45 struct kf_state *state = NULL;
46 int is_new_state = kf_state_load(&state);
47 (void)is_new_state;
48 kf_window.state = state;
49
50 struct kf_world *world = NULL;
51 kf_timeit("load world", kf_world_load(&world, true, NULL));
52 kf_window.room = world;
53
54 int idplayer = kf_actor_register("player");
55 kf_actorregistry.serialize[idplayer] = kf_player_serialize;
56 kf_actorregistry.deserialize[idplayer] = kf_player_deserialize;
57 kf_actorregistry.sprite[idplayer] = kf_actor_loadspritesheet("data/res/img/char/template.png");
58 kf_actorregistry.tick[idplayer] = kf_player_tick;
59 kf_actorregistry.draw[idplayer] = kf_player_draw;
60
61 int idplayer2 = kf_actor_register("player2");
62 kf_actorregistry.serialize[idplayer2] = kf_player_serialize;
63 kf_actorregistry.deserialize[idplayer2] = kf_player_deserialize;
64 kf_actorregistry.sprite[idplayer2] = kf_actor_loadspritesheet("data/res/img/char/whom.png");
65 kf_actorregistry.tick[idplayer2] = kf_player_tick;
66 kf_actorregistry.draw[idplayer2] = kf_player_draw;
67
68 if (!kf_exists("data/actors.bin"))
69 {
70 struct kf_actor *player = kf_actor_new("player");
71 player->controlled = true;
72 player->pos.x = world->width * KF_TILE_SIZE_PX / 2.0f;
73 player->pos.y = world->width * KF_TILE_SIZE_PX / 2.0f;
74
75 struct kf_actor *player2 = kf_actor_new("player2");
76 player2->pos.x = world->width * KF_TILE_SIZE_PX / 2.0f;
77 player2->pos.y = (world->width * KF_TILE_SIZE_PX / 2.0f) - 32;
78
79 kf_timeit("save actors", kf_saveactors());
80 }
81 else
82 {
83 kf_timeit("load actors", kf_loadactors());
84 }
85
86 kf_window.player = kf_actors; /* player should always be the first actor. */
87
88 kf_window.cam.target.x = kf_window.player->pos.x + (kf_window.player->size.x / 2);
89 kf_window.cam.target.y = kf_window.player->pos.y + (kf_window.player->size.y / 2);
90 kf_window.cam.zoom = 2;
91
92 kf_setmodal(&kf_modal_play);
93}
94
95void kf_startwindow(void)
96{
97 kf_window.running = 1;
98 kf_window.cam.offset.x = GetScreenWidth() / 2.0f;
99 kf_window.cam.offset.y = GetScreenHeight() / 2.0f;
100
101 while (!WindowShouldClose() && kf_window.running)
102 {
103 if (IsWindowResized())
104 {
105 kf_window.cam.offset.x = GetScreenWidth() / 2.0f;
106 kf_window.cam.offset.y = GetScreenHeight() / 2.0f;
107 }
108
109 if (kf_window.modal && kf_window.modal->render_world)
110 kf_window.modal->update();
111 if (kf_window.menu && kf_window.menu->render_world)
112 kf_window.menu->update();
113
114 BeginDrawing();
115 ClearBackground(BLACK);
116 {
117 BeginMode2D(kf_window.cam);
118 {
119 if (kf_window.modal && kf_window.modal->render_world)
120 kf_window.modal->render_world();
121 if (kf_window.menu && kf_window.menu->render_world)
122 kf_window.menu->render_world();
123 }
124 EndMode2D();
125
126 if (kf_window.modal && kf_window.modal->render_ui)
127 kf_window.modal->render_ui();
128 if (kf_window.menu && kf_window.menu->render_ui)
129 kf_window.menu->render_ui();
130 }
131 EndDrawing();
132
133 kf_frame++;
134 kf_dts = GetFrameTime();
135 kf_dtms = kf_dts * 1000;
136 kf_s += kf_dts;
137 }
138
139 kf_setmenu(NULL);
140 kf_setmodal(NULL);
141
142 kf_saveactors();
143
144 kf_state_save(kf_window.state);
145
146 free(kf_window.player);
147 free(kf_window.state);
148 free(kf_window.room);
149
150 CloseWindow();
151}
152
153void kf_closewindow(void)
154{
155 kf_window.running = false;
156}
157
158void kf_settargetfps(int fps)
159{
160 SetTargetFPS(kf_window.target_fps = fps);
161}
162
163void kf_setmodal(struct kf_modal *modal)
164{
165 if (kf_window.modal && kf_window.modal->exit)
166 {
167 kf_window.modal->exit();
168 kf_window.modal->exit = NULL;
169 }
170 kf_window.modal = modal;
171 if (kf_window.modal && kf_window.modal->init)
172 kf_window.modal->init();
173}
174
175void kf_setmenu(struct kf_modal *menu)
176{
177 if (kf_window.menu && kf_window.menu->exit)
178 {
179 kf_window.menu->exit();
180 kf_window.menu->exit = NULL;
181 }
182 kf_window.menu = menu;
183 if (kf_window.menu && kf_window.menu->init)
184 kf_window.menu->init();
185}
186
187static
188void _kf_modal_play_update(void)
189{
190 // kf_window.player->tick(kf_window.player);
191 for (struct kf_actor *actor = kf_actors ; actor != NULL ; actor = actor->next)
192 kf_actorregistry.tick[actor->id](actor);
193
194 Vector2 v = GetScreenToWorld2D(GetMousePosition(), kf_window.cam);
195 kf_window.select.x = v.x / KF_TILE_SIZE_PX;
196 kf_window.select.y = v.y / KF_TILE_SIZE_PX;
197
198 if (kf_checkinputpress(kf_inputbind_cancel) && kf_window.menu == NULL)
199 kf_window.running = 0;
200 else if (kf_checkinputpress(kf_inputbind_zoom_reset))
201 kf_window.cam.zoom = 2;
202 else if (kf_checkinputpress(kf_inputbind_zoom_in) && kf_window.cam.zoom < 3.50f)
203 kf_window.cam.zoom += 0.25f;
204 else if (kf_checkinputpress(kf_inputbind_zoom_out) && kf_window.cam.zoom > 1.00f)
205 kf_window.cam.zoom -= 0.25f;
206 else if (kf_checkinputpress(kf_inputbind_toggle_fps_limit))
207 kf_settargetfps(kf_window.target_fps != 60 ? 60 : 0);
208 else if (kf_checkinputpress(kf_inputbind_toggle_editor))
209 {
210 if (kf_window.modal == &kf_modal_edit)
211 kf_setmodal(&kf_modal_play);
212 else
213 kf_setmodal(&kf_modal_edit);
214 }
215}
216
217static
218void _kf_modal_play_render_world(void)
219{
220 kf_world_draw(kf_window.room, kf_window.cam);
221 // kf_world_drawcolliders(world, player, cam);
222 // kf_window.player->draw(kf_window.player);
223 for (struct kf_actor *actor = kf_actors ; actor != NULL ; actor = actor->next)
224 kf_actorregistry.draw[actor->id](actor);
225}
226
227static
228void _kf_modal_play_render_ui(void)
229{
230 const int dy = kf_window.fontsize + 4;
231 int y = -dy + 4; /* start at -dy so that the FPS starts at 0,0. */
232 y += 8; /* add a bit of padding */
233 int x = 8;
234
235 const Color d = GRAY; /* default colour */
236 Color c = d;
237
238 /* "curry" some arguments */
239# define line(FMT, ...) \
240 do \
241 { \
242 char *t = (char *)TextFormat(FMT __VA_OPT__(,) __VA_ARGS__); \
243 kf_drawtextshadowed(c, x, y+=dy, kf_window.fontsize, t); \
244 } \
245 while (0)
246
247 line("--time--");
248 c = GetFPS() >= kf_window.target_fps ? GREEN : RED;
249 line("fps: %d", GetFPS());
250 line("dts: %f", kf_dts);
251 c = d;
252 line("sec: %f", kf_s);
253
254 line("--modals--");
255 c = kf_window.modal ? ORANGE : d;
256 line("mode: %s", kf_window.modal ? kf_window.modal->name : "n/a");
257 c = kf_window.menu ? ORANGE : d;
258 line("menu: %s", kf_window.menu ? kf_window.menu->name : "n/a");
259
260# undef line
261}
262
263struct kf_modal kf_modal_play = {
264 .name = "play",
265 .update = _kf_modal_play_update,
266 .render_world = _kf_modal_play_render_world,
267 .render_ui = _kf_modal_play_render_ui,
268};