A game engine for top-down 2D RPG games.
rpg game-engine raylib c99

Subtiles, fix animations at high FPS

Changed files
+46 -38
include
keraforge
src
+3 -2
include/keraforge/graphics.h
··· 6 6 7 7 8 8 /* Number of frames since the game opened. 9 - You should only use this for animations! 10 - It's not consistent enough for precise timing use deltatime (kf_dts/kf_dtms) for that. */ 9 + Not consistent enough for precise timing! Use deltatime (kf_dts/kf_dtms) instead. */ 11 10 extern u64 kf_frame; 11 + /* Number of seconds since the game opened. */ 12 + extern f64 kf_s; 12 13 /* Deltatime in milliseconds */ 13 14 extern f32 kf_dtms; 14 15 /* Deltatime in seconds. */
+1
include/keraforge/world.h
··· 28 28 /* Represents a singular tile in the world. */ 29 29 struct kf_tile 30 30 { 31 + kf_tileid_t subid; 31 32 kf_tileid_t id; 32 33 kf_tiledatum_t data; 33 34 };
+1 -1
src/actor.c
··· 140 140 if (actor->vel.x != 0 || actor->vel.y != 0) 141 141 x += 7; /* walk sprites */ 142 142 143 - x += (kf_frame / 15) % 4; 143 + x += (int)(kf_s * 5) % 4; 144 144 145 145 /* todo: run and jump */ 146 146
+1
src/graphics.c
··· 2 2 3 3 4 4 u64 kf_frame = 0; 5 + f64 kf_s = 0; 5 6 f32 kf_dtms = 0; 6 7 f32 kf_dts = 0;
+23 -33
src/main.c
··· 1 + #include "keraforge/input.h" 1 2 #include <keraforge.h> 2 3 #include <raylib.h> 3 4 #include <raymath.h> ··· 8 9 static Camera2D cam; 9 10 static struct kf_vec2(u32) select = { 0, 0 }; 10 11 static int selected_tile = 0; 11 - static bool selected_menu_this_frame = false; 12 12 static enum { 13 13 menu_none, 14 14 menu_palette, 15 - menu_escape 16 15 } menu; 16 + static int target_fps = 60; 17 17 18 18 static kf_inputbind_t 19 19 inputbind_move_up, ··· 30 30 inputbind_palette, 31 31 inputbind_zoom_reset, 32 32 inputbind_zoom_in, 33 - inputbind_zoom_out 33 + inputbind_zoom_out, 34 + inputbind_toggle_fps_limit 34 35 ; 35 36 36 37 ··· 56 57 inputbind_zoom_reset = kf_addinput("zoom_reset", KEY_ZERO, KEY_NULL, MOUSE_BUTTON_UNKNOWN, GAMEPAD_BUTTON_UNKNOWN, GAMEPAD_AXIS_UNKNOWN); 57 58 inputbind_zoom_in = kf_addinput("zoom_in", KEY_EQUAL, KEY_NULL, MOUSE_BUTTON_UNKNOWN, GAMEPAD_BUTTON_UNKNOWN, GAMEPAD_AXIS_UNKNOWN); 58 59 inputbind_zoom_out = kf_addinput("zoom_out", KEY_MINUS, KEY_NULL, MOUSE_BUTTON_UNKNOWN, GAMEPAD_BUTTON_UNKNOWN, GAMEPAD_AXIS_UNKNOWN); 60 + 61 + inputbind_toggle_fps_limit = kf_addinput("toggle_fps_limit", KEY_NINE, KEY_NULL, MOUSE_BUTTON_UNKNOWN, GAMEPAD_BUTTON_UNKNOWN, GAMEPAD_AXIS_UNKNOWN); 59 62 } 60 63 61 64 static 62 65 void setmenu(int m) 63 66 { 64 67 menu = m; 65 - selected_menu_this_frame = true; 66 68 } 67 69 68 70 static ··· 140 142 141 143 // SetTraceLogLevel(LOG_WARNING); 142 144 InitWindow(800, 600, "Keraforge"); 143 - SetTargetFPS(60); 145 + SetTargetFPS(target_fps); 144 146 SetExitKey(KEY_NULL); 145 147 146 148 loadbinds(); ··· 186 188 if (!kf_exists("data/map.bin")) 187 189 { 188 190 printf("-> creating world\n"); 189 - world = kf_world_new(128, 128, 1); 191 + world = kf_world_new(4096, 4096, 2); 190 192 printf("-> saving world\n"); 191 193 size_t len = kf_world_getsize(world); 192 194 printf("-> writing of %lu bytes\n", len); ··· 241 243 if (kf_checkinputpress(inputbind_palette)) 242 244 setmenu(menu_palette); 243 245 else if (kf_checkinputpress(inputbind_cancel) && menu == menu_none) 244 - setmenu(menu_escape); 246 + running = 0; 245 247 else if (kf_checkinputpress(inputbind_zoom_reset)) 246 248 cam.zoom = 2; 247 249 else if (kf_checkinputpress(inputbind_zoom_in) && cam.zoom < 3.50f) 248 250 cam.zoom += 0.25f; 249 251 else if (kf_checkinputpress(inputbind_zoom_out) && cam.zoom > 1.00f) 250 252 cam.zoom -= 0.25f; 253 + else if (kf_checkinputpress(inputbind_toggle_fps_limit)) 254 + { 255 + target_fps = target_fps <= 0 ? 60 : 0; 256 + SetTargetFPS(target_fps); 257 + } 251 258 252 259 BeginDrawing(); 253 260 ClearBackground(BLACK); ··· 270 277 player->draw(world, player); 271 278 EndMode2D(); 272 279 273 - if (selected_menu_this_frame) 280 + switch (menu) 274 281 { 275 - selected_menu_this_frame = false; 276 - } 277 - else 278 - { 279 - switch (menu) 280 - { 281 - case menu_none: 282 - break; 283 - case menu_palette: 284 - if (kf_ui_choice("Select tile", &kf_tiles.key[0], kf_tiles.count + 1, &selected_tile)) 285 - setmenu(menu_none); 286 - break; 287 - case menu_escape: 288 - { 289 - static int result = 1; 290 - if (kf_ui_yesno("Exit game?", &result)) 291 - { 292 - menu = menu_none; 293 - if (result) 294 - running = 0; 295 - result = 1; 296 - } 297 - break; 298 - } 299 - } 282 + case menu_none: 283 + break; 284 + case menu_palette: 285 + if (kf_ui_choice("Select tile", &kf_tiles.key[0], kf_tiles.count + 1, &selected_tile)) 286 + setmenu(menu_none); 287 + break; 300 288 } 301 289 302 290 DrawFPS(0, 0); 303 291 DrawText(TextFormat("%f", kf_dts), 0, 20, 20, RED); 292 + DrawText(TextFormat("%f", kf_s), 0, 40, 20, RED); 304 293 305 294 EndDrawing(); 306 295 307 296 kf_frame++; 308 297 kf_dts = GetFrameTime(); 309 298 kf_dtms = kf_dts * 1000; 299 + kf_s += kf_dts; 310 300 } 311 301 312 302 if (world)
-1
src/math.c
··· 1 - #include "keraforge/math.h" 2 1 #include <keraforge.h> 3 2 #include <raylib.h> 4 3 #include <raymath.h>
+16 -1
src/world.c
··· 1 - #include "keraforge/world.h" 2 1 #include <keraforge.h> 3 2 #include <raylib.h> 4 3 #include <stdio.h> ··· 40 39 world->height = height; 41 40 memset(world->map, 0, sizeof(struct kf_tile)*width*height); 42 41 for (size_t i = 0 ; i < width*height ; i++) 42 + { 43 + world->map[i].subid = fill; 43 44 world->map[i].id = fill; 45 + } 44 46 45 47 u32 x; 46 48 for (u32 y = 0 ; y < height ; y++) ··· 179 181 { 180 182 for (x = sx ; x < ex ; x++) 181 183 { 184 + KF_SANITY_CHECK(tile->subid <= kf_tiles.count, "erroneous subtile on map at %u,%u: %u (count=%u)", x, y, tile->subid, kf_tiles.count); 182 185 KF_SANITY_CHECK(tile->id <= kf_tiles.count, "erroneous tile on map at %u,%u: %u (count=%u)", x, y, tile->id, kf_tiles.count); 186 + if (tile->data != 0x1111 && tile->subid) /* 0x1111: full tile, no subtile rendering needed */ 187 + { 188 + kf_drawsprite_wh( 189 + kf_tiles.sheet[tile->subid], 190 + x*KF_TILE_SIZE_PX, 191 + y*KF_TILE_SIZE_PX, 192 + KF_TILE_SIZE_PX, 193 + KF_TILE_SIZE_PX, 194 + kf_tiles.sprite[tile->subid].x + 2, /* 2,1 are offsets for the "middle" tile */ 195 + kf_tiles.sprite[tile->subid].y + 1 196 + ); 197 + } 183 198 if (tile->id) 184 199 { 185 200 struct kf_vec2(u32) s = kf_getspritefortilebitmask(tile->data);
+1
todo
··· 11 11 . World 12 12 / Tiles 13 13 . Actors 14 + . Compression (perhaps https://github.com/google/brotli/) 14 15 . Dialogue 15 16 . Quests 16 17 . Combat