From 48fef5ce2e8575658498d8748e2716c335b1c471 Mon Sep 17 00:00:00 2001 From: jacob Date: Tue, 5 Mar 2024 13:21:50 -0600 Subject: [PATCH] player movement --- CMakeLists.txt | 5 +- src/entity.h | 14 +++- src/game.c | 106 ++++++++++++------------- src/game.h | 10 ++- src/math.h | 16 +--- src/memory.h | 9 ++- src/tick.h | 3 +- src/user.c | 208 +++++++++++++++++++++++++------------------------ src/user.h | 11 +++ 9 files changed, 202 insertions(+), 180 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1af52dc1..c8f9ec15 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -185,13 +185,13 @@ if (CRTLIB) set(COMPILER_FLAGS "${COMPILER_FLAGS} -DCRTLIB=1") else() set(COMPILER_FLAGS "${COMPILER_FLAGS} -mno-stack-arg-probe -fno-builtin") - set(LINKER_FLAGS "${LINKER_FLAGS} -nostdlib") + set(LINKER_FLAGS "${LINKER_FLAGS} -nostdlib") endif() # Optimization if (UNOPTIMIZED) set(COMPILER_FLAGS "${COMPILER_FLAGS} -O0 -DUNOPTIMIZED=1") - set(LINKER_FLAGS "${LINKER_FLAGS} -O0 -DUNOPTIMIZED=1") + set(LINKER_FLAGS "${LINKER_FLAGS} -O0") else() set(COMPILER_FLAGS "${COMPILER_FLAGS} -O3 -flto") set(LINKER_FLAGS "${LINKER_FLAGS} -O3 -flto -fwhole-program") @@ -200,6 +200,7 @@ endif() # Debug info if (DEBINFO) set(COMPILER_FLAGS "${COMPILER_FLAGS} -g -DDEBINFO=1") + set(LINKER_FLAGS "${LINKER_FLAGS} -g") endif() # Developer mode diff --git a/src/entity.h b/src/entity.h index 7c127ebd..c04c509c 100644 --- a/src/entity.h +++ b/src/entity.h @@ -51,6 +51,15 @@ struct entity { struct mat3x3 world_xform; /* Calculated post-physics */ + /* ====================================================================== */ + /* Physics */ + + struct v2 velocity; + f32 drag; + + /* ENTITY_PROP_PLAYER_CONTROLLED */ + f32 player_acceleration_magnitude; + /* ====================================================================== */ /* Sprite */ @@ -71,15 +80,14 @@ struct entity { struct sheet_frame animation_frame; /* ====================================================================== */ - /* ENTITY_PROP_TEST */ + /* Testing */ + /* ENTITY_PROP_TEST */ b32 test_initialized; struct trs test_start_rel_trs; struct trs test_start_sprite_trs; - /* ====================================================================== */ /* ENTITY_PROP_TEST_SOUND_EMITTER */ - struct string sound_name; struct mixer_desc sound_desc; struct mixer_track_handle sound_handle; diff --git a/src/game.c b/src/game.c index 3f0443b2..50dab81e 100644 --- a/src/game.c +++ b/src/game.c @@ -10,7 +10,7 @@ #include "math.h" #include "scratch.h" -#define GAME_FPS 50 +#define GAME_FPS 30 GLOBAL struct { b32 shutdown; @@ -164,8 +164,9 @@ INTERNAL void game_update(void) run = 1; /* Player ent */ - struct entity *player_ent; { + (UNUSED)entity_tree_attach; + struct string sprite_name = STR("res/graphics/timmy.ase"); struct sheet *sheet = sheet_load(sprite_name); @@ -177,65 +178,20 @@ INTERNAL void game_update(void) struct entity *e = entity_alloc(); e->active = true; - e->rel_trs = TRS(.t = pos, .r = PI / 4, .s = V2(2, 1)); + e->rel_trs = TRS(.t = pos, .r = 0, .s = V2(1, 1)); e->sprite_name = sprite_name; e->sprite_trs = TRS(.s = sprite_size); e->sprite_pivot_norm = V2(0, 0.65); e->sprite_tint = COLOR_WHITE; - //entity_enable_prop(e, ENTITY_PROP_TEST); - entity_enable_prop(e, ENTITY_PROP_TEST_FOLLOW_MOUSE); + entity_enable_prop(e, ENTITY_PROP_PLAYER_CONTROLLED); + e->player_acceleration_magnitude = 5.0f; + e->drag = 2.0; - player_ent = e; - } - - /* Child ent */ - struct entity *child_ent; - { - struct string sprite_name = STR("res/graphics/timmy.ase"); - - struct v2 sprite_size = V2(1, 1); - struct v2 pos = V2(2, 2); - - struct entity *e = entity_alloc(); - e->active = true; - e->rel_trs = TRS(.t = pos, .r = 0, .s = V2(1, 1)); - - e->sprite_name = sprite_name; - e->sprite_trs = TRS(.s = sprite_size); - //e->sprite_pivot_norm = V2(0, 0.65); - e->sprite_tint = RGBA_F(1, 0, 0, 0.5); - - entity_enable_prop(e, ENTITY_PROP_TEST); - //entity_enable_prop(e, ENTITY_PROP_TEST_FOLLOW_MOUSE); - - entity_tree_attach(player_ent, e); - - child_ent = e; - } - - /* Child ent 2 */ - { - struct string sprite_name = STR("res/graphics/timmy.ase"); - - struct v2 sprite_size = V2(1, 1); - - struct v2 pos = V2(0, -1); - - struct entity *e = entity_alloc(); - e->active = true; - e->rel_trs = TRS(.t = pos, .r = PI / 2, .s = V2(1, 1)); - - e->sprite_name = sprite_name; - e->sprite_trs = TRS(.s = sprite_size); - //e->sprite_pivot_norm = V2(0, 0.65); - e->sprite_tint = RGBA_F(0, 1, 0, 0.2); //entity_enable_prop(e, ENTITY_PROP_TEST); //entity_enable_prop(e, ENTITY_PROP_TEST_FOLLOW_MOUSE); - - entity_tree_attach(child_ent, e); } } @@ -248,7 +204,18 @@ INTERNAL void game_update(void) struct game_cmd cmd = game_cmds.cmds[i]; switch (cmd.kind) { - case GAME_CMD_KIND_SET_PLAYER_FOCUS: { + /* Movement */ + case GAME_CMD_KIND_PLAYER_MOVE: { + struct v2 dir = cmd.dir; + if (v2_len(dir) > 1.f) { + /* Clamp magnitude */ + dir = v2_norm(dir); + } + L.tick.player_move = dir; + } break; + + /* Focus */ + case GAME_CMD_KIND_PLAYER_FOCUS: { L.tick.player_focus = cmd.pos; } break; @@ -339,6 +306,38 @@ break_animation: if (!ent->active) continue; if (entity_is_valid(ent->parent)) continue; /* Only update parent entities */ + /* ========================== * + * Player movement + * ========================== */ + + if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) { + f32 acc_magnitude = ent->player_acceleration_magnitude * (f32)L.tick.dt; + struct v2 acc = v2_mul(L.tick.player_move, acc_magnitude); + ent->velocity = v2_add(ent->velocity, acc); + } + + /* ========================== * + * Apply velocity + * ========================== */ + + ent->rel_trs.t = v2_add(ent->rel_trs.t, ent->velocity); + + if (ent->drag > 0) { + ent->velocity = v2_div(ent->velocity, ent->drag); + } + + /* ========================== * + * Player look direction + * ========================== */ + + if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) { + struct v2 look_pos = L.tick.player_focus; + struct v2 look_dir = v2_sub(ent->rel_trs.t, look_pos); + look_dir = v2_norm(look_dir); + f32 r = math_atan2(look_dir.y, look_dir.x); + ent->rel_trs.r = -r; + } + /* ========================== * * Update position from mouse * ========================== */ @@ -350,8 +349,9 @@ break_animation: } /* ========================== * - * Calculate tree trs + * Calculate xforms * ========================== */ + ent->world_xform = mat3x3_from_trs(ent->rel_trs); struct entity *child = entity_from_handle(ent->first); diff --git a/src/game.h b/src/game.h index 6a64af7a..c5817c10 100644 --- a/src/game.h +++ b/src/game.h @@ -6,16 +6,20 @@ struct tick; enum game_cmd_kind { GAME_CMD_KIND_NONE, - GAME_CMD_KIND_SET_PLAYER_FOCUS, + GAME_CMD_KIND_PLAYER_MOVE, + + GAME_CMD_KIND_PLAYER_FOCUS, GAME_CMD_KIND_COUNT }; struct game_cmd { enum game_cmd_kind kind; - b32 state; /* 1 = start, 0 = stop */ - /* GAME_CMD_KIND_SET_PLAYER_FOCUS */ + /* GAME_CMD_KIND_PLAYER_MOVE */ + struct v2 dir; + + /* GAME_CMD_KIND_PLAYER_FOCUS */ struct v2 pos; }; diff --git a/src/math.h b/src/math.h index 9d6f773d..bd2b4fb9 100644 --- a/src/math.h +++ b/src/math.h @@ -249,10 +249,8 @@ INLINE f32 math_atan2(f32 x, f32 y) { res = swap ? (s >= 0.0f ? (PI / 2.f) : -(PI / 2.f)) - res : res; /* Adjust quadrants */ - if (x >= 0.0f && y >= 0.0f) {} /* 1st quadrant */ - else if (x < 0.0f && y >= 0.0f) { res = PI + res; } /* 2nd quadrant */ - else if (x < 0.0f && y < 0.0f) { res = -PI + res; } /* 3rd quadrant */ - else if (x >= 0.0f && y < 0.0f) {} /* 4th quadrant */ + if (x < 0.0f && y >= 0.0f) { res = PI + res; } /* 2nd quadrant */ + else if (x <= 0.0f && y < 0.0f) { res = -PI + res; } /* 3rd quadrant */ return res; } @@ -678,16 +676,6 @@ INLINE struct trs trs_from_mat3x3(struct mat3x3 m) trs.t = mat3x3_get_pos(m); trs.r = mat3x3_get_rot(m); trs.s = mat3x3_get_scale(m); - - trs.t = V2(m.e[2][0], m.e[2][1]); - - struct v2 bx = V2(m.e[0][0], m.e[0][1]); - struct v2 by = V2(m.e[1][0], m.e[1][1]); - - trs.s = V2(v2_len(bx), v2_len(by)); - - trs.r = math_atan2(bx.x, bx.y); - return trs; } diff --git a/src/memory.h b/src/memory.h index eca510b6..47825d9f 100644 --- a/src/memory.h +++ b/src/memory.h @@ -1,10 +1,6 @@ #ifndef MEMORY_H #define MEMORY_H -#if CRTLIB -# include -#endif - #define MEMZERO_STRUCT(ptr) MEMZERO(ptr, sizeof(*ptr)) #define MEMZERO_ARRAY(a) MEMZERO(a, sizeof(a)) #define MEMZERO(ptr, count) MEMSET(ptr, 0, count) @@ -12,7 +8,12 @@ #define MEMCPY(dest, src, count) memcpy(dest, src, count) #define MEMSET(ptr, val, count) memset(ptr, val, count) + +#if CRTLIB +# include +#else void *memcpy(void *__restrict dest, const void *__restrict src, u64 n); void *memset(void *dest, int c, u64 n); +#endif #endif diff --git a/src/tick.h b/src/tick.h index 54110483..03aeacf8 100644 --- a/src/tick.h +++ b/src/tick.h @@ -10,7 +10,8 @@ struct tick { f64 dt; f64 time; - struct v2 player_focus; /* Mouse cursor pos in world coordinates */ + struct v2 player_move; /* Player movement direction */ + struct v2 player_focus; /* Mouse cursor pos in world coordinates */ u64 entities_count; /* Includes 'released' & non-active entities */ struct entity entities[MAX_ENTITIES]; diff --git a/src/user.c b/src/user.c index 354293cd..f7434dad 100644 --- a/src/user.c +++ b/src/user.c @@ -54,6 +54,22 @@ GLOBAL struct { struct v2 screen_mouse; } L = { 0 } DEBUG_LVAR(L_user); + +/* ========================== * + * Bind state + * ========================== */ + +/* TODO: Remove this */ + +GLOBAL enum user_bind_kind g_binds[SYS_BTN_COUNT] = { + [SYS_BTN_W] = USER_BIND_KIND_MOVE_UP, + [SYS_BTN_S] = USER_BIND_KIND_MOVE_DOWN, + [SYS_BTN_A] = USER_BIND_KIND_MOVE_LEFT, + [SYS_BTN_D] = USER_BIND_KIND_MOVE_RIGHT +}; + +GLOBAL b32 g_bind_state[USER_BIND_KIND_COUNT] = { 0 }; + /* ========================== * * Window -> user communication * ========================== */ @@ -260,7 +276,7 @@ INTERNAL void user_update(void) * Read sys events * ========================== */ - i32 zooms_to_apply = 0; + i32 input_zooms = 0; for (u64 entity_index = 0; entity_index < events.count; ++entity_index) { struct sys_event *event = &events.events[entity_index]; @@ -286,9 +302,9 @@ INTERNAL void user_update(void) /* Zoom camera/view */ if (event->kind == SYS_EVENT_KIND_BUTTON_DOWN) { if (event->button == SYS_BTN_MWHEELUP) { - ++zooms_to_apply; + ++input_zooms; } else if (event->button == SYS_BTN_MWHEELDOWN) { - --zooms_to_apply; + --input_zooms; } } @@ -313,8 +329,22 @@ INTERNAL void user_update(void) } } } + + /* Bind */ + if (event->kind == SYS_EVENT_KIND_BUTTON_DOWN || event->kind == SYS_EVENT_KIND_BUTTON_UP) { + enum sys_btn button = event->button; + button = button >= SYS_BTN_COUNT ? SYS_BTN_NONE : button; + enum user_bind_kind bind = g_binds[button]; + if (bind) { + g_bind_state[bind] = event->kind == SYS_EVENT_KIND_BUTTON_DOWN; + } + } } + /* ========================== * + * Process input + * ========================== */ + /* Pan view */ if (L.panning) { struct v2 offset = v2_sub(L.panning_from, view_mouse_pos(L.world_view)); @@ -323,9 +353,9 @@ INTERNAL void user_update(void) } /* Zoom view */ - if (zooms_to_apply != 0) { - i32 dir = zooms_to_apply >= 0 ? 1 : -1; - u32 zooms_abs = zooms_to_apply >= 0 ? zooms_to_apply : -zooms_to_apply; + if (input_zooms != 0) { + i32 dir = input_zooms >= 0 ? 1 : -1; + u32 zooms_abs = input_zooms >= 0 ? input_zooms : -input_zooms; /* Zoom camera/view */ f32 zoom_rate = 2; @@ -347,6 +377,46 @@ INTERNAL void user_update(void) L.world_view.center = v2_add(L.world_view.center, offset); } + /* Process binds */ + struct v2 input_move_dir = { 0 }; + for (enum user_bind_kind bind = 0; bind < (i32)ARRAY_COUNT(g_bind_state); ++bind) { + b32 state = g_bind_state[bind]; + if (!state) { + continue; + } + + switch (bind) { + case USER_BIND_KIND_MOVE_UP: { + input_move_dir.y -= 1; + } break; + + case USER_BIND_KIND_MOVE_DOWN: { + input_move_dir.y += 1; + } break; + + case USER_BIND_KIND_MOVE_LEFT: { + input_move_dir.x -= 1; + } break; + + case USER_BIND_KIND_MOVE_RIGHT: { + input_move_dir.x += 1; + } break; + + default: break; + } + } + input_move_dir = v2_norm(input_move_dir); + + /* Queue move cmd */ + queue_game_cmd(&cmd_list, (struct game_cmd) { + .kind = GAME_CMD_KIND_PLAYER_MOVE, + .dir = input_move_dir + }); + + /* ========================== * + * Produce interpolated tick + * ========================== */ + /* Pull ticks */ struct interp_ticks interp_ticks = pull_interp_ticks(); struct tick *t0 = interp_ticks.from_tick; @@ -385,7 +455,6 @@ INTERNAL void user_update(void) //DEBUGBREAK; } - e->world_xform = mat3x3_lerp(e0->world_xform, e1->world_xform, blend); } } @@ -409,7 +478,6 @@ INTERNAL void user_update(void) i64 rows = 20; i64 cols = 20; - /* Draw column lines */ struct v2 col_ray = V2(0, rows); for (i64 col = starty; col <= (starty + cols); ++col) { @@ -433,71 +501,6 @@ INTERNAL void user_update(void) } } -#if 1 - /* Draw math functions */ - { - u32 detail = 1000; - - f32 thickness = 2.f / PIXELS_PER_UNIT / L.world_view.zoom; - - /* sin */ - { - u32 color = COLOR_RED; - f32 x_start = -10; - f32 x_end = 10; - struct v2_array v = { .points = arena_push_array(scratch.arena, struct v2, detail), .count = detail }; - for (u32 i = 0; i < detail; ++i) { - f32 x = x_start + ((x_end - x_start) * (i / ((f32)detail - 1))); - f32 y = math_sin(x); - v.points[i] = V2(x, -y); - } - draw_solid_poly_line(L.world_canvas, v, false, thickness, color); - } - - /* arcsin */ - { - u32 color = COLOR_BLUE; - f32 x_start = -1; - f32 x_end = 1; - struct v2_array v = { .points = arena_push_array(scratch.arena, struct v2, detail), .count = detail }; - for (u32 i = 0; i < detail; ++i) { - f32 x = x_start + ((x_end - x_start) * (i / ((f32)detail - 1))); - f32 y = math_asin(x); - v.points[i] = V2(x, -y); - } - draw_solid_poly_line(L.world_canvas, v, false, thickness, color); - } - - /* arccos */ - { - u32 color = COLOR_GREEN; - f32 x_start = -1; - f32 x_end = 1; - struct v2_array v = { .points = arena_push_array(scratch.arena, struct v2, detail), .count = detail }; - for (u32 i = 0; i < detail; ++i) { - f32 x = x_start + ((x_end - x_start) * (i / ((f32)detail - 1))); - f32 y = math_acos(x); - v.points[i] = V2(x, -y); - } - draw_solid_poly_line(L.world_canvas, v, false, thickness, color); - } - - /* arctan */ - { - u32 color = COLOR_BLACK; - f32 x_start = -10; - f32 x_end = 10; - struct v2_array v = { .points = arena_push_array(scratch.arena, struct v2, detail), .count = detail }; - for (u32 i = 0; i < detail; ++i) { - f32 x = x_start + ((x_end - x_start) * (i / ((f32)detail - 1))); - f32 y = math_atan2(1, x); - v.points[i] = V2(x, -y); - } - draw_solid_poly_line(L.world_canvas, v, false, thickness, color); - } - } -#endif - /* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ @@ -579,39 +582,45 @@ INTERNAL void user_update(void) draw_solid_circle(L.world_canvas, mat3x3_get_pos(mtx_pre_pivot), 0.02, color, 20); } + } -#if 0 - /* Debug draw sprite info */ - if (entity_has_prop(ent, ENTITY_PROP_TEST)) { - struct font *disp_font = font_load_async(STR("res/fonts/fixedsys.ttf"), 12.0f); + /* Debug draw info */ + { + struct mat3x3 mtx = ent->world_xform; + struct v2 bx = mat3x3_get_right(mtx); - f32 offset = 0.3; + struct font *disp_font = font_load_async(STR("res/fonts/fixedsys.ttf"), 12.0f); - struct v2 dir = v2_mul(mat3x3_get_up(mtx), 0.5f); - dir = v2_add(dir, v2_mul(v2_norm(dir), offset)); + f32 offset = 0.75; - struct v2 pos = v2_add(mat3x3_get_pos(mtx), dir); + 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); - if (disp_font) { - struct string disp_name = { .len = tex_name.len - 13, .text = tex_name.text + 13 }; - - struct string fmt = STR( - "sprite name: %F,\n" - "rel rot: %F,\n" - "sprite rot: %F\n" - ); - struct string text = string_format(scratch.arena, fmt, - FMT_STR(disp_name), - FMT_FLOAT((f64)ent->world_trs.r), - FMT_FLOAT((f64)ent->sprite_trs.r) - ); - - - draw_text_ex(L.world_canvas, disp_font, pos, 1.0f / PIXELS_PER_UNIT, text); + if (disp_font) { + struct string disp_name = ent->sprite_name; + if (disp_name.len > 13) { + disp_name = (struct string) { .len = disp_name.len - 13, .text = disp_name.text + 13 }; } + + struct string fmt = STR( + "sprite name: %F,\n" + "rel rot: %F,\n" + "mtx rot: %F,\n" + "mtx bx: %F, %F\n" + ); + struct string text = string_format(scratch.arena, fmt, + FMT_STR(disp_name), + FMT_FLOAT((f64)ent->rel_trs.r), + FMT_FLOAT((f64)trs_from_mat3x3(mtx).r), + FMT_FLOAT((f64)bx.x), FMT_FLOAT((f64)bx.y) + ); + + + draw_text_ex(L.world_canvas, disp_font, pos, 1.0f / PIXELS_PER_UNIT, text); } -#endif } /* Debug draw transform */ @@ -629,8 +638,7 @@ INTERNAL void user_update(void) /* Send world mouse pos */ struct v2 world_mouse = view_mouse_pos(L.world_view); queue_game_cmd(&cmd_list, (struct game_cmd) { - .kind = GAME_CMD_KIND_SET_PLAYER_FOCUS, - .state = true, + .kind = GAME_CMD_KIND_PLAYER_FOCUS, .pos = world_mouse }); diff --git a/src/user.h b/src/user.h index 37fdc5dc..5e4d394a 100644 --- a/src/user.h +++ b/src/user.h @@ -3,6 +3,17 @@ struct sys_window; +enum user_bind_kind { + USER_BIND_KIND_NONE, + + USER_BIND_KIND_MOVE_UP, + USER_BIND_KIND_MOVE_DOWN, + USER_BIND_KIND_MOVE_LEFT, + USER_BIND_KIND_MOVE_RIGHT, + + USER_BIND_KIND_COUNT +}; + void user_startup(struct sys_window *window); void user_shutdown(void);