more bullet testing
This commit is contained in:
parent
bcbf9c9588
commit
45c6d94009
@ -30,7 +30,7 @@
|
|||||||
#define PIXELS_PER_UNIT 256.0
|
#define PIXELS_PER_UNIT 256.0
|
||||||
|
|
||||||
#define GAME_FPS 50.0
|
#define GAME_FPS 50.0
|
||||||
#define GAME_TIMESCALE 1
|
#define GAME_TIMESCALE 1.0
|
||||||
|
|
||||||
/* How many ticks back in time should the user blend between?
|
/* How many ticks back in time should the user blend between?
|
||||||
* <Delay ms> = <USER_INTERP_OFFSET_TICK_RATIO> * <Game tick rate>
|
* <Delay ms> = <USER_INTERP_OFFSET_TICK_RATIO> * <Game tick rate>
|
||||||
|
|||||||
15
src/entity.c
15
src/entity.c
@ -72,7 +72,8 @@ void entity_store_copy_replace(struct entity_store *dest, struct entity_store *s
|
|||||||
|
|
||||||
void entity_store_reset(struct entity_store *store)
|
void entity_store_reset(struct entity_store *store)
|
||||||
{
|
{
|
||||||
store->count = 0;
|
store->allocated = 0;
|
||||||
|
store->reserved = 0;
|
||||||
store->first_free = entity_nil_handle();
|
store->first_free = entity_nil_handle();
|
||||||
arena_pop_to(&store->arena, STORE_ENTITIES_OFFSET);
|
arena_pop_to(&store->arena, STORE_ENTITIES_OFFSET);
|
||||||
store_make_root(store);
|
store_make_root(store);
|
||||||
@ -87,7 +88,7 @@ INTERNAL struct entity *entity_alloc_internal(struct entity_store *store)
|
|||||||
struct entity *entity = NULL;
|
struct entity *entity = NULL;
|
||||||
struct entity_handle handle = { 0 };
|
struct entity_handle handle = { 0 };
|
||||||
if (store->first_free.gen) {
|
if (store->first_free.gen) {
|
||||||
/* Reuse from free list */
|
/* Reuse from free list */;
|
||||||
entity = entity_from_handle(store, store->first_free);
|
entity = entity_from_handle(store, store->first_free);
|
||||||
handle = entity->handle;
|
handle = entity->handle;
|
||||||
++handle.gen;
|
++handle.gen;
|
||||||
@ -95,10 +96,11 @@ INTERNAL struct entity *entity_alloc_internal(struct entity_store *store)
|
|||||||
} else {
|
} else {
|
||||||
/* Make new */
|
/* Make new */
|
||||||
entity = arena_push(&store->arena, struct entity);
|
entity = arena_push(&store->arena, struct entity);
|
||||||
handle = (struct entity_handle) { .gen = 1, .idx = store->count++ };
|
handle = (struct entity_handle) { .gen = 1, .idx = store->reserved++ };
|
||||||
}
|
}
|
||||||
*entity = g_entity_default;
|
*entity = g_entity_default;
|
||||||
entity->handle = handle;
|
entity->handle = handle;
|
||||||
|
++store->allocated;
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,6 +127,7 @@ INTERNAL void entity_release_internal(struct entity_store *store, struct entity
|
|||||||
ent->valid = false;
|
ent->valid = false;
|
||||||
ent->next_free = store->first_free;
|
ent->next_free = store->first_free;
|
||||||
store->first_free = ent->handle;
|
store->first_free = ent->handle;
|
||||||
|
--store->allocated;
|
||||||
}
|
}
|
||||||
|
|
||||||
void entity_release(struct entity_store *store, struct entity *ent)
|
void entity_release(struct entity_store *store, struct entity *ent)
|
||||||
@ -152,7 +155,7 @@ struct entity_store *entity_get_store(struct entity *ent)
|
|||||||
/* Returns a valid entity or read-only nil entity. Always safe to read result, need to check `valid` to write. */
|
/* Returns a valid entity or read-only nil entity. Always safe to read result, need to check `valid` to write. */
|
||||||
struct entity *entity_from_handle(struct entity_store *store, struct entity_handle handle)
|
struct entity *entity_from_handle(struct entity_store *store, struct entity_handle handle)
|
||||||
{
|
{
|
||||||
if (handle.gen != 0 && handle.idx < store->count) {
|
if (handle.gen != 0 && handle.idx < store->reserved) {
|
||||||
struct entity *entity = &store->entities[handle.idx];
|
struct entity *entity = &store->entities[handle.idx];
|
||||||
if (entity->handle.gen == handle.gen) {
|
if (entity->handle.gen == handle.gen) {
|
||||||
return entity;
|
return entity;
|
||||||
@ -163,7 +166,7 @@ struct entity *entity_from_handle(struct entity_store *store, struct entity_hand
|
|||||||
|
|
||||||
struct entity *entity_find_first_match_one(struct entity_store *store, enum entity_prop prop)
|
struct entity *entity_find_first_match_one(struct entity_store *store, enum entity_prop prop)
|
||||||
{
|
{
|
||||||
u64 count = store->count;
|
u64 count = store->reserved;
|
||||||
struct entity *entities = store->entities;
|
struct entity *entities = store->entities;
|
||||||
for (u64 entity_index = 0; entity_index < count; ++entity_index) {
|
for (u64 entity_index = 0; entity_index < count; ++entity_index) {
|
||||||
struct entity *ent = &entities[entity_index];
|
struct entity *ent = &entities[entity_index];
|
||||||
@ -176,7 +179,7 @@ struct entity *entity_find_first_match_one(struct entity_store *store, enum enti
|
|||||||
|
|
||||||
struct entity *entity_find_first_match_all(struct entity_store *store, struct entity_prop_array props)
|
struct entity *entity_find_first_match_all(struct entity_store *store, struct entity_prop_array props)
|
||||||
{
|
{
|
||||||
u64 count = store->count;
|
u64 count = store->reserved;
|
||||||
struct entity *entities = store->entities;
|
struct entity *entities = store->entities;
|
||||||
for (u64 entity_index = 0; entity_index < count; ++entity_index) {
|
for (u64 entity_index = 0; entity_index < count; ++entity_index) {
|
||||||
struct entity *ent = &entities[entity_index];
|
struct entity *ent = &entities[entity_index];
|
||||||
|
|||||||
@ -34,7 +34,8 @@ struct entity_handle {
|
|||||||
|
|
||||||
struct entity_store {
|
struct entity_store {
|
||||||
struct arena arena;
|
struct arena arena;
|
||||||
u64 count;
|
u64 allocated;
|
||||||
|
u64 reserved;
|
||||||
struct entity_handle first_free;
|
struct entity_handle first_free;
|
||||||
struct entity_handle root;
|
struct entity_handle root;
|
||||||
struct entity *entities;
|
struct entity *entities;
|
||||||
|
|||||||
207
src/game.c
207
src/game.c
@ -247,10 +247,40 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Update sprite from animation
|
* Activate entities
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
for (u64 entity_index = 0; entity_index < store->count; ++entity_index) {
|
for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) {
|
||||||
|
struct entity *ent = &store->entities[entity_index];
|
||||||
|
if (!ent->valid) continue;
|
||||||
|
|
||||||
|
if (!entity_has_prop(ent, ENTITY_PROP_ACTIVE)) {
|
||||||
|
entity_enable_prop(ent, ENTITY_PROP_ACTIVE);
|
||||||
|
++ent->continuity_gen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Reset triggered entities
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) {
|
||||||
|
struct entity *ent = &store->entities[entity_index];
|
||||||
|
if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue;
|
||||||
|
|
||||||
|
if (entity_has_prop(ent, ENTITY_PROP_TRIGGER_NEXT_TICK)) {
|
||||||
|
entity_disable_prop(ent, ENTITY_PROP_TRIGGER_NEXT_TICK);
|
||||||
|
entity_enable_prop(ent, ENTITY_PROP_TRIGGERED_THIS_TICK);
|
||||||
|
} else if (entity_has_prop(ent, ENTITY_PROP_TRIGGERED_THIS_TICK)) {
|
||||||
|
entity_disable_prop(ent, ENTITY_PROP_TRIGGERED_THIS_TICK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Update animations from sprite
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) {
|
||||||
struct entity *ent = &store->entities[entity_index];
|
struct entity *ent = &store->entities[entity_index];
|
||||||
if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue;
|
if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue;
|
||||||
if (sprite_tag_is_nil(ent->sprite)) continue;
|
if (sprite_tag_is_nil(ent->sprite)) continue;
|
||||||
@ -302,7 +332,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
|
|||||||
* Update control from player cmds
|
* Update control from player cmds
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
for (u64 entity_index = 0; entity_index < store->count; ++entity_index) {
|
for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) {
|
||||||
struct entity *ent = &store->entities[entity_index];
|
struct entity *ent = &store->entities[entity_index];
|
||||||
if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue;
|
if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue;
|
||||||
|
|
||||||
@ -363,7 +393,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
|
|||||||
* Test
|
* Test
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
for (u64 entity_index = 0; entity_index < store->count; ++entity_index) {
|
for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) {
|
||||||
struct entity *ent = &store->entities[entity_index];
|
struct entity *ent = &store->entities[entity_index];
|
||||||
if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue;
|
if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue;
|
||||||
|
|
||||||
@ -394,67 +424,11 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
|
||||||
* Activate triggers
|
|
||||||
* ========================== */
|
|
||||||
|
|
||||||
for (u64 entity_index = 0; entity_index < store->count; ++entity_index) {
|
|
||||||
struct entity *ent = &store->entities[entity_index];
|
|
||||||
if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue;
|
|
||||||
|
|
||||||
/* Trigger equipped */
|
|
||||||
if (entity_has_prop(ent, ENTITY_PROP_TRIGGERING_EQUIPPED)) {
|
|
||||||
struct entity *eq = entity_from_handle(store, ent->equipped);
|
|
||||||
if (entity_has_prop(eq, ENTITY_PROP_ACTIVE)) {
|
|
||||||
entity_enable_prop(eq, ENTITY_PROP_TRIGGERED_THIS_TICK);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ========================== *
|
|
||||||
* Fire triggers
|
|
||||||
* ========================== */
|
|
||||||
|
|
||||||
for (u64 entity_index = 0; entity_index < store->count; ++entity_index) {
|
|
||||||
struct entity *ent = &store->entities[entity_index];
|
|
||||||
if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) 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)) {
|
|
||||||
struct xform xf = entity_get_xform(ent);
|
|
||||||
|
|
||||||
struct sprite_tag sprite = ent->sprite;
|
|
||||||
u32 animation_frame = ent->animation_frame;
|
|
||||||
struct xform sprite_xform = xform_mul(xf, ent->sprite_local_xform);
|
|
||||||
struct sprite_sheet *sheet = sprite_sheet_from_tag_await(sprite_frame_scope, sprite);
|
|
||||||
|
|
||||||
struct sprite_sheet_slice out_slice = sprite_sheet_get_slice(sheet, STR("out"), animation_frame);
|
|
||||||
struct v2 out_pos = xform_mul_v2(sprite_xform, out_slice.center);
|
|
||||||
struct v2 out_vec = xform_basis_mul_v2(sprite_xform, out_slice.dir);
|
|
||||||
out_vec = v2_norm(out_vec);
|
|
||||||
out_vec = v2_mul(out_vec, 2);
|
|
||||||
|
|
||||||
{
|
|
||||||
/* Spawn bullet */
|
|
||||||
struct entity *bullet = entity_alloc(root);
|
|
||||||
bullet->sprite = sprite_tag_from_path(STR("res/graphics/bullet.ase"));
|
|
||||||
struct xform bullet_xf = XFORM_POS(out_pos);
|
|
||||||
entity_set_xform(bullet, bullet_xf);
|
|
||||||
bullet->velocity = out_vec;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Simulate entity physics
|
* Simulate entity physics
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
for (u64 entity_index = 0; entity_index < store->count; ++entity_index) {
|
for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) {
|
||||||
struct entity *ent = &store->entities[entity_index];
|
struct entity *ent = &store->entities[entity_index];
|
||||||
if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue;
|
if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue;
|
||||||
|
|
||||||
@ -540,11 +514,67 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Activate triggers
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) {
|
||||||
|
struct entity *ent = &store->entities[entity_index];
|
||||||
|
if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue;
|
||||||
|
|
||||||
|
/* Trigger equipped */
|
||||||
|
if (entity_has_prop(ent, ENTITY_PROP_TRIGGERING_EQUIPPED)) {
|
||||||
|
struct entity *eq = entity_from_handle(store, ent->equipped);
|
||||||
|
if (entity_has_prop(eq, ENTITY_PROP_ACTIVE)) {
|
||||||
|
entity_enable_prop(eq, ENTITY_PROP_TRIGGERED_THIS_TICK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Fire triggers
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) {
|
||||||
|
struct entity *ent = &store->entities[entity_index];
|
||||||
|
if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) 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)) {
|
||||||
|
struct xform xf = entity_get_xform(ent);
|
||||||
|
|
||||||
|
struct sprite_tag sprite = ent->sprite;
|
||||||
|
u32 animation_frame = ent->animation_frame;
|
||||||
|
struct xform sprite_xform = xform_mul(xf, ent->sprite_local_xform);
|
||||||
|
struct sprite_sheet *sheet = sprite_sheet_from_tag_await(sprite_frame_scope, sprite);
|
||||||
|
|
||||||
|
struct sprite_sheet_slice out_slice = sprite_sheet_get_slice(sheet, STR("out"), animation_frame);
|
||||||
|
struct v2 out_pos = xform_mul_v2(sprite_xform, out_slice.center);
|
||||||
|
struct v2 out_vec = xform_basis_mul_v2(sprite_xform, out_slice.dir);
|
||||||
|
out_vec = v2_norm(out_vec);
|
||||||
|
out_vec = v2_mul(out_vec, 5);
|
||||||
|
|
||||||
|
{
|
||||||
|
/* Spawn bullet */
|
||||||
|
struct entity *bullet = entity_alloc(root);
|
||||||
|
bullet->sprite = sprite_tag_from_path(STR("res/graphics/bullet.ase"));
|
||||||
|
struct xform bullet_xf = XFORM_POS(out_pos);
|
||||||
|
entity_set_xform(bullet, bullet_xf);
|
||||||
|
bullet->velocity = out_vec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Update camera position
|
* Update camera position
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
for (u64 entity_index = 0; entity_index < store->count; ++entity_index) {
|
for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) {
|
||||||
struct entity *ent = &store->entities[entity_index];
|
struct entity *ent = &store->entities[entity_index];
|
||||||
if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue;
|
if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue;
|
||||||
|
|
||||||
@ -589,7 +619,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
|
|||||||
* Update sound emitters
|
* Update sound emitters
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
for (u64 entity_index = 0; entity_index < store->count; ++entity_index) {
|
for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) {
|
||||||
struct entity *ent = &store->entities[entity_index];
|
struct entity *ent = &store->entities[entity_index];
|
||||||
if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue;
|
if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue;
|
||||||
|
|
||||||
@ -622,7 +652,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
|
|||||||
|
|
||||||
struct entity **ents_to_release = arena_dry_push(temp.arena, struct entity *);
|
struct entity **ents_to_release = arena_dry_push(temp.arena, struct entity *);
|
||||||
u64 ents_to_release_count = 0;
|
u64 ents_to_release_count = 0;
|
||||||
for (u64 entity_index = 0; entity_index < store->count; ++entity_index) {
|
for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) {
|
||||||
struct entity *ent = &store->entities[entity_index];
|
struct entity *ent = &store->entities[entity_index];
|
||||||
if (!ent->valid) continue;
|
if (!ent->valid) continue;
|
||||||
|
|
||||||
@ -689,36 +719,6 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
|
|||||||
publish_game_tick();
|
publish_game_tick();
|
||||||
__profframe("Game");
|
__profframe("Game");
|
||||||
|
|
||||||
/* ========================== *
|
|
||||||
* Reset triggered entities
|
|
||||||
* ========================== */
|
|
||||||
|
|
||||||
for (u64 entity_index = 0; entity_index < store->count; ++entity_index) {
|
|
||||||
struct entity *ent = &store->entities[entity_index];
|
|
||||||
if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue;
|
|
||||||
|
|
||||||
if (entity_has_prop(ent, ENTITY_PROP_TRIGGER_NEXT_TICK)) {
|
|
||||||
entity_disable_prop(ent, ENTITY_PROP_TRIGGER_NEXT_TICK);
|
|
||||||
entity_enable_prop(ent, ENTITY_PROP_TRIGGERED_THIS_TICK);
|
|
||||||
} else if (entity_has_prop(ent, ENTITY_PROP_TRIGGERED_THIS_TICK)) {
|
|
||||||
entity_disable_prop(ent, ENTITY_PROP_TRIGGERED_THIS_TICK);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ========================== *
|
|
||||||
* Activate entities
|
|
||||||
* ========================== */
|
|
||||||
|
|
||||||
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_ACTIVE)) {
|
|
||||||
entity_enable_prop(ent, ENTITY_PROP_ACTIVE);
|
|
||||||
++ent->continuity_gen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* End frame cache scopes
|
* End frame cache scopes
|
||||||
* ========================== */
|
* ========================== */
|
||||||
@ -749,10 +749,23 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(game_thread_entry_point, arg)
|
|||||||
if (!G.paused) {
|
if (!G.paused) {
|
||||||
game_update(game_cmds);
|
game_update(game_cmds);
|
||||||
}
|
}
|
||||||
/* Check for pause cmd */
|
/* Check for pause / next frame cmds */
|
||||||
for (u64 i = 0; i < game_cmds.count; ++i) {
|
for (u64 i = 0; i < game_cmds.count; ++i) {
|
||||||
if (game_cmds.cmds[i].kind == GAME_CMD_KIND_PAUSE) {
|
struct game_cmd cmd = game_cmds.cmds[i];
|
||||||
G.paused = !G.paused;
|
switch (cmd.kind) {
|
||||||
|
case GAME_CMD_KIND_PAUSE: {
|
||||||
|
G.paused = !G.paused;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case GAME_CMD_KIND_STEP: {
|
||||||
|
if (G.paused) {
|
||||||
|
G.paused = false;
|
||||||
|
game_update(game_cmds);
|
||||||
|
G.paused = true;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,6 +22,7 @@ enum game_cmd_kind {
|
|||||||
GAME_CMD_KIND_CLEAR_ALL,
|
GAME_CMD_KIND_CLEAR_ALL,
|
||||||
GAME_CMD_KIND_SPAWN_TEST,
|
GAME_CMD_KIND_SPAWN_TEST,
|
||||||
GAME_CMD_KIND_PAUSE,
|
GAME_CMD_KIND_PAUSE,
|
||||||
|
GAME_CMD_KIND_STEP,
|
||||||
|
|
||||||
GAME_CMD_KIND_COUNT
|
GAME_CMD_KIND_COUNT
|
||||||
};
|
};
|
||||||
|
|||||||
41
src/user.c
41
src/user.c
@ -86,6 +86,7 @@ GLOBAL READONLY enum user_bind_kind g_binds[SYS_BTN_COUNT] = {
|
|||||||
|
|
||||||
[SYS_BTN_C] = USER_BIND_KIND_DEBUG_CLEAR,
|
[SYS_BTN_C] = USER_BIND_KIND_DEBUG_CLEAR,
|
||||||
[SYS_BTN_V] = USER_BIND_KIND_DEBUG_SPAWN,
|
[SYS_BTN_V] = USER_BIND_KIND_DEBUG_SPAWN,
|
||||||
|
[SYS_BTN_N] = USER_BIND_KIND_DEBUG_STEP,
|
||||||
[SYS_BTN_F1] = USER_BIND_KIND_DEBUG_PAUSE,
|
[SYS_BTN_F1] = USER_BIND_KIND_DEBUG_PAUSE,
|
||||||
[SYS_BTN_F2] = USER_BIND_KIND_DEBUG_CAMERA,
|
[SYS_BTN_F2] = USER_BIND_KIND_DEBUG_CAMERA,
|
||||||
[SYS_BTN_F3] = USER_BIND_KIND_DEBUG_DRAW,
|
[SYS_BTN_F3] = USER_BIND_KIND_DEBUG_DRAW,
|
||||||
@ -440,24 +441,29 @@ INTERNAL void user_update(void)
|
|||||||
tick_blend = clamp_f32(tick_blend, 0.0f, 1.0f);
|
tick_blend = clamp_f32(tick_blend, 0.0f, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: Should we actually be basing interpolated tick on t1 rather
|
world_copy_replace(&G.world, t0);
|
||||||
* than t0? This means un-interpolated values will use the newer frame's
|
|
||||||
* value, while still interpolating from the older frame. */
|
|
||||||
world_copy_replace(&G.world, t1);
|
|
||||||
|
|
||||||
/* Blend world globals */
|
/* Blend world globals */
|
||||||
G.world.time = math_lerp64(t0->time, t1->time, (f64)tick_blend);
|
G.world.time = math_lerp64(t0->time, t1->time, (f64)tick_blend);
|
||||||
|
|
||||||
/* Blend entities */
|
/* Blend entities */
|
||||||
u64 num_entities = min_u64(t0->entity_store->count, t1->entity_store->count);
|
u64 num_entities = min_u64(t0->entity_store->reserved, t1->entity_store->reserved);
|
||||||
{
|
{
|
||||||
__profscope(tick_blending);
|
__profscope(tick_blending);
|
||||||
for (u64 i = 0; i < num_entities; ++i) {
|
for (u64 i = 0; i < num_entities; ++i) {
|
||||||
|
struct entity *e = &store->entities[i];
|
||||||
struct entity *e0 = &t0->entity_store->entities[i];
|
struct entity *e0 = &t0->entity_store->entities[i];
|
||||||
struct entity *e1 = &t1->entity_store->entities[i];
|
struct entity *e1 = &t1->entity_store->entities[i];
|
||||||
struct entity *e = &store->entities[i];
|
ASSERT(e->cached_global_xform_dirty == false); /* Game thread should have cached all global xforms before publishing */
|
||||||
ASSERT(!e->valid || e->cached_global_xform_dirty == false); /* Game thread should have cached all global xforms before publishing */
|
|
||||||
if (e0->handle.gen == e1->handle.gen && e0->continuity_gen == e1->continuity_gen) {
|
if (entity_has_prop(e, ENTITY_PROP_TEST)) {
|
||||||
|
DEBUGBREAKABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e0->valid && e1->valid
|
||||||
|
&& entity_has_prop(e0, ENTITY_PROP_ACTIVE) && entity_has_prop(e1, ENTITY_PROP_ACTIVE)
|
||||||
|
&& e0->handle.gen == e1->handle.gen
|
||||||
|
&& e0->continuity_gen == e1->continuity_gen) {
|
||||||
e->local_xform = xform_lerp(e0->local_xform, e1->local_xform, tick_blend);
|
e->local_xform = xform_lerp(e0->local_xform, e1->local_xform, tick_blend);
|
||||||
e->cached_global_xform = xform_lerp(e0->cached_global_xform, e1->cached_global_xform, tick_blend);
|
e->cached_global_xform = xform_lerp(e0->cached_global_xform, e1->cached_global_xform, tick_blend);
|
||||||
|
|
||||||
@ -586,6 +592,16 @@ INTERNAL void user_update(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Test step */
|
||||||
|
{
|
||||||
|
struct bind_state state = G.bind_states[USER_BIND_KIND_DEBUG_STEP];
|
||||||
|
if (state.num_presses) {
|
||||||
|
queue_game_cmd(&cmd_list, (struct game_cmd) {
|
||||||
|
.kind = GAME_CMD_KIND_STEP
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Test spawn */
|
/* Test spawn */
|
||||||
{
|
{
|
||||||
struct bind_state state = G.bind_states[USER_BIND_KIND_DEBUG_SPAWN];
|
struct bind_state state = G.bind_states[USER_BIND_KIND_DEBUG_SPAWN];
|
||||||
@ -770,16 +786,16 @@ INTERNAL void user_update(void)
|
|||||||
* Draw entities
|
* Draw entities
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
for (u64 entity_index = 0; entity_index < store->count; ++entity_index) {
|
for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) {
|
||||||
__profscope(user_entity_iter);
|
__profscope(user_entity_iter);
|
||||||
struct entity *ent = &store->entities[entity_index];
|
struct entity *ent = &store->entities[entity_index];
|
||||||
if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue;
|
if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue;
|
||||||
if (ent->is_root) continue;
|
|
||||||
|
|
||||||
struct sprite_tag sprite = ent->sprite;
|
struct sprite_tag sprite = ent->sprite;
|
||||||
|
|
||||||
/* Skip undrawable entities */
|
/* Skip undrawable entities */
|
||||||
if (sprite_tag_is_nil(sprite) && !entity_has_prop(ent, ENTITY_PROP_CAMERA)) {
|
if (ent->is_root
|
||||||
|
|| (sprite_tag_is_nil(sprite) && !entity_has_prop(ent, ENTITY_PROP_CAMERA))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1030,6 +1046,9 @@ INTERNAL void user_update(void)
|
|||||||
draw_text(G.viewport_canvas, font, pos, string_format(temp.arena, STR("world time: %F"), FMT_FLOAT((f64)G.world.time)));
|
draw_text(G.viewport_canvas, font, pos, string_format(temp.arena, STR("world time: %F"), FMT_FLOAT((f64)G.world.time)));
|
||||||
pos.y += spacing;
|
pos.y += spacing;
|
||||||
|
|
||||||
|
draw_text(G.viewport_canvas, font, pos, string_format(temp.arena, STR("entities: %F/%F"), FMT_UINT(G.world.entity_store->allocated), FMT_UINT(G.world.entity_store->reserved)));
|
||||||
|
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)));
|
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;
|
pos.y += spacing;
|
||||||
|
|
||||||
|
|||||||
@ -27,6 +27,7 @@ enum user_bind_kind {
|
|||||||
USER_BIND_KIND_DEBUG_DRAW,
|
USER_BIND_KIND_DEBUG_DRAW,
|
||||||
USER_BIND_KIND_DEBUG_CAMERA,
|
USER_BIND_KIND_DEBUG_CAMERA,
|
||||||
USER_BIND_KIND_DEBUG_PAUSE,
|
USER_BIND_KIND_DEBUG_PAUSE,
|
||||||
|
USER_BIND_KIND_DEBUG_STEP,
|
||||||
USER_BIND_KIND_FULLSCREEN,
|
USER_BIND_KIND_FULLSCREEN,
|
||||||
USER_BIND_KIND_ZOOM_IN,
|
USER_BIND_KIND_ZOOM_IN,
|
||||||
USER_BIND_KIND_ZOOM_OUT,
|
USER_BIND_KIND_ZOOM_OUT,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user