entity_prop_kinematic
This commit is contained in:
parent
2a357c127f
commit
38075e5efd
BIN
res/graphics/bullet.ase
(Stored with Git LFS)
BIN
res/graphics/bullet.ase
(Stored with Git LFS)
Binary file not shown.
51
src/entity.c
51
src/entity.c
@ -218,17 +218,20 @@ INTERNAL void entity_mark_child_xforms_dirty(struct entity_store *store, struct
|
||||
INTERNAL struct xform entity_get_xform_w_store(struct entity_store *store, struct entity *ent)
|
||||
{
|
||||
struct xform xf;
|
||||
if (ent->is_top) {
|
||||
xf = ent->local_xform;
|
||||
} else if (!ent->cached_global_xform_dirty) {
|
||||
xf = ent->cached_global_xform;
|
||||
} else {
|
||||
struct entity_handle parent_handle = ent->parent;
|
||||
struct entity *parent = entity_from_handle(store, parent_handle);
|
||||
xf = entity_get_xform_w_store(store, parent);
|
||||
xf = xform_mul(xf, ent->local_xform);
|
||||
if (ent->cached_global_xform_dirty) {
|
||||
if (ent->is_top) {
|
||||
xf = ent->local_xform;
|
||||
} else {
|
||||
struct entity *parent = entity_from_handle(store, ent->parent);
|
||||
xf = entity_get_xform_w_store(store, parent);
|
||||
xf = xform_mul(xf, ent->local_xform);
|
||||
ent->cached_global_xform = xf;
|
||||
ent->cached_global_xform_dirty = false;
|
||||
}
|
||||
ent->cached_global_xform = xf;
|
||||
ent->cached_global_xform_dirty = false;
|
||||
} else {
|
||||
xf = ent->cached_global_xform;
|
||||
}
|
||||
return xf;
|
||||
}
|
||||
@ -236,17 +239,21 @@ INTERNAL struct xform entity_get_xform_w_store(struct entity_store *store, struc
|
||||
struct xform entity_get_xform(struct entity *ent)
|
||||
{
|
||||
struct xform xf;
|
||||
if (ent->is_top) {
|
||||
xf = ent->local_xform;
|
||||
} else if (!ent->cached_global_xform_dirty) {
|
||||
xf = ent->cached_global_xform;
|
||||
} else {
|
||||
struct entity_store *store = entity_get_store(ent);
|
||||
struct entity *parent = entity_from_handle(store, ent->parent);
|
||||
xf = entity_get_xform_w_store(store, parent);
|
||||
xf = xform_mul(xf, ent->local_xform);
|
||||
if (ent->cached_global_xform_dirty) {
|
||||
if (ent->is_top) {
|
||||
xf = ent->local_xform;
|
||||
} else {
|
||||
struct entity_store *store = entity_get_store(ent);
|
||||
struct entity *parent = entity_from_handle(store, ent->parent);
|
||||
xf = entity_get_xform_w_store(store, parent);
|
||||
xf = xform_mul(xf, ent->local_xform);
|
||||
ent->cached_global_xform = xf;
|
||||
ent->cached_global_xform_dirty = false;
|
||||
}
|
||||
ent->cached_global_xform = xf;
|
||||
ent->cached_global_xform_dirty = false;
|
||||
} else {
|
||||
xf = ent->cached_global_xform;
|
||||
}
|
||||
return xf;
|
||||
}
|
||||
@ -259,18 +266,16 @@ struct xform entity_get_local_xform(struct entity *ent)
|
||||
void entity_set_xform(struct entity *ent, struct xform xf)
|
||||
{
|
||||
struct entity_store *store = entity_get_store(ent);
|
||||
/* Update local xform */
|
||||
if (ent->is_top) {
|
||||
ent->local_xform = xf;
|
||||
} else {
|
||||
/* Update child local xform */
|
||||
struct entity *parent = entity_from_handle(store, ent->parent);
|
||||
struct xform parent_global = entity_get_xform_w_store(store, parent);
|
||||
ent->local_xform = xform_mul(xform_invert(parent_global), xf);
|
||||
|
||||
/* Set child global xform */
|
||||
ent->cached_global_xform = xf;
|
||||
ent->cached_global_xform_dirty = false;
|
||||
}
|
||||
ent->cached_global_xform = xf;
|
||||
ent->cached_global_xform_dirty = false;
|
||||
entity_mark_child_xforms_dirty(store, ent);
|
||||
}
|
||||
|
||||
|
||||
19
src/entity.h
19
src/entity.h
@ -8,18 +8,22 @@ enum entity_prop {
|
||||
ENTITY_PROP_NONE,
|
||||
|
||||
ENTITY_PROP_ACTIVE,
|
||||
ENTITY_PROP_RELEASE_AT_END_OF_TICK,
|
||||
|
||||
ENTITY_PROP_RELEASE_NEXT_TICK,
|
||||
|
||||
ENTITY_PROP_KINEMATIC,
|
||||
|
||||
ENTITY_PROP_PLAYER_CONTROLLED,
|
||||
ENTITY_PROP_CAMERA,
|
||||
ENTITY_PROP_CAMERA_ACTIVE,
|
||||
|
||||
ENTITY_PROP_BULLET,
|
||||
ENTITY_PROP_WEAPON,
|
||||
ENTITY_PROP_TRIGGERING_EQUIPPED,
|
||||
ENTITY_PROP_TRIGGERED_THIS_TICK,
|
||||
ENTITY_PROP_TRIGGER_NEXT_TICK,
|
||||
|
||||
ENTITY_PROP_BULLET,
|
||||
|
||||
/* Test props */
|
||||
|
||||
ENTITY_PROP_TEST,
|
||||
@ -66,12 +70,18 @@ struct entity {
|
||||
struct entity_handle first;
|
||||
struct entity_handle last;
|
||||
|
||||
/* ====================================================================== */
|
||||
/* Activation */
|
||||
|
||||
/* If 0, the entity will auto activate at start of next tick if not already active. */
|
||||
u64 activation_tick;
|
||||
|
||||
/* ====================================================================== */
|
||||
/* Position */
|
||||
|
||||
/* Access with xform getters/setters */
|
||||
struct xform local_xform; /* Transform in relation to parent entity (or the world if entity has no parent) */
|
||||
struct xform cached_global_xform; /* Calculated from entity tree */
|
||||
struct xform local_xform; /* Transform in relation to parent entity (or the world if entity has no parent) */
|
||||
struct xform cached_global_xform; /* Calculated from entity tree */
|
||||
b32 cached_global_xform_dirty;
|
||||
|
||||
/* ====================================================================== */
|
||||
@ -92,6 +102,7 @@ struct entity {
|
||||
/* ====================================================================== */
|
||||
/* Physics */
|
||||
|
||||
/* ENTITY_PROP_KINEMATIC */
|
||||
struct v2 acceleration;
|
||||
struct v2 velocity;
|
||||
|
||||
|
||||
224
src/game.c
224
src/game.c
@ -129,7 +129,7 @@ INTERNAL void spawn_test_entities(void)
|
||||
|
||||
player_ent = e;
|
||||
|
||||
//entity_enable_prop(e, ENTITY_PROP_TEST);
|
||||
entity_enable_prop(e, ENTITY_PROP_KINEMATIC);
|
||||
}
|
||||
|
||||
/* Weapon */
|
||||
@ -156,6 +156,8 @@ INTERNAL void spawn_test_entities(void)
|
||||
e->trigger_delay = 1.0 / 10.0;
|
||||
|
||||
player_ent->equipped = e->handle;
|
||||
|
||||
//entity_enable_prop(e, ENTITY_PROP_KINEMATIC);
|
||||
}
|
||||
|
||||
/* Camera */
|
||||
@ -246,6 +248,35 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
|
||||
};
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Release entities
|
||||
* ========================== */
|
||||
|
||||
/* TODO: Breadth first iteration to only release parent entities (since
|
||||
* child entities will be released along with parent anyway) */
|
||||
|
||||
{
|
||||
struct temp_arena temp = arena_temp_begin(scratch.arena);
|
||||
|
||||
struct entity **ents_to_release = arena_dry_push(temp.arena, struct entity *);
|
||||
u64 ents_to_release_count = 0;
|
||||
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_RELEASE_NEXT_TICK)) {
|
||||
*arena_push(temp.arena, struct entity *) = ent;
|
||||
++ents_to_release_count;
|
||||
}
|
||||
}
|
||||
|
||||
for (u64 i = 0; i < ents_to_release_count; ++i) {
|
||||
entity_release(store, ents_to_release[i]);
|
||||
}
|
||||
|
||||
arena_temp_end(temp);
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Activate entities
|
||||
* ========================== */
|
||||
@ -255,8 +286,11 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
|
||||
if (!ent->valid) continue;
|
||||
|
||||
if (!entity_has_prop(ent, ENTITY_PROP_ACTIVE)) {
|
||||
entity_enable_prop(ent, ENTITY_PROP_ACTIVE);
|
||||
++ent->continuity_gen;
|
||||
if (ent->activation_tick == 0 || G.tick.tick_id >= ent->activation_tick) {
|
||||
entity_enable_prop(ent, ENTITY_PROP_ACTIVE);
|
||||
ent->activation_tick = G.tick.tick_id;
|
||||
++ent->continuity_gen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -424,6 +458,91 @@ 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 (eq->valid) {
|
||||
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, 25);
|
||||
|
||||
{
|
||||
/* FIXME: Weapon velocity should affect bullet velocity
|
||||
* (This should also make bullet_src_ent unnecessary for
|
||||
* drawing bullet trails) */
|
||||
|
||||
#if 1
|
||||
/* Spawn bullet */
|
||||
struct entity *bullet = entity_alloc(root);
|
||||
bullet->sprite = sprite_tag_from_path(STR("res/graphics/bullet.ase"));
|
||||
struct xform bullet_xf = XFORM_TRS(.t = out_pos, .r = v2_angle(out_vec) + PI / 2);
|
||||
entity_set_xform(bullet, bullet_xf);
|
||||
bullet->velocity = out_vec;
|
||||
bullet->bullet_src = ent->handle;
|
||||
entity_enable_prop(bullet, ENTITY_PROP_BULLET);
|
||||
#elif 1
|
||||
/* TODO: Remove this (testing) */
|
||||
struct v2 barrel_velocity = entity_from_handle(store, ent->parent)->velocity;
|
||||
|
||||
/* Create bullet */
|
||||
/* TODO: Move bullet infront of barrel by hitbox */
|
||||
struct entity *bullet = entity_alloc(root);
|
||||
bullet->sprite = sprite_tag_from_path(STR("res/graphics/bullet.ase"));
|
||||
struct xform bullet_xf = XFORM_TRS(.t = out_pos, .r = v2_angle(out_vec) + PI / 2);
|
||||
entity_set_xform(bullet, bullet_xf);
|
||||
entity_enable_prop(bullet, ENTITY_PROP_BULLET);
|
||||
bullet->bullet_src = ent->handle;
|
||||
bullet->activation_tick = G.tick.tick_id + 1;
|
||||
bullet->velocity = barrel_velocity;
|
||||
|
||||
/* Create impulse */
|
||||
struct entity *impulse = entity_alloc(root);
|
||||
entity_enable_prop(impulse, ENTITY_PROP_IMPULSE);
|
||||
impulse->impulse_target = bullet->handle;
|
||||
impulse->impulse_vec = out_vec;
|
||||
impulse->activation_tick = bullet->activation_tick + 1; /* Ensure bullet exists for 1 tick at the start of the barrel before impulse is applied */
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Simulate entity physics
|
||||
* ========================== */
|
||||
@ -500,7 +619,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
|
||||
|
||||
/* Integrate acceleration & velocity */
|
||||
|
||||
{
|
||||
if (entity_has_prop(ent, ENTITY_PROP_KINEMATIC)) {
|
||||
f32 dt = (f32)G.tick.dt;
|
||||
|
||||
/* Apply acceleration to velocity */
|
||||
@ -514,74 +633,6 @@ 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, 25);
|
||||
|
||||
/* TODO: Remove this (testing) */
|
||||
{
|
||||
struct entity *parent = entity_from_handle(store, ent->parent);
|
||||
out_vec = v2_add(out_vec, parent->velocity);
|
||||
}
|
||||
|
||||
{
|
||||
/* FIXME: Weapon velocity should affect bullet velocity
|
||||
* (This should also make bullet_src_ent unnecessary for
|
||||
* drawing bullet trails) */
|
||||
|
||||
/* Spawn bullet */
|
||||
struct entity *bullet = entity_alloc(root);
|
||||
bullet->sprite = sprite_tag_from_path(STR("res/graphics/bullet.ase"));
|
||||
struct xform bullet_xf = XFORM_TRS(.t = out_pos, .r = v2_angle(out_vec) + PI / 2);
|
||||
entity_set_xform(bullet, bullet_xf);
|
||||
bullet->velocity = out_vec;
|
||||
bullet->bullet_src = ent->handle;
|
||||
entity_enable_prop(bullet, ENTITY_PROP_BULLET);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Update camera position
|
||||
* ========================== */
|
||||
@ -656,35 +707,6 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Release entities
|
||||
* ========================== */
|
||||
|
||||
/* TODO: Breadth first iteration to only release parent entities (since
|
||||
* child entities will be released along with parent anyway) */
|
||||
|
||||
{
|
||||
struct temp_arena temp = arena_temp_begin(scratch.arena);
|
||||
|
||||
struct entity **ents_to_release = arena_dry_push(temp.arena, struct entity *);
|
||||
u64 ents_to_release_count = 0;
|
||||
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_RELEASE_AT_END_OF_TICK)) {
|
||||
*arena_push(temp.arena, struct entity *) = ent;
|
||||
++ents_to_release_count;
|
||||
}
|
||||
}
|
||||
|
||||
for (u64 i = 0; i < ents_to_release_count; ++i) {
|
||||
entity_release(store, ents_to_release[i]);
|
||||
}
|
||||
|
||||
arena_temp_end(temp);
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Publish tick
|
||||
* ========================== */
|
||||
|
||||
@ -804,6 +804,7 @@ INTERNAL void user_update(void)
|
||||
struct xform sprite_xform = xf;
|
||||
|
||||
/* Draw bullet trail */
|
||||
#if 0
|
||||
if (entity_has_prop(ent, ENTITY_PROP_BULLET)) {
|
||||
f32 max_len = 0.75;
|
||||
|
||||
@ -829,6 +830,7 @@ INTERNAL void user_update(void)
|
||||
|
||||
draw_solid_line(G.world_canvas, start, end, thickness, color);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Draw sprite */
|
||||
if (!sprite_tag_is_nil(sprite)) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user