player acceleration, debug draw & camera mode
This commit is contained in:
parent
a4dc273480
commit
c5d0f8b6ea
BIN
res/graphics/tim.ase
(Stored with Git LFS)
BIN
res/graphics/tim.ase
(Stored with Git LFS)
Binary file not shown.
@ -124,9 +124,9 @@ void app_entry_point(void)
|
||||
draw_startup();
|
||||
|
||||
/* Startup threaded systems */
|
||||
user_startup(&window);
|
||||
work_startup(worker_count);
|
||||
game_startup();
|
||||
user_startup(&window);
|
||||
playback_startup();
|
||||
|
||||
sys_window_show(&window);
|
||||
@ -139,9 +139,9 @@ void app_entry_point(void)
|
||||
* forcing process exit (to prevent process hanging in the background
|
||||
* when a thread gets stuck) */
|
||||
playback_shutdown();
|
||||
user_shutdown();
|
||||
game_shutdown();
|
||||
work_shutdown();
|
||||
user_shutdown();
|
||||
|
||||
/* Write window settings to file */
|
||||
struct sys_window_settings settings = sys_window_get_settings(&window);
|
||||
|
||||
@ -54,11 +54,12 @@ struct entity {
|
||||
/* ====================================================================== */
|
||||
/* Physics */
|
||||
|
||||
struct v2 acceleration;
|
||||
struct v2 velocity;
|
||||
f32 drag;
|
||||
|
||||
/* ENTITY_PROP_PLAYER_CONTROLLED */
|
||||
f32 player_acceleration_magnitude;
|
||||
f32 player_max_speed;
|
||||
f32 player_acceleration;
|
||||
|
||||
/* ====================================================================== */
|
||||
/* Sprite */
|
||||
|
||||
28
src/game.c
28
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;
|
||||
@ -187,8 +187,8 @@ INTERNAL void game_update(void)
|
||||
e->sprite_tint = COLOR_WHITE;
|
||||
|
||||
entity_enable_prop(e, ENTITY_PROP_PLAYER_CONTROLLED);
|
||||
e->player_acceleration_magnitude = 4.f;
|
||||
e->drag = 5;
|
||||
e->player_max_speed = 5.f;
|
||||
e->player_acceleration = 20.0f;
|
||||
|
||||
player_ent = e;
|
||||
|
||||
@ -326,19 +326,27 @@ break_animation:
|
||||
* ========================== */
|
||||
|
||||
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);
|
||||
f32 max_speed = ent->player_max_speed;
|
||||
f32 acceleration_rate = ent->player_acceleration;
|
||||
acceleration_rate = clamp_f32(acceleration_rate, 0, GAME_FPS); /* Can't integrate acceleration rate higher than FPS */
|
||||
struct v2 target_velocity = v2_mul(L.tick.player_move, max_speed);
|
||||
struct v2 target_acceleration = v2_sub(target_velocity, ent->velocity);
|
||||
ent->acceleration = v2_mul(target_acceleration, acceleration_rate);
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Apply velocity
|
||||
* Integrate acceleration & velocity
|
||||
* ========================== */
|
||||
|
||||
ent->rel_trs.t = v2_add(ent->rel_trs.t, ent->velocity);
|
||||
{
|
||||
f32 dt = (f32)L.tick.dt;
|
||||
|
||||
if (ent->drag > 0) {
|
||||
ent->velocity = v2_div(ent->velocity, ent->drag);
|
||||
/* Apply acceleration to velocity */
|
||||
struct v2 a = v2_mul(ent->acceleration, dt);
|
||||
ent->velocity = v2_add(ent->velocity, a);
|
||||
|
||||
/* Apply velocity to position */
|
||||
ent->rel_trs.t = v2_add(ent->rel_trs.t, v2_mul(ent->velocity, dt));
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
|
||||
157
src/user.c
157
src/user.c
@ -42,6 +42,9 @@ GLOBAL struct {
|
||||
b32 panning;
|
||||
struct v2 panning_from;
|
||||
|
||||
b32 debug_draw;
|
||||
b32 debug_camera;
|
||||
|
||||
/* User thread input */
|
||||
struct sys_mutex sys_events_mutex;
|
||||
struct arena sys_events_arena;
|
||||
@ -59,16 +62,28 @@ GLOBAL struct {
|
||||
* Bind state
|
||||
* ========================== */
|
||||
|
||||
struct bind_state {
|
||||
b32 pressed; /* Is this bind held down this frame */
|
||||
u32 num_presses; /* How many times was this bind pressed since last frame */
|
||||
};
|
||||
|
||||
GLOBAL struct bind_state g_bind_states[USER_BIND_KIND_COUNT] = { 0 };
|
||||
|
||||
/* 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
|
||||
};
|
||||
[SYS_BTN_D] = USER_BIND_KIND_MOVE_RIGHT,
|
||||
|
||||
GLOBAL b32 g_bind_state[USER_BIND_KIND_COUNT] = { 0 };
|
||||
/* Testing */
|
||||
|
||||
[SYS_BTN_F6] = USER_BIND_KIND_DEBUG_DRAW,
|
||||
[SYS_BTN_F7] = USER_BIND_KIND_DEBUG_CAMERA,
|
||||
[SYS_BTN_MWHEELUP] = USER_BIND_KIND_ZOOM_IN,
|
||||
[SYS_BTN_MWHEELDOWN] = USER_BIND_KIND_ZOOM_OUT
|
||||
};
|
||||
|
||||
/* ========================== *
|
||||
* Window -> user communication
|
||||
@ -246,6 +261,22 @@ INTERNAL void debug_draw_xform(struct mat3x3 mtx)
|
||||
draw_solid_quad(L.world_canvas, quad, color);
|
||||
}
|
||||
|
||||
/* TODO: remove this (testing) */
|
||||
INTERNAL void debug_draw_movement(struct entity *ent)
|
||||
{
|
||||
f32 thickness = 2.f / PIXELS_PER_UNIT / L.world_view.zoom;
|
||||
|
||||
u32 color_vel = RGBA_F(1, 0.5, 0, 1);
|
||||
u32 color_acc = RGBA_F(1, 1, 0.5, 1);
|
||||
|
||||
struct v2 pos = mat3x3_get_pos(ent->world_xform);
|
||||
struct v2 vel_ray = ent->velocity;
|
||||
struct v2 acc_ray = ent->acceleration;
|
||||
|
||||
draw_solid_ray(L.world_canvas, pos, vel_ray, thickness, color_vel);
|
||||
draw_solid_ray(L.world_canvas, pos, acc_ray, thickness, color_acc);
|
||||
}
|
||||
|
||||
INTERNAL void user_update(void)
|
||||
{
|
||||
struct temp_arena scratch = scratch_begin_no_conflict();
|
||||
@ -276,7 +307,13 @@ INTERNAL void user_update(void)
|
||||
* Read sys events
|
||||
* ========================== */
|
||||
|
||||
i32 input_zooms = 0;
|
||||
/* Reset bind states "was_pressed" */
|
||||
for (u32 i = 0; i < ARRAY_COUNT(g_bind_states); ++i) {
|
||||
g_bind_states[i] = (struct bind_state) {
|
||||
.pressed = g_bind_states[i].pressed
|
||||
};
|
||||
}
|
||||
|
||||
for (u64 entity_index = 0; entity_index < events.count; ++entity_index) {
|
||||
struct sys_event *event = &events.events[entity_index];
|
||||
|
||||
@ -299,15 +336,6 @@ INTERNAL void user_update(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* Zoom camera/view */
|
||||
if (event->kind == SYS_EVENT_KIND_BUTTON_DOWN) {
|
||||
if (event->button == SYS_BTN_MWHEELUP) {
|
||||
++input_zooms;
|
||||
} else if (event->button == SYS_BTN_MWHEELDOWN) {
|
||||
--input_zooms;
|
||||
}
|
||||
}
|
||||
|
||||
if (event->kind == SYS_EVENT_KIND_BUTTON_UP) {
|
||||
#if DEVELOPER
|
||||
/* Escape quit */
|
||||
@ -331,12 +359,16 @@ INTERNAL void user_update(void)
|
||||
}
|
||||
|
||||
/* Bind */
|
||||
if (event->kind == SYS_EVENT_KIND_BUTTON_DOWN || event->kind == SYS_EVENT_KIND_BUTTON_UP) {
|
||||
if ((event->kind == SYS_EVENT_KIND_BUTTON_DOWN || event->kind == SYS_EVENT_KIND_BUTTON_UP) && !event->is_repeat) {
|
||||
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;
|
||||
b32 pressed = event->kind == SYS_EVENT_KIND_BUTTON_DOWN;
|
||||
g_bind_states[bind].pressed = pressed;
|
||||
if (pressed) {
|
||||
++g_bind_states[bind].num_presses;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -353,6 +385,7 @@ INTERNAL void user_update(void)
|
||||
}
|
||||
|
||||
/* Zoom view */
|
||||
i32 input_zooms = g_bind_states[USER_BIND_KIND_ZOOM_IN].num_presses - g_bind_states[USER_BIND_KIND_ZOOM_OUT].num_presses;
|
||||
if (input_zooms != 0) {
|
||||
i32 dir = input_zooms >= 0 ? 1 : -1;
|
||||
u32 zooms_abs = input_zooms >= 0 ? input_zooms : -input_zooms;
|
||||
@ -377,15 +410,18 @@ INTERNAL void user_update(void)
|
||||
L.world_view.center = v2_add(L.world_view.center, offset);
|
||||
}
|
||||
|
||||
/* Process binds */
|
||||
/* Movement */
|
||||
{
|
||||
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) {
|
||||
for (enum user_bind_kind bind = 0; bind < (i32)ARRAY_COUNT(g_bind_states); ++bind) {
|
||||
struct bind_state state = g_bind_states[bind];
|
||||
|
||||
if (!state.pressed && state.num_presses <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (bind) {
|
||||
/* Movement */
|
||||
case USER_BIND_KIND_MOVE_UP: {
|
||||
input_move_dir.y -= 1;
|
||||
} break;
|
||||
@ -405,13 +441,19 @@ INTERNAL void user_update(void)
|
||||
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
|
||||
.dir = v2_norm(input_move_dir)
|
||||
});
|
||||
}
|
||||
|
||||
/* Debug */
|
||||
if (g_bind_states[USER_BIND_KIND_DEBUG_DRAW].num_presses > 0) {
|
||||
L.debug_draw = !L.debug_draw;
|
||||
}
|
||||
if (g_bind_states[USER_BIND_KIND_DEBUG_CAMERA].num_presses > 0) {
|
||||
L.debug_camera = !L.debug_camera;
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Produce interpolated tick
|
||||
@ -446,12 +488,15 @@ INTERNAL void user_update(void)
|
||||
e->rel_trs = trs_lerp(e0->rel_trs, e1->rel_trs, tick_blend);
|
||||
e->world_xform = mat3x3_lerp(e0->world_xform, e1->world_xform, tick_blend);
|
||||
|
||||
e->acceleration = v2_lerp(e0->acceleration, e1->acceleration, tick_blend);
|
||||
e->velocity = v2_lerp(e0->velocity, e1->velocity, tick_blend);
|
||||
e->player_acceleration = math_lerp_f32(e0->player_acceleration, e1->player_acceleration, tick_blend);
|
||||
|
||||
e->sprite_trs = trs_lerp(e0->sprite_trs, e1->sprite_trs, tick_blend);
|
||||
e->sprite_pivot_norm = v2_lerp(e0->sprite_pivot_norm, e1->sprite_pivot_norm, tick_blend);
|
||||
|
||||
e->camera_rot = math_lerp_angle(e0->camera_rot, e1->camera_rot, tick_blend);
|
||||
e->camera_zoom = math_lerp_f32(e0->camera_rot, e1->camera_rot, tick_blend);
|
||||
|
||||
e->camera_zoom = math_lerp_f32(e0->camera_zoom, e1->camera_zoom, tick_blend);
|
||||
}
|
||||
}
|
||||
#else
|
||||
@ -509,17 +554,17 @@ INTERNAL void user_update(void)
|
||||
struct entity *ent = &tick->entities[entity_index];
|
||||
if (!ent->valid) continue;
|
||||
|
||||
b32 is_camera = entity_has_prop(ent, ENTITY_PROP_CAMERA);
|
||||
|
||||
/* Update view */
|
||||
if (entity_has_prop(ent, ENTITY_PROP_CAMERA)) {
|
||||
if (ent->camera_active) {
|
||||
if (is_camera && ent->camera_active && !L.debug_camera) {
|
||||
struct v2 center = mat3x3_get_pos(ent->world_xform);
|
||||
f32 rot = ent->camera_rot;
|
||||
f32 zoom = ent->camera_zoom;
|
||||
zoom = zoom > 0 ? zoom : 1.0;
|
||||
zoom = zoom > 0 ? zoom : 1;
|
||||
L.world_view.center = center;
|
||||
L.world_view.rot = rot;
|
||||
L.world_view.zoom = 1;
|
||||
}
|
||||
L.world_view.zoom = zoom;
|
||||
}
|
||||
|
||||
/* Draw sprite */
|
||||
@ -550,6 +595,7 @@ INTERNAL void user_update(void)
|
||||
draw_texture_quad(L.world_canvas, params, quad);
|
||||
}
|
||||
|
||||
if (L.debug_draw && !is_camera) {
|
||||
#if 0
|
||||
/* Debug draw sprite quad */
|
||||
{
|
||||
@ -576,11 +622,14 @@ INTERNAL void user_update(void)
|
||||
draw_solid_circle(L.world_canvas, mat3x3_get_pos(mtx_pre_pivot), 0.02, color, 20);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Debug draw info */
|
||||
{
|
||||
if (L.debug_draw && !is_camera) {
|
||||
struct mat3x3 mtx = ent->world_xform;
|
||||
struct v2 bx = mat3x3_get_right(mtx);
|
||||
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);
|
||||
|
||||
@ -594,31 +643,30 @@ INTERNAL void user_update(void)
|
||||
|
||||
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"
|
||||
"sprite name: \"%F\"\n"
|
||||
"pos: (%F, %F)\n"
|
||||
"scale: (%F, %F)\n"
|
||||
"rot: %F\n"
|
||||
"velocity: (%F, %F)\n"
|
||||
"acceleration: (%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)
|
||||
FMT_FLOAT((f64)trs.t.x), FMT_FLOAT((f64)trs.t.y),
|
||||
FMT_FLOAT((f64)trs.s.x), FMT_FLOAT((f64)trs.s.y),
|
||||
FMT_FLOAT((f64)trs.r),
|
||||
FMT_FLOAT((f64)velocity.x), FMT_FLOAT((f64)velocity.y),
|
||||
FMT_FLOAT((f64)acceleration.x), FMT_FLOAT((f64)acceleration.y)
|
||||
);
|
||||
|
||||
|
||||
draw_text_ex(L.world_canvas, disp_font, pos, 1.0f / PIXELS_PER_UNIT, text);
|
||||
}
|
||||
}
|
||||
|
||||
/* Debug draw transform */
|
||||
{
|
||||
debug_draw_xform(ent->world_xform);
|
||||
debug_draw_movement(ent);
|
||||
}
|
||||
}
|
||||
|
||||
@ -636,34 +684,37 @@ INTERNAL void user_update(void)
|
||||
});
|
||||
|
||||
/* Debug draw info */
|
||||
{
|
||||
if (L.debug_draw) {
|
||||
f32 spacing = 20;
|
||||
struct v2 pos = V2(10, 8);
|
||||
struct font *font = font_load(STR("res/fonts/fixedsys.ttf"), 12.0f);
|
||||
|
||||
draw_text(L.ui_canvas, font, pos, string_format(scratch.arena, STR("L.time: %F"), FMT_FLOAT((f64)L.time)));
|
||||
draw_text(L.ui_canvas, font, pos, string_format(scratch.arena, STR("time: %F"), FMT_FLOAT((f64)L.time)));
|
||||
pos.y += spacing;
|
||||
|
||||
draw_text(L.ui_canvas, font, pos, string_format(scratch.arena, STR("L.screen_size: (%F, %F)"), FMT_FLOAT((f64)L.screen_size.x), FMT_FLOAT((f64)L.screen_size.y)));
|
||||
draw_text(L.ui_canvas, font, pos, string_format(scratch.arena, STR("screen_size: (%F, %F)"), FMT_FLOAT((f64)L.screen_size.x), FMT_FLOAT((f64)L.screen_size.y)));
|
||||
pos.y += spacing;
|
||||
|
||||
draw_text(L.ui_canvas, font, pos, string_format(scratch.arena, STR("L.screen_center: (%F, %F)"), FMT_FLOAT((f64)L.screen_center.x), FMT_FLOAT((f64)L.screen_center.y)));
|
||||
draw_text(L.ui_canvas, font, pos, string_format(scratch.arena, STR("screen_center: (%F, %F)"), FMT_FLOAT((f64)L.screen_center.x), FMT_FLOAT((f64)L.screen_center.y)));
|
||||
pos.y += spacing;
|
||||
|
||||
draw_text(L.ui_canvas, font, pos, string_format(scratch.arena, STR("L.screen_mouse: (%F, %F)"), FMT_FLOAT((f64)L.screen_mouse.x), FMT_FLOAT((f64)L.screen_mouse.y)));
|
||||
draw_text(L.ui_canvas, font, pos, string_format(scratch.arena, STR("screen_mouse: (%F, %F)"), FMT_FLOAT((f64)L.screen_mouse.x), FMT_FLOAT((f64)L.screen_mouse.y)));
|
||||
pos.y += spacing;
|
||||
|
||||
draw_text(L.ui_canvas, font, pos, string_format(scratch.arena, STR("L.world_view.center: (%F, %F)"), FMT_FLOAT((f64)L.world_view.center.x), FMT_FLOAT((f64)L.world_view.center.y)));
|
||||
draw_text(L.ui_canvas, font, pos, string_format(scratch.arena, STR("world_view.center: (%F, %F)"), FMT_FLOAT((f64)L.world_view.center.x), FMT_FLOAT((f64)L.world_view.center.y)));
|
||||
pos.y += spacing;
|
||||
|
||||
draw_text(L.ui_canvas, font, pos, string_format(scratch.arena, STR("L.world_view.rot: %F"), FMT_FLOAT((f64)L.world_view.rot)));
|
||||
draw_text(L.ui_canvas, font, pos, string_format(scratch.arena, STR("world_view.rot: %F"), FMT_FLOAT((f64)L.world_view.rot)));
|
||||
pos.y += spacing;
|
||||
|
||||
draw_text(L.ui_canvas, font, pos, string_format(scratch.arena, STR("L.world_view.zoom: %F"), FMT_FLOAT((f64)L.world_view.zoom)));
|
||||
draw_text(L.ui_canvas, font, pos, string_format(scratch.arena, STR("world_view.zoom: %F"), FMT_FLOAT((f64)L.world_view.zoom)));
|
||||
pos.y += spacing;
|
||||
|
||||
draw_text(L.ui_canvas, font, pos, string_format(scratch.arena, STR("world_mouse: (%F, %F)"), FMT_FLOAT((f64)world_mouse.x), FMT_FLOAT((f64)world_mouse.y)));
|
||||
pos.y += spacing;
|
||||
|
||||
draw_text(L.ui_canvas, font, pos, string_format(scratch.arena, STR("debug_camera: %F"), FMT_STR(L.debug_camera ? STR("true") : STR("false"))));
|
||||
pos.y += spacing;
|
||||
}
|
||||
|
||||
/* Push game cmds */
|
||||
|
||||
@ -11,6 +11,13 @@ enum user_bind_kind {
|
||||
USER_BIND_KIND_MOVE_LEFT,
|
||||
USER_BIND_KIND_MOVE_RIGHT,
|
||||
|
||||
/* Testing */
|
||||
|
||||
USER_BIND_KIND_DEBUG_DRAW,
|
||||
USER_BIND_KIND_DEBUG_CAMERA,
|
||||
USER_BIND_KIND_ZOOM_IN,
|
||||
USER_BIND_KIND_ZOOM_OUT,
|
||||
|
||||
USER_BIND_KIND_COUNT
|
||||
};
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user