weapon attachment to parent

This commit is contained in:
jacob 2024-08-15 13:59:42 -05:00
parent 9424c9c2c9
commit f48a059397
8 changed files with 80 additions and 33 deletions

BIN
res/graphics/gun.ase (Stored with Git LFS)

Binary file not shown.

BIN
res/graphics/tim.ase (Stored with Git LFS)

Binary file not shown.

View File

@ -265,6 +265,7 @@ struct xform entity_get_local_xform(struct entity *ent)
void entity_set_xform(struct entity *ent, struct xform xf) void entity_set_xform(struct entity *ent, struct xform xf)
{ {
if (!xform_eq(xf, ent->cached_global_xform)) {
struct entity_store *store = entity_get_store(ent); struct entity_store *store = entity_get_store(ent);
/* Update local xform */ /* Update local xform */
if (ent->is_top) { if (ent->is_top) {
@ -278,13 +279,16 @@ void entity_set_xform(struct entity *ent, struct xform xf)
ent->cached_global_xform_dirty = false; ent->cached_global_xform_dirty = false;
entity_mark_child_xforms_dirty(store, ent); entity_mark_child_xforms_dirty(store, ent);
} }
}
void entity_set_local_xform(struct entity *ent, struct xform xf) void entity_set_local_xform(struct entity *ent, struct xform xf)
{ {
if (!xform_eq(xf, ent->local_xform)) {
ent->local_xform = xf; ent->local_xform = xf;
ent->cached_global_xform_dirty = true; ent->cached_global_xform_dirty = true;
entity_mark_child_xforms_dirty(entity_get_store(ent), ent); entity_mark_child_xforms_dirty(entity_get_store(ent), ent);
} }
}
/* ========================== * /* ========================== *
* Tree * Tree

View File

@ -24,6 +24,8 @@ enum entity_prop {
ENTITY_PROP_BULLET, ENTITY_PROP_BULLET,
ENTITY_PROP_ATTACHED,
/* Test props */ /* Test props */
ENTITY_PROP_TEST, ENTITY_PROP_TEST,
@ -122,6 +124,13 @@ struct entity {
f64 animation_time_in_frame; f64 animation_time_in_frame;
u32 animation_frame; u32 animation_frame;
/* ====================================================================== */
/* Attachment */
/* ENTITY_PROP_ATTACHED */
/* Slice name on the parent entity's sprite to attach to */
struct string attach_slice;
/* ====================================================================== */ /* ====================================================================== */
/* Equip */ /* Equip */

View File

@ -118,9 +118,9 @@ INTERNAL void spawn_test_entities(void)
entity_set_xform(e, xf); entity_set_xform(e, xf);
e->sprite = sprite_tag_from_path(STR("res/graphics/tim.ase")); e->sprite = sprite_tag_from_path(STR("res/graphics/tim.ase"));
e->sprite_span_name = STR("idle.unarmed"); //e->sprite_span_name = STR("idle.unarmed");
//e->sprite_span_name = STR("idle.one_handed"); //e->sprite_span_name = STR("idle.one_handed");
//e->sprite_span_name = STR("idle.two_handed"); e->sprite_span_name = STR("idle.two_handed");
entity_enable_prop(e, ENTITY_PROP_PLAYER_CONTROLLED); entity_enable_prop(e, ENTITY_PROP_PLAYER_CONTROLLED);
e->player_max_speed = 4.f; e->player_max_speed = 4.f;
@ -140,18 +140,14 @@ INTERNAL void spawn_test_entities(void)
f32 r = PI / 4; f32 r = PI / 4;
struct entity *e = entity_alloc(root); struct entity *e = entity_alloc(root);
#else #else
struct v2 pos = V2(0.1, 0);
struct v2 size = V2(1, 1);
f32 r = 0;
struct entity *e = entity_alloc(player_ent); struct entity *e = entity_alloc(player_ent);
#endif #endif
struct xform xf = XFORM_TRS(.t = pos, .r = r, .s = size);
entity_set_local_xform(e, xf);
e->sprite = sprite_tag_from_path(STR("res/graphics/gun.ase")); e->sprite = sprite_tag_from_path(STR("res/graphics/gun.ase"));
entity_enable_prop(e, ENTITY_PROP_ATTACHED);
e->attach_slice = STR("attach.wep");
entity_enable_prop(e, ENTITY_PROP_WEAPON); entity_enable_prop(e, ENTITY_PROP_WEAPON);
e->trigger_delay = 1.0 / 10.0; e->trigger_delay = 1.0 / 10.0;
@ -284,7 +280,8 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
if (!ent->valid) continue; if (!ent->valid) continue;
if (!entity_has_prop(ent, ENTITY_PROP_ACTIVE)) { if (!entity_has_prop(ent, ENTITY_PROP_ACTIVE)) {
if (ent->activation_tick == 0 || G.tick.tick_id >= ent->activation_tick) { u64 atick = ent->activation_tick;
if (atick != 0 || G.tick.tick_id >= atick) {
entity_enable_prop(ent, ENTITY_PROP_ACTIVE); entity_enable_prop(ent, ENTITY_PROP_ACTIVE);
ent->activation_tick = G.tick.tick_id; ent->activation_tick = G.tick.tick_id;
++ent->continuity_gen; ++ent->continuity_gen;
@ -360,6 +357,33 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
ent->sprite_local_xform = xf; ent->sprite_local_xform = xf;
} }
/* ========================== *
* Update attachments
* ========================== */
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_ATTACHED)) {
struct entity *parent = entity_from_handle(store, ent->parent);
struct sprite_tag parent_sprite = parent->sprite;
struct sprite_sheet *parent_sheet = sprite_sheet_from_tag_await(sprite_frame_scope, parent_sprite);
struct xform parent_xf = entity_get_xform(parent);
struct xform parent_sprite_xf = xform_mul(parent_xf, parent->sprite_local_xform);
struct sprite_sheet_slice attach_slice = sprite_sheet_get_slice(parent_sheet, ent->attach_slice, parent->animation_frame);
struct v2 attach_pos = xform_mul_v2(parent_sprite_xf, attach_slice.center);
struct v2 attach_dir = xform_basis_mul_v2(parent_sprite_xf, attach_slice.dir);
struct xform xf = entity_get_xform(ent);
xf.og = attach_pos;
xf = xform_with_rotation(xf, v2_angle(attach_dir) + PI / 2);
entity_set_xform(ent, xf);
}
}
/* ========================== * /* ========================== *
* Update control from player cmds * Update control from player cmds
* ========================== */ * ========================== */
@ -506,7 +530,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
bullet->bullet_src = ent->handle; bullet->bullet_src = ent->handle;
bullet->bullet_src_pos = rel_pos; bullet->bullet_src_pos = rel_pos;
bullet->bullet_src_dir = rel_dir; bullet->bullet_src_dir = rel_dir;
bullet->bullet_impulse = 25; bullet->bullet_impulse = 5;
entity_enable_prop(bullet, ENTITY_PROP_BULLET); entity_enable_prop(bullet, ENTITY_PROP_BULLET);
} }
@ -530,7 +554,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
f32 final_xf_angle; f32 final_xf_angle;
{ {
struct sprite_sheet *sheet = sprite_sheet_from_tag_await(sprite_frame_scope, ent->sprite); struct sprite_sheet *sheet = sprite_sheet_from_tag_await(sprite_frame_scope, ent->sprite);
struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, STR("hold"), ent->animation_frame); struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, STR("attach.wep"), ent->animation_frame);
f32 forward_hold_angle_offset; f32 forward_hold_angle_offset;
{ {

View File

@ -741,6 +741,11 @@ INLINE struct v2 xform_get_scale(struct xform xf);
INLINE struct trs trs_from_xform(struct xform m); INLINE struct trs trs_from_xform(struct xform m);
INLINE struct trs trs_lerp(struct trs a, struct trs b, f32 t); INLINE struct trs trs_lerp(struct trs a, struct trs b, f32 t);
INLINE b32 xform_eq(struct xform xf1, struct xform xf2)
{
return v2_eq(xf1.bx, xf2.bx) && v2_eq(xf1.by, xf2.by) && v2_eq(xf1.og, xf2.og);
}
INLINE struct xform xform_from_pos(struct v2 v) INLINE struct xform xform_from_pos(struct v2 v)
{ {
return (struct xform) { return (struct xform) {

View File

@ -11,6 +11,9 @@
#define MEMCMP_STRUCT(p1, p2) MEMCMP((p1), (p2), sizeof(*p1)) #define MEMCMP_STRUCT(p1, p2) MEMCMP((p1), (p2), sizeof(*p1))
#define MEMCMP(p1, p2, n) memcmp((p1), (p2), (n)) #define MEMCMP(p1, p2, n) memcmp((p1), (p2), (n))
#define MEMEQ_STRUCT(p1, p2) MEMEQ((p1), (p2), sizeof(*p1))
#define MEMEQ(p1, p2, n) (MEMCMP((p1), (p2), (n)) == 0)
#define MEMSET(ptr, val, count) memset((ptr), (val), (count)) #define MEMSET(ptr, val, count) memset((ptr), (val), (count))
#if CRTLIB #if CRTLIB

View File

@ -974,6 +974,8 @@ struct sprite_sheet_slice sprite_sheet_get_slice(struct sprite_sheet *sheet, str
/* Return 'pivot' by default */ /* Return 'pivot' by default */
struct sprite_sheet_slice res = { 0 }; struct sprite_sheet_slice res = { 0 };
if (string_eq(name, STR("pivot"))) { if (string_eq(name, STR("pivot"))) {
/* 'pivot' slice does not exist, return center */
res.center = V2(0, 0);
res.center_px = v2_mul(sheet->frame_size, 0.5f); res.center_px = v2_mul(sheet->frame_size, 0.5f);
res.dir_px = V2(res.center_px.x, 0); res.dir_px = V2(res.center_px.x, 0);
res.dir = V2(0, -0.5); res.dir = V2(0, -0.5);
@ -1096,10 +1098,10 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sprite_evictor_thread_entry_point, arg)
} }
#endif #endif
/* Check usage time */
#if RESOURCE_RELOADING #if RESOURCE_RELOADING
/* Check usage time */
/* Only check conditional if RESOURCE_RELOADING is enabled, /* Only check conditional if RESOURCE_RELOADING is enabled,
* since over-budget is assumed to be * true otherwise */ * since over-budget is assumed to be true otherwise */
if (cache_over_budget) if (cache_over_budget)
#endif #endif
{ {