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 kf_window.state = state;
48
49 struct kf_world *world = NULL;
50 kf_world_load(&world, false);
51 kf_window.room = world;
52
53 kf_actorregistry.id[0] = "player";
54 kf_actorregistry.serialize[0] = kf_player_serialize;
55 kf_actorregistry.deserialize[0] = kf_player_deserialize;
56 kf_actorregistry.count++;
57
58 struct kf_actor *player = kf_actor_new("player", kf_actor_loadspritesheet("data/res/img/char/template.png"), 10, 10, true);
59 player->sizeoffset.y = 6;
60 player->tick = kf_player_tick;
61 player->draw = kf_player_draw;
62 player->controlled = true;
63 if (is_new_state) /* place the player in the centre of the room */
64 {
65 state->player.pos.x = world->width * KF_TILE_SIZE_PX / 2.0f;
66 state->player.pos.y = world->width * KF_TILE_SIZE_PX / 2.0f;
67 }
68 player->pos.x = state->player.pos.x;
69 player->pos.y = state->player.pos.y;
70 kf_window.player = player;
71
72 struct kf_actor *player2 = kf_actor_new("player", kf_actor_loadspritesheet("data/res/img/char/whom.png"), 10, 10, true);
73 player2->sizeoffset.y = 6;
74 player2->tick = kf_player_tick; /* when controlled is false, player_tick won't process keybinds */
75 player2->draw = kf_player_draw;
76 player2->pos.x = player->pos.x;
77 player2->pos.y = player->pos.y - 24;
78
79 kf_window.cam.target.x = player->pos.x + (player->size.x / 2);
80 kf_window.cam.target.y = player->pos.y + (player->size.y / 2);
81 kf_window.cam.zoom = 2;
82
83 kf_setmodal(&kf_modal_play);
84}
85
86void kf_startwindow(void)
87{
88 kf_window.running = 1;
89 kf_window.cam.offset.x = GetScreenWidth() / 2.0f;
90 kf_window.cam.offset.y = GetScreenHeight() / 2.0f;
91
92 while (!WindowShouldClose() && kf_window.running)
93 {
94 if (IsWindowResized())
95 {
96 kf_window.cam.offset.x = GetScreenWidth() / 2.0f;
97 kf_window.cam.offset.y = GetScreenHeight() / 2.0f;
98 }
99
100 if (kf_window.modal && kf_window.modal->render_world)
101 kf_window.modal->update();
102 if (kf_window.menu && kf_window.menu->render_world)
103 kf_window.menu->update();
104
105 BeginDrawing();
106 ClearBackground(BLACK);
107 {
108 BeginMode2D(kf_window.cam);
109 {
110 if (kf_window.modal && kf_window.modal->render_world)
111 kf_window.modal->render_world();
112 if (kf_window.menu && kf_window.menu->render_world)
113 kf_window.menu->render_world();
114 }
115 EndMode2D();
116
117 if (kf_window.modal && kf_window.modal->render_ui)
118 kf_window.modal->render_ui();
119 if (kf_window.menu && kf_window.menu->render_ui)
120 kf_window.menu->render_ui();
121 }
122 EndDrawing();
123
124 kf_frame++;
125 kf_dts = GetFrameTime();
126 kf_dtms = kf_dts * 1000;
127 kf_s += kf_dts;
128 }
129
130 kf_setmenu(NULL);
131 kf_setmodal(NULL);
132
133 kf_saveactors();
134
135 kf_window.state->player.pos = kf_window.player->pos;
136 kf_state_save(kf_window.state);
137
138 free(kf_window.player);
139 free(kf_window.state);
140 free(kf_window.room);
141
142 CloseWindow();
143}
144
145void kf_closewindow(void)
146{
147 kf_window.running = false;
148}
149
150void kf_settargetfps(int fps)
151{
152 SetTargetFPS(kf_window.target_fps = fps);
153}
154
155void kf_setmodal(struct kf_modal *modal)
156{
157 if (kf_window.modal && kf_window.modal->exit)
158 {
159 kf_window.modal->exit();
160 kf_window.modal->exit = NULL;
161 }
162 kf_window.modal = modal;
163 if (kf_window.modal && kf_window.modal->init)
164 kf_window.modal->init();
165}
166
167void kf_setmenu(struct kf_modal *menu)
168{
169 if (kf_window.menu && kf_window.menu->exit)
170 {
171 kf_window.menu->exit();
172 kf_window.menu->exit = NULL;
173 }
174 kf_window.menu = menu;
175 if (kf_window.menu && kf_window.menu->init)
176 kf_window.menu->init();
177}
178
179static
180void _kf_modal_play_update(void)
181{
182 // kf_window.player->tick(kf_window.player);
183 for (struct kf_actor *actor = kf_actors ; actor != NULL ; actor = actor->next)
184 actor->tick(actor);
185
186 Vector2 v = GetScreenToWorld2D(GetMousePosition(), kf_window.cam);
187 kf_window.select.x = v.x / KF_TILE_SIZE_PX;
188 kf_window.select.y = v.y / KF_TILE_SIZE_PX;
189
190 if (kf_checkinputpress(kf_inputbind_cancel) && kf_window.menu == NULL)
191 kf_window.running = 0;
192 else if (kf_checkinputpress(kf_inputbind_zoom_reset))
193 kf_window.cam.zoom = 2;
194 else if (kf_checkinputpress(kf_inputbind_zoom_in) && kf_window.cam.zoom < 3.50f)
195 kf_window.cam.zoom += 0.25f;
196 else if (kf_checkinputpress(kf_inputbind_zoom_out) && kf_window.cam.zoom > 1.00f)
197 kf_window.cam.zoom -= 0.25f;
198 else if (kf_checkinputpress(kf_inputbind_toggle_fps_limit))
199 kf_settargetfps(kf_window.target_fps != 60 ? 60 : 0);
200 else if (kf_checkinputpress(kf_inputbind_toggle_editor))
201 {
202 if (kf_window.modal == &kf_modal_edit)
203 kf_setmodal(&kf_modal_play);
204 else
205 kf_setmodal(&kf_modal_edit);
206 }
207}
208
209static
210void _kf_modal_play_render_world(void)
211{
212 kf_world_draw(kf_window.room, kf_window.cam);
213 // kf_world_drawcolliders(world, player, cam);
214 // kf_window.player->draw(kf_window.player);
215 for (struct kf_actor *actor = kf_actors ; actor != NULL ; actor = actor->next)
216 actor->draw(actor);
217}
218
219static
220void _kf_modal_play_render_ui(void)
221{
222 const int dy = kf_window.fontsize + 4;
223 int y = -dy + 4; /* start at -dy so that the FPS starts at 0,0. */
224 y += 8; /* add a bit of padding */
225 int x = 8;
226
227 const Color d = GRAY; /* default colour */
228 Color c = d;
229
230 /* "curry" some arguments */
231# define line(FMT, ...) \
232 do \
233 { \
234 char *t = (char *)TextFormat(FMT __VA_OPT__(,) __VA_ARGS__); \
235 kf_drawtextshadowed(c, x, y+=dy, kf_window.fontsize, t); \
236 } \
237 while (0)
238
239 line("--time--");
240 c = GetFPS() >= kf_window.target_fps ? GREEN : RED;
241 line("fps: %d", GetFPS());
242 line("dts: %f", kf_dts);
243 c = d;
244 line("sec: %f", kf_s);
245
246 line("--modals--");
247 c = kf_window.modal ? ORANGE : d;
248 line("mode: %s", kf_window.modal ? kf_window.modal->name : "n/a");
249 c = kf_window.menu ? ORANGE : d;
250 line("menu: %s", kf_window.menu ? kf_window.menu->name : "n/a");
251
252# undef line
253}
254
255struct kf_modal kf_modal_play = {
256 .name = "play",
257 .update = _kf_modal_play_update,
258 .render_world = _kf_modal_play_render_world,
259 .render_ui = _kf_modal_play_render_ui,
260};