diff --git a/src/config.h b/src/config.h index 871621cb..97f1ecda 100644 --- a/src/config.h +++ b/src/config.h @@ -30,7 +30,7 @@ #define PIXELS_PER_UNIT 256.0 #define GAME_FPS 50.0 -#define GAME_TIMESCALE 1.0 +#define GAME_TIMESCALE 1 /* How many ticks back in time should the user blend between? * = * diff --git a/src/entity.h b/src/entity.h index 5cde6981..cb74b9ec 100644 --- a/src/entity.h +++ b/src/entity.h @@ -113,10 +113,11 @@ struct entity { struct entity_handle equipped; /* ====================================================================== */ - /* Weapon */ + /* Triggers */ - /* ENTITY_PROP_WEAPON */ - f32 fire_rate; + /* ENTITY_PROP_TRIGGERED_THIS_TICK */ + f32 trigger_delay; /* Minimum time between triggers */ + f32 last_triggered; /* ====================================================================== */ /* Testing */ diff --git a/src/game.c b/src/game.c index 5ea0ae18..169bbdc4 100644 --- a/src/game.c +++ b/src/game.c @@ -15,6 +15,8 @@ GLOBAL struct { struct atomic_i32 game_thread_shutdown; struct sys_thread game_thread; + b32 paused; + /* Game thread input */ struct sys_mutex game_cmds_mutex; struct arena game_cmds_arena; @@ -101,7 +103,7 @@ INTERNAL struct game_cmd_array pop_cmds(struct arena *arena) INTERNAL void spawn_test_entities(void) { - /* Player ent */ + /* Player */ struct entity *player_ent; { struct v2 pos = V2(1, 1); @@ -109,8 +111,11 @@ INTERNAL void spawn_test_entities(void) f32 r = 0; struct entity *e = entity_alloc_top(G.tick.entity_store); - entity_set_xform(e, XFORM_TRS(.t = pos, .r = r, .s = size)); + struct xform xf = XFORM_TRS(.t = pos, .r = r, .s = size); + entity_set_xform(e, xf); + + entity_enable_prop(e, ENTITY_PROP_ANIMATING); e->sprite = sprite_tag_from_path(STR("res/graphics/tim.ase")); e->sprite_span_name = STR("idle.unarmed"); //e->sprite_span_name = STR("idle.one_handed"); @@ -121,33 +126,32 @@ INTERNAL void spawn_test_entities(void) e->player_acceleration = 20.0f; e->control.focus = V2(0, -1); - entity_enable_prop(e, ENTITY_PROP_ANIMATING); - player_ent = e; //entity_enable_prop(e, ENTITY_PROP_TEST); } - /* Child 1 */ + /* Weapon */ { struct v2 pos = V2(1, 0); struct v2 size = V2(1, 1); f32 r = PI / 4; - struct xform xf = XFORM_TRS(.t = pos, .r = r, .s = size); - struct entity *e = entity_alloc_top(G.tick.entity_store); + + struct xform xf = XFORM_TRS(.t = pos, .r = r, .s = size); entity_set_local_xform(e, xf); + entity_enable_prop(e, ENTITY_PROP_ANIMATING); e->sprite = sprite_tag_from_path(STR("res/graphics/gun.ase")); - entity_enable_prop(e, ENTITY_PROP_ANIMATING); entity_enable_prop(e, ENTITY_PROP_WEAPON); + e->trigger_delay = 1.0 / 10.0; player_ent->equipped = e->handle; } - /* Camera ent */ + /* Camera */ { struct entity *e = entity_alloc_top(G.tick.entity_store); entity_set_xform(e, XFORM_IDENT); @@ -179,7 +183,7 @@ INTERNAL void publish_game_tick(void) sys_mutex_unlock(&lock); } -INTERNAL void game_update(void) +INTERNAL void game_update(struct game_cmd_array game_cmds) { __prof; @@ -194,7 +198,7 @@ INTERNAL void game_update(void) G.tick.dt = max_f64(0.0, (1.0 / GAME_FPS) * G.tick.timescale); G.tick.time += G.tick.dt; - struct game_cmd_array game_cmds = pop_cmds(scratch.arena); + f64 time = G.tick.time; struct entity_store *store = G.tick.entity_store; struct entity *root = entity_from_handle(store, store->root); struct sprite_scope *sprite_frame_scope = sprite_scope_begin(); @@ -367,7 +371,7 @@ INTERNAL void game_update(void) ent->test_start_sprite_xform = ent->sprite_local_xform; } - f32 t = ((f32)G.tick.time); + f32 t = (f32)time; struct v2 og = v2_mul(V2(math_cos(t), math_sin(t)), 3); f32 r = t * 3; struct v2 s = V2(1 + (math_fabs(math_sin(t * 5)) * 3), 1); @@ -406,17 +410,23 @@ INTERNAL void game_update(void) } /* ========================== * - * Fire weapons + * Fire triggers * ========================== */ for (u64 entity_index = 0; entity_index < store->count; ++entity_index) { struct entity *ent = &store->entities[entity_index]; if (!ent->valid) continue; + if (!entity_has_prop(ent, ENTITY_PROP_TRIGGERED_THIS_TICK)) continue; + if ((time - ent->last_triggered < ent->trigger_delay) && ent->last_triggered != 0) continue; + ent->last_triggered = time; + + /* Fire weapon */ if (entity_has_prop(ent, ENTITY_PROP_WEAPON)) { - if (entity_has_prop(ent, ENTITY_PROP_TRIGGERED_THIS_TICK)) { - ent->sprite_tint = RGBA_32_F(1, 0, 0, 1); - } + f32 r = 1.0f * ((f32)sys_rand_u32() / U32_MAX); + f32 g = 1.0f * ((f32)sys_rand_u32() / U32_MAX); + f32 b = 1.0f * ((f32)sys_rand_u32() / U32_MAX); + ent->sprite_tint = RGBA_32_F(r, g, b, 1); } } @@ -661,15 +671,32 @@ INTERNAL void game_update(void) INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(game_thread_entry_point, arg) { + struct temp_arena scratch = scratch_begin_no_conflict(); + (UNUSED)arg; sys_timestamp_t last_frame_ts = 0; f64 target_dt = GAME_FPS > (0) ? (1.0 / GAME_FPS) : 0; while (!atomic_i32_eval(&G.game_thread_shutdown)) { __profscope(game_update_w_sleep); + struct temp_arena temp = arena_temp_begin(scratch.arena); sleep_frame(last_frame_ts, target_dt); last_frame_ts = sys_timestamp(); - game_update(); + { + struct game_cmd_array game_cmds = pop_cmds(temp.arena); + if (!G.paused) { + game_update(game_cmds); + } + /* Check for pause cmd */ + for (u64 i = 0; i < game_cmds.count; ++i) { + if (game_cmds.cmds[i].kind == GAME_CMD_KIND_PAUSE) { + G.paused = !G.paused; + } + } + } + arena_temp_end(temp); } + + scratch_end(scratch); } /* ========================== * diff --git a/src/game.h b/src/game.h index 32a8e374..44e2d70d 100644 --- a/src/game.h +++ b/src/game.h @@ -21,6 +21,7 @@ enum game_cmd_kind { /* Testing */ GAME_CMD_KIND_CLEAR_ALL, GAME_CMD_KIND_SPAWN_TEST, + GAME_CMD_KIND_PAUSE, GAME_CMD_KIND_COUNT }; diff --git a/src/user.c b/src/user.c index b7f284cd..361bca22 100644 --- a/src/user.c +++ b/src/user.c @@ -86,8 +86,9 @@ GLOBAL READONLY enum user_bind_kind g_binds[SYS_BTN_COUNT] = { [SYS_BTN_C] = USER_BIND_KIND_DEBUG_CLEAR, [SYS_BTN_V] = USER_BIND_KIND_DEBUG_SPAWN, - [SYS_BTN_F6] = USER_BIND_KIND_DEBUG_DRAW, - [SYS_BTN_F7] = USER_BIND_KIND_DEBUG_CAMERA, + [SYS_BTN_F1] = USER_BIND_KIND_DEBUG_PAUSE, + [SYS_BTN_F2] = USER_BIND_KIND_DEBUG_CAMERA, + [SYS_BTN_F3] = USER_BIND_KIND_DEBUG_DRAW, [SYS_BTN_F11] = USER_BIND_KIND_FULLSCREEN, [SYS_BTN_MWHEELUP] = USER_BIND_KIND_ZOOM_IN, [SYS_BTN_MWHEELDOWN] = USER_BIND_KIND_ZOOM_OUT, @@ -575,6 +576,16 @@ INTERNAL void user_update(void) } } + /* Test pause */ + { + struct bind_state state = G.bind_states[USER_BIND_KIND_DEBUG_PAUSE]; + if (state.num_presses) { + queue_game_cmd(&cmd_list, (struct game_cmd) { + .kind = GAME_CMD_KIND_PAUSE + }); + } + } + /* Test spawn */ { struct bind_state state = G.bind_states[USER_BIND_KIND_DEBUG_SPAWN]; @@ -766,9 +777,10 @@ INTERNAL void user_update(void) if (!ent->valid) continue; if (ent->is_root) continue; + struct sprite_tag sprite = ent->sprite; + /* Skip undrawable entities */ - if (sprite_tag_is_nil(ent->sprite) - && !entity_has_prop(ent, ENTITY_PROP_CAMERA)) { + if (sprite_tag_is_nil(sprite) && !entity_has_prop(ent, ENTITY_PROP_CAMERA)) { continue; } @@ -783,13 +795,12 @@ INTERNAL void user_update(void) struct xform sprite_xform = xf; /* Draw sprite */ - if (!sprite_tag_is_nil(ent->sprite)) { + if (!sprite_tag_is_nil(sprite)) { /* Calculate sprite xform */ sprite_xform = xform_mul(xf, ent->sprite_local_xform); /* Async load */ - struct sprite_tag sprite = ent->sprite; struct sprite_sheet *sheet = sprite_sheet_from_tag_async(sprite_frame_scope, sprite); struct sprite_texture *texture = sprite_texture_from_tag_async(sprite_frame_scope, sprite); (UNUSED)texture; @@ -863,7 +874,6 @@ INTERNAL void user_update(void) /* Draw slices */ if (!sprite_tag_is_nil(ent->sprite)) { - struct sprite_tag sprite = ent->sprite; struct sprite_sheet *sheet = sprite_sheet_from_tag_async(sprite_frame_scope, sprite); for (u64 i = 0; i < sheet->slice_groups_count; ++i) { @@ -1018,6 +1028,9 @@ INTERNAL void user_update(void) draw_text(G.viewport_canvas, font, pos, string_format(temp.arena, STR("time: %F"), FMT_FLOAT((f64)G.time))); pos.y += spacing; + draw_text(G.viewport_canvas, font, pos, string_format(temp.arena, STR("world time: %F"), FMT_FLOAT((f64)G.world.time))); + pos.y += spacing; + draw_text(G.viewport_canvas, font, pos, string_format(temp.arena, STR("screen_size: (%F, %F)"), FMT_FLOAT((f64)G.screen_size.x), FMT_FLOAT((f64)G.screen_size.y))); pos.y += spacing; diff --git a/src/user.h b/src/user.h index bfe94d37..ffae5355 100644 --- a/src/user.h +++ b/src/user.h @@ -26,6 +26,7 @@ enum user_bind_kind { USER_BIND_KIND_DEBUG_SPAWN, USER_BIND_KIND_DEBUG_DRAW, USER_BIND_KIND_DEBUG_CAMERA, + USER_BIND_KIND_DEBUG_PAUSE, USER_BIND_KIND_FULLSCREEN, USER_BIND_KIND_ZOOM_IN, USER_BIND_KIND_ZOOM_OUT,