sprite tag / animating logic touchup

This commit is contained in:
jacob 2024-03-06 19:26:00 -06:00
parent 6b21649c74
commit ed9841c1b1
10 changed files with 117 additions and 84 deletions

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

Binary file not shown.

View File

@ -910,6 +910,7 @@ struct ase_decode_sheet_result ase_decode_sheet(struct arena *arena, struct buff
scratch_end(scratch); scratch_end(scratch);
res.image_size = V2(image_width, image_height); res.image_size = V2(image_width, image_height);
res.frame_size = V2(frame_width, frame_height);
res.num_frames = num_frames; res.num_frames = num_frames;
res.num_tags = num_tags; res.num_tags = num_tags;
res.frame_head = frame_head; res.frame_head = frame_head;

View File

@ -23,6 +23,7 @@ struct ase_decode_image_result {
struct ase_decode_sheet_result { struct ase_decode_sheet_result {
struct v2 image_size; struct v2 image_size;
struct v2 frame_size;
u32 num_frames; u32 num_frames;
u32 num_tags; u32 num_tags;
struct ase_frame *frame_head; struct ase_frame *frame_head;

View File

@ -26,18 +26,3 @@ b32 entity_has_prop(struct entity *entity, enum entity_prop prop)
u64 bit = prop % 64; u64 bit = prop % 64;
return !!(entity->props[index] & ((u64)1 << bit)); return !!(entity->props[index] & ((u64)1 << bit));
} }
/* ========================== *
* Animation
* ========================== */
/* TODO: Move this to game */
void entity_start_animation(struct entity *entity, struct string animation_name, u64 flags)
{
entity_enable_prop(entity, ENTITY_PROP_SPRITE_ANIMATED);
entity->animation_name = animation_name;
entity->animation_flags = flags;
entity->animation_time_in_frame = 0;
++entity->animation_start_gen;
}

View File

@ -16,7 +16,7 @@ struct entity_handle {
enum entity_prop { enum entity_prop {
ENTITY_PROP_NONE, ENTITY_PROP_NONE,
ENTITY_PROP_SPRITE_ANIMATED, ENTITY_PROP_ANIMATING,
ENTITY_PROP_PLAYER_CONTROLLED, ENTITY_PROP_PLAYER_CONTROLLED,
ENTITY_PROP_CAMERA, ENTITY_PROP_CAMERA,
@ -48,7 +48,6 @@ struct entity {
/* Translation, rotation, scale in relation to parent entity */ /* Translation, rotation, scale in relation to parent entity */
struct trs rel_trs; struct trs rel_trs;
struct mat3x3 world_xform; /* Calculated post-physics */ struct mat3x3 world_xform; /* Calculated post-physics */
/* ====================================================================== */ /* ====================================================================== */
@ -65,6 +64,7 @@ struct entity {
/* Sprite */ /* Sprite */
struct string sprite_name; struct string sprite_name;
struct string sprite_tag_name;
struct trs sprite_trs; struct trs sprite_trs;
struct v2 sprite_pivot_norm; /* Pivot x & y are each normalized about sprite dimensions. <0, 0> is center, <1, 1> is bottom right corner, etc. */ struct v2 sprite_pivot_norm; /* Pivot x & y are each normalized about sprite dimensions. <0, 0> is center, <1, 1> is bottom right corner, etc. */
u32 sprite_tint; u32 sprite_tint;
@ -72,13 +72,9 @@ struct entity {
/* ====================================================================== */ /* ====================================================================== */
/* Animation */ /* Animation */
/* ENTITY_PROP_SPRITE_ANIMATED */ /* ENTITY_PROP_ANIMATING */
struct string animation_name; b32 animation_looping;
u64 animation_flags; f64 animation_start_time; /* Calculated */
f64 animation_time_in_frame;
u64 animation_start_gen;
u64 animation_gen;
struct sheet_frame animation_frame;
/* ====================================================================== */ /* ====================================================================== */
/* Testing */ /* Testing */
@ -117,11 +113,4 @@ void entity_enable_prop(struct entity *entity, enum entity_prop prop);
void entity_disable_prop(struct entity *entity, enum entity_prop prop); void entity_disable_prop(struct entity *entity, enum entity_prop prop);
b32 entity_has_prop(struct entity *entity, enum entity_prop prop); b32 entity_has_prop(struct entity *entity, enum entity_prop prop);
/* Animation */
#define ANIMATION_FLAG_NONE 0x0
#define ANIMATION_FLAG_LOOPING 0x1
void entity_start_animation(struct entity *entity, struct string animation_name, u64 flags);
#endif #endif

View File

@ -167,10 +167,11 @@ INTERNAL void game_update(void)
{ {
struct string sprite_name = STR("res/graphics/tim.ase"); struct string sprite_name = STR("res/graphics/tim.ase");
struct string sprite_tag_name = STR("UNARMED");
struct sheet *sheet = sheet_load(sprite_name); struct sheet *sheet = sheet_load(sprite_name);
f32 meters_width = sheet->image_size.x / PIXELS_PER_UNIT; f32 meters_width = sheet->frame_size.x / PIXELS_PER_UNIT;
f32 meters_height = sheet->image_size.y / PIXELS_PER_UNIT; f32 meters_height = sheet->frame_size.y / PIXELS_PER_UNIT;
struct v2 sprite_size = V2(meters_width, meters_height); struct v2 sprite_size = V2(meters_width, meters_height);
struct v2 pos = V2(0, 0); struct v2 pos = V2(0, 0);
@ -181,6 +182,7 @@ INTERNAL void game_update(void)
e->rel_trs = TRS(.t = pos, .r = 0, .s = V2(1, 1)); e->rel_trs = TRS(.t = pos, .r = 0, .s = V2(1, 1));
e->sprite_name = sprite_name; e->sprite_name = sprite_name;
e->sprite_tag_name = sprite_tag_name;
e->sprite_trs = TRS(.s = sprite_size); e->sprite_trs = TRS(.s = sprite_size);
e->sprite_pivot_norm = V2(0, 0.65); e->sprite_pivot_norm = V2(0, 0.65);
//e->sprite_pivot_norm = V2(0.4, 0.65); //e->sprite_pivot_norm = V2(0.4, 0.65);
@ -190,6 +192,9 @@ INTERNAL void game_update(void)
e->player_max_speed = 5.f; e->player_max_speed = 5.f;
e->player_acceleration = 15.0f; e->player_acceleration = 15.0f;
entity_enable_prop(e, ENTITY_PROP_ANIMATING);
e->animation_looping = true;
player_ent = e; player_ent = e;
//entity_enable_prop(e, ENTITY_PROP_TEST); //entity_enable_prop(e, ENTITY_PROP_TEST);
@ -205,7 +210,7 @@ INTERNAL void game_update(void)
entity_enable_prop(e, ENTITY_PROP_CAMERA); entity_enable_prop(e, ENTITY_PROP_CAMERA);
e->camera_active = true; e->camera_active = true;
e->camera_follow = player_ent->handle; e->camera_follow = player_ent->handle;
e->camera_zoom = 1; e->camera_zoom = 1.5;
} }
} }
@ -260,39 +265,46 @@ INTERNAL void game_update(void)
ent->test_start_sprite_trs = ent->sprite_trs; ent->test_start_sprite_trs = ent->sprite_trs;
} }
/* ENTITY_PROP_ANIMATING */
if (entity_has_prop(ent, ENTITY_PROP_ANIMATING) && ent->animation_start_time == 0) {
ent->animation_start_time = L.tick.time;
}
/* ========================== * /* ========================== *
* Update animation * Update animation
* ========================== */ * ========================== */
if (entity_has_prop(ent, ENTITY_PROP_SPRITE_ANIMATED)) { if (ent->animation_start_time > 0) {
struct sheet *sheet = sheet_load(ent->sprite_name); /* Stop animation if past duration and not looping */
struct sheet_tag tag = sheet_get_tag(sheet, ent->animation_name); if (!ent->animation_looping) {
f64 time_in_anim = L.tick.time - ent->animation_start_time;
if (ent->animation_start_gen == ent->animation_gen) { struct sheet *sheet = sheet_load(ent->sprite_name);
ent->animation_time_in_frame += L.tick.dt; if (sheet) {
} else { struct sheet_tag tag = sheet_get_tag(sheet, ent->sprite_tag_name);
ent->animation_frame = sheet_get_frame(sheet, tag.start);
ent->animation_start_gen = ent->animation_gen;
}
while (ent->animation_frame.duration != 0 && ent->animation_time_in_frame > ent->animation_frame.duration) { struct sheet_frame frame = { 0 };
u64 new_frame_index = ent->animation_frame.index + 1; u64 frame_index = tag.start;
if (new_frame_index > tag.end) { while (time_in_anim > 0) {
if (ent->animation_flags & ANIMATION_FLAG_LOOPING) { frame = sheet_get_frame(sheet, frame_index);
/* Restart animation */ if (frame_index > tag.end) {
new_frame_index = tag.start; entity_disable_prop(ent, ENTITY_PROP_ANIMATING);
} else { ent->animation_start_time = 0;
/* End animation */ break;
entity_start_animation(ent, STR("Default"), ANIMATION_FLAG_LOOPING); }
goto break_animation; time_in_anim -= frame.duration;
++frame_index;
} }
} else {
entity_disable_prop(ent, ENTITY_PROP_ANIMATING);
ent->animation_start_time = 0;
} }
ent->animation_frame = sheet_get_frame(sheet, new_frame_index);
ent->animation_time_in_frame -= ent->animation_frame.duration;
} }
} }
break_animation:
(UNUSED)0; /* Disable label at end of compound statement warning */ /* ========================== *
* Test
* ========================== */
/* ENTITY_PROP_TEST */ /* ENTITY_PROP_TEST */
if (entity_has_prop(ent, ENTITY_PROP_TEST)) { if (entity_has_prop(ent, ENTITY_PROP_TEST)) {

View File

@ -331,6 +331,15 @@ INLINE struct v2 v2_norm(struct v2 a)
return a; return a;
} }
INLINE struct v2 v2_round(struct v2 a)
{
return V2(
(f32)math_round_f32(a.x),
(f32)math_round_f32(a.y)
);
}
INLINE f32 v2_dot(struct v2 a, struct v2 b) INLINE f32 v2_dot(struct v2 a, struct v2 b)
{ {
return a.x * b.x + a.y * b.y; return a.x * b.x + a.y * b.y;

View File

@ -83,6 +83,7 @@ INTERNAL struct sheet sheet_from_ase(struct arena *arena, struct ase_decode_shee
/* Init frames */ /* Init frames */
sheet.image_size = ase.image_size; sheet.image_size = ase.image_size;
sheet.frame_size = ase.frame_size;
sheet.frames = arena_push_array_zero(arena, struct sheet_frame, ase.num_frames); sheet.frames = arena_push_array_zero(arena, struct sheet_frame, ase.num_frames);
sheet.frames_count = ase.num_frames; sheet.frames_count = ase.num_frames;
for (struct ase_frame *ase_frame = ase.frame_head; ase_frame; ase_frame = ase_frame->next) { for (struct ase_frame *ase_frame = ase.frame_head; ase_frame; ase_frame = ase_frame->next) {

View File

@ -8,6 +8,7 @@ struct sheet_frame;
struct sheet { struct sheet {
struct v2 image_size; struct v2 image_size;
struct v2 frame_size;
u32 frames_count; u32 frames_count;
struct sheet_frame *frames; struct sheet_frame *frames;
u32 tags_count; u32 tags_count;

View File

@ -226,7 +226,13 @@ INTERNAL struct mat3x3 view_get_xform(struct view view)
return res; return res;
} }
INTERNAL struct v2 view_inverse_point(struct view view, struct v2 p) INTERNAL struct v2 view_xform_point(struct view view, struct v2 p)
{
struct mat3x3 mtx = view_get_xform(view);
return mat3x3_mul_v2(mtx, p);
}
INTERNAL struct v2 view_inverse_xform_point(struct view view, struct v2 p)
{ {
struct mat3x3 mtx_inverse = mat3x3_inverse(view_get_xform(view)); struct mat3x3 mtx_inverse = mat3x3_inverse(view_get_xform(view));
return mat3x3_mul_v2(mtx_inverse, p); return mat3x3_mul_v2(mtx_inverse, p);
@ -234,7 +240,7 @@ INTERNAL struct v2 view_inverse_point(struct view view, struct v2 p)
INTERNAL struct v2 view_mouse_pos(struct view view) INTERNAL struct v2 view_mouse_pos(struct view view)
{ {
return view_inverse_point(view, L.screen_mouse); return view_inverse_xform_point(view, L.screen_mouse);
} }
/* ========================== * /* ========================== *
@ -606,11 +612,33 @@ INTERNAL void user_update(void)
if (texture) { if (texture) {
u32 tint = ent->sprite_tint; u32 tint = ent->sprite_tint;
struct draw_texture_params params = DRAW_TEXTURE_PARAMS(.texture = texture, .tint = tint); struct draw_texture_params params = DRAW_TEXTURE_PARAMS(.texture = texture, .tint = tint);
if (entity_has_prop(ent, ENTITY_PROP_SPRITE_ANIMATED)) {
struct sheet_frame frame = ent->animation_frame; struct sheet *sheet = sheet_load(ent->sprite_name);
if (sheet) {
struct sheet_tag tag = sheet_get_tag(sheet, ent->sprite_tag_name);
struct sheet_frame frame = sheet_get_frame(sheet, tag.start);
if (entity_has_prop(ent, ENTITY_PROP_ANIMATING)) {
b32 looping = ent->animation_looping;
f64 time_in_anim = tick->time - ent->animation_start_time;
u64 frame_index = tag.start;
while (time_in_anim > 0) {
frame = sheet_get_frame(sheet, frame_index);
time_in_anim -= frame.duration;
++frame_index;
if (frame_index > tag.end) {
frame_index = tag.start;
if (!looping) {
break;
}
}
}
}
params.clip = frame.clip; params.clip = frame.clip;
params = DRAW_TEXTURE_PARAMS(.texture = texture, .clip = frame.clip);
} }
draw_texture_quad(L.world_canvas, params, quad); draw_texture_quad(L.world_canvas, params, quad);
} }
@ -645,22 +673,18 @@ INTERNAL void user_update(void)
/* Debug draw info */ /* Debug draw info */
if (L.debug_draw && !is_camera) { if (L.debug_draw && !is_camera) {
struct mat3x3 mtx = ent->world_xform;
struct trs trs = trs_from_mat3x3(mtx);
struct v2 velocity = ent->velocity;
struct v2 acceleration = ent->acceleration;
struct font *disp_font = font_load_async(STR("res/fonts/fixedsys.ttf"), 12.0f); struct font *disp_font = font_load_async(STR("res/fonts/fixedsys.ttf"), 12.0f);
//f32 offset = 0.75;
//struct v2 dir = v2_mul(mat3x3_get_up(mtx), 0.5f);
//dir = v2_add(dir, v2_mul(v2_norm(dir), offset));
//struct v2 pos = v2_add(mat3x3_get_pos(mtx), dir);
f32 offset = 1.5;
struct v2 pos = v2_add(mat3x3_get_pos(mtx), v2_mul(V2(0, -1), offset));
if (disp_font) { if (disp_font) {
struct mat3x3 mtx = ent->world_xform;
struct trs trs = trs_from_mat3x3(mtx);
struct v2 velocity = ent->velocity;
struct v2 acceleration = ent->acceleration;
f32 offset = 1;
struct v2 pos = v2_add(mat3x3_get_pos(mtx), v2_mul(V2(0, -1), offset));
pos = view_xform_point(L.world_view, pos);
pos = v2_round(pos);
struct string disp_name = ent->sprite_name; struct string disp_name = ent->sprite_name;
struct string fmt = STR( struct string fmt = STR(
@ -681,7 +705,7 @@ INTERNAL void user_update(void)
); );
draw_text_ex(L.world_canvas, disp_font, pos, 1.0f / PIXELS_PER_UNIT, text); draw_text(L.ui_canvas, disp_font, pos, text);
} }
debug_draw_xform(ent->world_xform); debug_draw_xform(ent->world_xform);
@ -753,11 +777,21 @@ INTERNAL void user_update(void)
/* Present */ /* Present */
i32 vsync = VSYNC_ENABLED; i32 vsync = VSYNC_ENABLED;
struct renderer_canvas *canvases[] = {
L.world_canvas, struct renderer_canvas **canvases = NULL;
L.ui_canvas u64 canvases_count = 0;
};
renderer_canvas_present(canvases, ARRAY_COUNT(canvases), L.screen_size.x, L.screen_size.y, vsync); if (t0->id <= 0 || t1->id <= 0) {
/* Don't render world on first frame */
struct renderer_canvas *present_canvases[] = { L.ui_canvas };
canvases = present_canvases;
canvases_count = ARRAY_COUNT(present_canvases);
} else {
struct renderer_canvas *present_canvases[] = { L.world_canvas, L.ui_canvas };
canvases = present_canvases;
canvases_count = ARRAY_COUNT(present_canvases);
}
renderer_canvas_present(canvases, canvases_count, L.screen_size.x, L.screen_size.y, vsync);
scratch_end(scratch); scratch_end(scratch);
} }