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);
res.image_size = V2(image_width, image_height);
res.frame_size = V2(frame_width, frame_height);
res.num_frames = num_frames;
res.num_tags = num_tags;
res.frame_head = frame_head;

View File

@ -23,6 +23,7 @@ struct ase_decode_image_result {
struct ase_decode_sheet_result {
struct v2 image_size;
struct v2 frame_size;
u32 num_frames;
u32 num_tags;
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;
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 {
ENTITY_PROP_NONE,
ENTITY_PROP_SPRITE_ANIMATED,
ENTITY_PROP_ANIMATING,
ENTITY_PROP_PLAYER_CONTROLLED,
ENTITY_PROP_CAMERA,
@ -48,7 +48,6 @@ struct entity {
/* Translation, rotation, scale in relation to parent entity */
struct trs rel_trs;
struct mat3x3 world_xform; /* Calculated post-physics */
/* ====================================================================== */
@ -65,6 +64,7 @@ struct entity {
/* Sprite */
struct string sprite_name;
struct string sprite_tag_name;
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. */
u32 sprite_tint;
@ -72,13 +72,9 @@ struct entity {
/* ====================================================================== */
/* Animation */
/* ENTITY_PROP_SPRITE_ANIMATED */
struct string animation_name;
u64 animation_flags;
f64 animation_time_in_frame;
u64 animation_start_gen;
u64 animation_gen;
struct sheet_frame animation_frame;
/* ENTITY_PROP_ANIMATING */
b32 animation_looping;
f64 animation_start_time; /* Calculated */
/* ====================================================================== */
/* 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);
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

View File

@ -167,10 +167,11 @@ INTERNAL void game_update(void)
{
struct string sprite_name = STR("res/graphics/tim.ase");
struct string sprite_tag_name = STR("UNARMED");
struct sheet *sheet = sheet_load(sprite_name);
f32 meters_width = sheet->image_size.x / PIXELS_PER_UNIT;
f32 meters_height = sheet->image_size.y / PIXELS_PER_UNIT;
f32 meters_width = sheet->frame_size.x / PIXELS_PER_UNIT;
f32 meters_height = sheet->frame_size.y / PIXELS_PER_UNIT;
struct v2 sprite_size = V2(meters_width, meters_height);
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->sprite_name = sprite_name;
e->sprite_tag_name = sprite_tag_name;
e->sprite_trs = TRS(.s = sprite_size);
e->sprite_pivot_norm = V2(0, 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_acceleration = 15.0f;
entity_enable_prop(e, ENTITY_PROP_ANIMATING);
e->animation_looping = true;
player_ent = e;
//entity_enable_prop(e, ENTITY_PROP_TEST);
@ -205,7 +210,7 @@ INTERNAL void game_update(void)
entity_enable_prop(e, ENTITY_PROP_CAMERA);
e->camera_active = true;
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;
}
/* 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
* ========================== */
if (entity_has_prop(ent, ENTITY_PROP_SPRITE_ANIMATED)) {
struct sheet *sheet = sheet_load(ent->sprite_name);
struct sheet_tag tag = sheet_get_tag(sheet, ent->animation_name);
if (ent->animation_start_time > 0) {
/* Stop animation if past duration and not looping */
if (!ent->animation_looping) {
f64 time_in_anim = L.tick.time - ent->animation_start_time;
if (ent->animation_start_gen == ent->animation_gen) {
ent->animation_time_in_frame += L.tick.dt;
} else {
ent->animation_frame = sheet_get_frame(sheet, tag.start);
ent->animation_start_gen = ent->animation_gen;
}
struct sheet *sheet = sheet_load(ent->sprite_name);
if (sheet) {
struct sheet_tag tag = sheet_get_tag(sheet, ent->sprite_tag_name);
while (ent->animation_frame.duration != 0 && ent->animation_time_in_frame > ent->animation_frame.duration) {
u64 new_frame_index = ent->animation_frame.index + 1;
if (new_frame_index > tag.end) {
if (ent->animation_flags & ANIMATION_FLAG_LOOPING) {
/* Restart animation */
new_frame_index = tag.start;
} else {
/* End animation */
entity_start_animation(ent, STR("Default"), ANIMATION_FLAG_LOOPING);
goto break_animation;
struct sheet_frame frame = { 0 };
u64 frame_index = tag.start;
while (time_in_anim > 0) {
frame = sheet_get_frame(sheet, frame_index);
if (frame_index > tag.end) {
entity_disable_prop(ent, ENTITY_PROP_ANIMATING);
ent->animation_start_time = 0;
break;
}
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 */
if (entity_has_prop(ent, ENTITY_PROP_TEST)) {

View File

@ -331,6 +331,15 @@ INLINE struct v2 v2_norm(struct v2 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)
{
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 */
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_count = ase.num_frames;
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 v2 image_size;
struct v2 frame_size;
u32 frames_count;
struct sheet_frame *frames;
u32 tags_count;

View File

@ -226,7 +226,13 @@ INTERNAL struct mat3x3 view_get_xform(struct view view)
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));
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)
{
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) {
u32 tint = ent->sprite_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 = DRAW_TEXTURE_PARAMS(.texture = texture, .clip = frame.clip);
}
draw_texture_quad(L.world_canvas, params, quad);
}
@ -645,22 +673,18 @@ INTERNAL void user_update(void)
/* Debug draw info */
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);
//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) {
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 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);
@ -753,11 +777,21 @@ INTERNAL void user_update(void)
/* Present */
i32 vsync = VSYNC_ENABLED;
struct renderer_canvas *canvases[] = {
L.world_canvas,
L.ui_canvas
};
renderer_canvas_present(canvases, ARRAY_COUNT(canvases), L.screen_size.x, L.screen_size.y, vsync);
struct renderer_canvas **canvases = NULL;
u64 canvases_count = 0;
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);
}