use cursor position as aim direction

This commit is contained in:
jacob 2024-03-15 16:52:40 -05:00
parent 39f7b09036
commit 744a6f8d65
6 changed files with 119 additions and 131 deletions

View File

@ -28,5 +28,3 @@
#define AUDIO_ENABLED 0 #define AUDIO_ENABLED 0
#define VSYNC_ENABLED 0 #define VSYNC_ENABLED 0
#define MOUSE_SENSITIVITY 1

View File

@ -60,7 +60,7 @@ struct entity {
/* ENTITY_PROP_PLAYER_CONTROLLED */ /* ENTITY_PROP_PLAYER_CONTROLLED */
f32 player_max_speed; f32 player_max_speed;
f32 player_acceleration; f32 player_acceleration;
struct v2 player_focus_dir; struct v2 player_aim;
/* ====================================================================== */ /* ====================================================================== */
/* Sprite */ /* Sprite */

View File

@ -121,7 +121,7 @@ INTERNAL void game_update(void)
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;
e->player_acceleration = 20.0f; e->player_acceleration = 20.0f;
e->player_focus_dir = V2(0, -1); e->player_aim = V2(0, -1);
entity_enable_prop(e, ENTITY_PROP_ANIMATING); entity_enable_prop(e, ENTITY_PROP_ANIMATING);
@ -238,8 +238,6 @@ INTERNAL void game_update(void)
* Process game cmds * Process game cmds
* ========================== */ * ========================== */
L.world.player_focus_move_dir = V2(0, 0);
struct game_cmd_array game_cmds = pop_cmds(scratch.arena); struct game_cmd_array game_cmds = pop_cmds(scratch.arena);
for (u64 cmd_index = 0; cmd_index < game_cmds.count; ++cmd_index) { for (u64 cmd_index = 0; cmd_index < game_cmds.count; ++cmd_index) {
struct game_cmd cmd = game_cmds.cmds[cmd_index]; struct game_cmd cmd = game_cmds.cmds[cmd_index];
@ -248,7 +246,7 @@ INTERNAL void game_update(void)
/* Movement */ /* Movement */
case GAME_CMD_KIND_PLAYER_MOVE: { case GAME_CMD_KIND_PLAYER_MOVE: {
L.world.player_move_dir = cmd.move_dir; L.world.player_move_dir = cmd.move_dir;
L.world.player_focus_move_dir = v2_add(L.world.player_focus_move_dir, cmd.focus_move_dir); L.world.player_aim = cmd.aim;
} break; } break;
/* Clear level */ /* Clear level */
@ -385,16 +383,16 @@ INTERNAL void game_update(void)
} }
/* ========================== * /* ========================== *
* Player focus * Player aim
* ========================== */ * ========================== */
if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) { if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) {
/* Update focus */ /* Update aim */
ent->player_focus_dir = v2_add(ent->player_focus_dir, L.world.player_focus_move_dir); ent->player_aim = L.world.player_aim;
/* Update view angle */ /* Update view angle */
struct v2 ent_pos = ent->rel_xform.og; struct v2 ent_pos = ent->rel_xform.og;
struct v2 look_pos = v2_add(ent_pos, ent->player_focus_dir); struct v2 look_pos = v2_add(ent_pos, ent->player_aim);
f32 r = v2_angle_to_point(ent_pos, look_pos) + PI / 2; f32 r = v2_angle_to_point(ent_pos, look_pos) + PI / 2;
ent->rel_xform = xform_with_rotation(ent->rel_xform, r); ent->rel_xform = xform_with_rotation(ent->rel_xform, r);
} }
@ -460,26 +458,27 @@ INTERNAL void game_update(void)
ent->camera_target_xform = xform_with_scale(ent->camera_target_xform, V2(1, 1)); ent->camera_target_xform = xform_with_scale(ent->camera_target_xform, V2(1, 1));
if (entity_has_prop(follow, ENTITY_PROP_PLAYER_CONTROLLED)) { if (entity_has_prop(follow, ENTITY_PROP_PLAYER_CONTROLLED)) {
#if 1 #if 0
/* Regular style camera */ /* Regular style camera */
f32 target_dist_x = 0.5; f32 target_dist_x = 0.5;
f32 target_dist_y = target_dist_x * (16.0f / 9.0f); //f32 target_dist_y = target_dist_x * (16.0f / 9.0f);
struct v2 focus_dir = follow->player_focus_dir; f32 target_dist_y = target_dist_x;
struct v2 target_dir = v2_mul_v2(v2_norm(focus_dir), V2(target_dist_x, target_dist_y)); struct v2 target_dir = v2_mul_v2(v2_norm(follow->player_aim), V2(target_dist_x, target_dist_y));
struct v2 target_pos = v2_add(ent->camera_target_xform.og, target_dir); struct v2 target_pos = v2_add(ent->camera_target_xform.og, target_dir);
ent->camera_target_xform.og = target_pos; ent->camera_target_xform.og = target_pos;
#else #else
/* "Look" style camera */ /* "Look" style camera */
struct v2 focus_dir = follow->player_focus_dir; f32 ratio_x = 0.33f;
struct v2 focus_half_dir = v2_mul(focus_dir, 0.5f); f32 ratio_y = 0.33f;
struct v2 focus_half_pos = v2_add(follow->world_xform.og, focus_half_dir); struct v2 camera_focus_dir = v2_mul_v2(follow->player_aim, V2(ratio_x, ratio_y));
ent->camera_target_xform.og = focus_half_pos; struct v2 camera_focus_pos = v2_add(follow->world_xform.og, camera_focus_dir);
ent->camera_target_xform.og = camera_focus_pos;
#endif #endif
} }
/* Lerp camera */ /* Lerp camera */
if (ent->camera_applied_lerp_gen_plus_one == ent->camera_lerp_gen + 1) { if (ent->camera_applied_lerp_gen_plus_one == ent->camera_lerp_gen + 1) {
f32 t = 1 - math_pow(2.f, -10.f * (f32)L.world.dt); f32 t = 1 - math_pow(2.f, -20.f * (f32)L.world.dt);
ent->rel_xform = xform_lerp(ent->rel_xform, ent->camera_target_xform, t); ent->rel_xform = xform_lerp(ent->rel_xform, ent->camera_target_xform, t);
} else { } else {
/* Skip lerp */ /* Skip lerp */

View File

@ -19,7 +19,7 @@ struct game_cmd {
/* GAME_CMD_KIND_PLAYER_MOVE */ /* GAME_CMD_KIND_PLAYER_MOVE */
struct v2 move_dir; struct v2 move_dir;
struct v2 focus_move_dir; struct v2 aim;
}; };
struct game_cmd_array { struct game_cmd_array {

View File

@ -14,9 +14,6 @@
#include "sys.h" #include "sys.h"
#include "world.h" #include "world.h"
#include "entity.h" #include "entity.h"
/* FIXME: remove this (testing) */
#include "sound.h"
#include "mixer.h" #include "mixer.h"
struct bind_state { struct bind_state {
@ -67,7 +64,6 @@ GLOBAL struct {
struct v2 screen_cursor; struct v2 screen_cursor;
struct v2 world_cursor; struct v2 world_cursor;
struct v2 mouse_delta; struct v2 mouse_delta;
struct v2 last_focus_screen_pos;
} L = { 0 }, DEBUG_LVAR(L_user); } L = { 0 }, DEBUG_LVAR(L_user);
/* ========================== * /* ========================== *
@ -406,7 +402,7 @@ INTERNAL void user_update(void)
e->acceleration = v2_lerp(e0->acceleration, e1->acceleration, tick_blend); e->acceleration = v2_lerp(e0->acceleration, e1->acceleration, tick_blend);
e->velocity = v2_lerp(e0->velocity, e1->velocity, tick_blend); e->velocity = v2_lerp(e0->velocity, e1->velocity, tick_blend);
e->player_acceleration = math_lerp(e0->player_acceleration, e1->player_acceleration, tick_blend); e->player_acceleration = math_lerp(e0->player_acceleration, e1->player_acceleration, tick_blend);
e->player_focus_dir = v2_lerp(e0->player_focus_dir, e1->player_focus_dir, tick_blend); e->player_aim = v2_lerp(e0->player_aim, e1->player_aim, tick_blend);
e->sprite_xform = xform_lerp(e0->sprite_xform, e1->sprite_xform, tick_blend); e->sprite_xform = xform_lerp(e0->sprite_xform, e1->sprite_xform, tick_blend);
e->animation_time_in_frame = math_lerp_f64(e0->animation_time_in_frame, e1->animation_time_in_frame, (f64)tick_blend); e->animation_time_in_frame = math_lerp_f64(e0->animation_time_in_frame, e1->animation_time_in_frame, (f64)tick_blend);
@ -421,9 +417,30 @@ INTERNAL void user_update(void)
tick_is_first_frame = L.world.tick_id == 0; tick_is_first_frame = L.world.tick_id == 0;
#endif #endif
} }
struct entity_array entities_array = entity_store_as_array(&L.world.entity_store); struct entity_array entities_array = entity_store_as_array(&L.world.entity_store);
/* ========================== *
* Find important entities
* ========================== */
struct entity *player = entity_nil();
struct entity *active_camera = entity_nil();
for (u64 entity_index = 0; entity_index < entities_array.count; ++entity_index) {
struct entity *ent = &entities_array.entities[entity_index];
if (!ent->valid) continue;
/* Player */
if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) {
player = ent;
}
/* Active camera */
if (entity_has_prop(ent, ENTITY_PROP_CAMERA) && entity_has_prop(ent, ENTITY_PROP_CAMERA_ACTIVE)) {
active_camera = ent;
}
}
/* ========================== * /* ========================== *
* Read sys events * Read sys events
* ========================== */ * ========================== */
@ -460,21 +477,6 @@ INTERNAL void user_update(void)
#endif #endif
} }
#if 0
/* Text */
if (event->kind == SYS_EVENT_KIND_TEXT) {
/* TODO: remove this (sound test) */
{
//u32 flags = SOUND_FLAG_STEREO;
u32 flags = 0;
struct sound *sound = sound_load(STR("res/sounds/test.mp3"), flags);
if (sound) {
mixer_play_ex(sound, MIXER_DESC(.volume = 1.0, .speed = 1.0));
}
}
}
#endif
/* Update mouse pos */ /* Update mouse pos */
if (event->kind == SYS_EVENT_KIND_CURSOR_MOVE) { if (event->kind == SYS_EVENT_KIND_CURSOR_MOVE) {
L.screen_cursor = event->cursor_position; L.screen_cursor = event->cursor_position;
@ -527,10 +529,6 @@ INTERNAL void user_update(void)
} }
if (L.bind_states[USER_BIND_KIND_DEBUG_CAMERA].num_presses > 0) { if (L.bind_states[USER_BIND_KIND_DEBUG_CAMERA].num_presses > 0) {
if (!L.debug_camera) {
/* Move cursor to last crosshair pos */
sys_window_cursor_set_pos(L.window, L.last_focus_screen_pos);
}
L.debug_camera = !L.debug_camera; L.debug_camera = !L.debug_camera;
} }
@ -579,16 +577,9 @@ INTERNAL void user_update(void)
sys_window_cursor_hide(L.window); sys_window_cursor_hide(L.window);
sys_window_cursor_enable_keep_in_window(L.window); sys_window_cursor_enable_keep_in_window(L.window);
enum entity_prop props[] = { ENTITY_PROP_CAMERA, ENTITY_PROP_CAMERA_ACTIVE }; struct v2 center = active_camera->world_xform.og;
struct entity_prop_array props_array = { f32 rot = xform_get_rotation(active_camera->world_xform);
.props = props, f32 zoom = active_camera->camera_zoom;
.count = ARRAY_COUNT(props)
};
struct entity *ent = entity_find_first_match_all(&L.world.entity_store, props_array);
struct v2 center = ent->world_xform.og;
f32 rot = xform_get_rotation(ent->world_xform);
f32 zoom = ent->camera_zoom;
zoom = zoom > 0 ? zoom : 1; zoom = zoom > 0 ? zoom : 1;
struct trs trs = TRS( struct trs trs = TRS(
@ -615,57 +606,6 @@ INTERNAL void user_update(void)
mixer_set_listener(listener_pos, listener_dir); mixer_set_listener(listener_pos, listener_dir);
} }
/* ========================== *
* Construct movement input
* ========================== */
/* Movement */
{
struct v2 player_move_dir = { 0 };
for (enum user_bind_kind bind = 0; bind < (i32)ARRAY_COUNT(L.bind_states); ++bind) {
struct bind_state state = L.bind_states[bind];
if (!state.is_held && state.num_presses <= 0) {
continue;
}
switch (bind) {
/* Movement */
case USER_BIND_KIND_MOVE_UP: {
player_move_dir.y -= 1;
} break;
case USER_BIND_KIND_MOVE_DOWN: {
player_move_dir.y += 1;
} break;
case USER_BIND_KIND_MOVE_LEFT: {
player_move_dir.x -= 1;
} break;
case USER_BIND_KIND_MOVE_RIGHT: {
player_move_dir.x += 1;
} break;
default: break;
}
}
player_move_dir = xform_basis_invert_mul_v2(L.world_view, player_move_dir); /* Make move dir relative to world view */
player_move_dir = v2_norm(player_move_dir);
struct game_cmd cmd = (struct game_cmd) {
.kind = GAME_CMD_KIND_PLAYER_MOVE,
.move_dir = player_move_dir
};
if (!L.debug_camera) {
struct v2 focus_move_dir = xform_basis_invert_mul_v2(L.world_view, L.mouse_delta); /* Make focus relative to world view direction */
focus_move_dir = v2_mul(focus_move_dir, MOUSE_SENSITIVITY);
cmd.focus_move_dir = focus_move_dir;
}
queue_game_cmd(&cmd_list, cmd);
}
/* ========================== * /* ========================== *
* Draw test grid * Draw test grid
* ========================== */ * ========================== */
@ -718,7 +658,7 @@ INTERNAL void user_update(void)
struct entity *ent = &entities_array.entities[entity_index]; struct entity *ent = &entities_array.entities[entity_index];
if (!ent->valid) continue; if (!ent->valid) continue;
b32 is_camera = entity_has_prop(ent, ENTITY_PROP_CAMERA); b32 skip_debug_draw = entity_has_prop(ent, ENTITY_PROP_CAMERA);
/* Draw sprite */ /* Draw sprite */
if (ent->sprite_name.len > 0) { if (ent->sprite_name.len > 0) {
@ -759,7 +699,7 @@ INTERNAL void user_update(void)
draw_texture_quad(L.world_canvas, params, quad); draw_texture_quad(L.world_canvas, params, quad);
#if 0 #if 0
if (L.debug_draw && !is_camera) { if (L.debug_draw && !skip_debug_draw) {
/* Debug draw sprite quad */ /* Debug draw sprite quad */
{ {
f32 thickness = 2.f; f32 thickness = 2.f;
@ -782,24 +722,8 @@ INTERNAL void user_update(void)
} }
} }
/* Draw crosshair */
if (!L.debug_camera && entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) {
struct v2 focus_pos = v2_add(ent->world_xform.og, ent->player_focus_dir);
struct v2 focus_pos_screen = xform_mul_v2(L.world_view, focus_pos);
u32 tint = RGBA_F(1, 1, 1, 0.5);
struct texture *t = texture_load_async(STR("res/graphics/crosshair.ase"));
if (t) {
struct xform xf = XFORM_TRS(.t = focus_pos_screen, .s = t->size);
struct quad quad = quad_mul_xform(QUAD_UNIT_SQUARE_CENTERED, xf);
draw_texture_quad(L.screen_canvas, DRAW_TEXTURE_PARAMS(.texture = t, .tint = tint), quad);
}
L.last_focus_screen_pos = focus_pos_screen;
}
/* Debug draw info */ /* Debug draw info */
if (L.debug_draw && !is_camera) { if (L.debug_draw && !skip_debug_draw) {
struct temp_arena temp = arena_temp_begin(scratch.arena); struct temp_arena temp = arena_temp_begin(scratch.arena);
#if 0 #if 0
@ -854,20 +778,87 @@ INTERNAL void user_update(void)
draw_solid_arrow_line(L.screen_canvas, start, end, thickness, arrow_height, color); draw_solid_arrow_line(L.screen_canvas, start, end, thickness, arrow_height, color);
} }
/* Draw focus */ /* Draw aim */
if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) { if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) {
u32 color = RGBA_F(0.75, 0, 0.75, 0.5); u32 color = RGBA_F(0.75, 0, 0.75, 0.5);
f32 thickness = 3; f32 thickness = 3;
f32 arrow_height = 10; f32 arrow_height = 10;
struct v2 pos = xform_mul_v2(L.world_view, ent->world_xform.og); struct v2 pos = xform_mul_v2(L.world_view, ent->world_xform.og);
struct v2 focus_ray = xform_basis_mul_v2(L.world_view, ent->player_focus_dir); struct v2 aim_ray = xform_basis_mul_v2(L.world_view, ent->player_aim);
draw_solid_arrow_ray(L.screen_canvas, pos, focus_ray, thickness, arrow_height, color); draw_solid_arrow_ray(L.screen_canvas, pos, aim_ray, thickness, arrow_height, color);
} }
arena_temp_end(temp); arena_temp_end(temp);
} }
} }
/* Draw crosshair */
if (!L.debug_camera) {
struct v2 crosshair_pos = L.screen_cursor;
u32 tint = RGBA_F(1, 1, 1, 0.5);
struct texture *t = texture_load_async(STR("res/graphics/crosshair.ase"));
if (t) {
struct xform xf = XFORM_TRS(.t = crosshair_pos, .s = t->size);
struct quad quad = quad_mul_xform(QUAD_UNIT_SQUARE_CENTERED, xf);
draw_texture_quad(L.screen_canvas, DRAW_TEXTURE_PARAMS(.texture = t, .tint = tint), quad);
}
}
/* ========================== *
* Construct movement input
* ========================== */
/* Movement */
struct v2 input_move_dir = { 0 };
{
for (enum user_bind_kind bind = 0; bind < (i32)ARRAY_COUNT(L.bind_states); ++bind) {
struct bind_state state = L.bind_states[bind];
if (!state.is_held && state.num_presses <= 0) {
continue;
}
switch (bind) {
/* Movement */
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 = xform_basis_invert_mul_v2(L.world_view, input_move_dir); /* Make move dir relative to world view */
input_move_dir = v2_norm(input_move_dir);
}
/* Aim */
struct v2 input_aim = player->player_aim;
if (!L.debug_camera) {
input_aim = v2_sub(L.world_cursor, player->world_xform.og);
}
/* Queue cmd */
struct game_cmd movement_cmd = (struct game_cmd) {
.kind = GAME_CMD_KIND_PLAYER_MOVE,
.move_dir = input_move_dir,
.aim = input_aim
};
queue_game_cmd(&cmd_list, movement_cmd);
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */

View File

@ -12,8 +12,8 @@ struct world {
f64 dt; f64 dt;
f64 time; f64 time;
struct v2 player_move_dir; /* Player movement direction */ struct v2 player_move_dir;
struct v2 player_focus_move_dir; /* Focus movement direction */ struct v2 player_aim;
struct entity_store entity_store; struct entity_store entity_store;
}; };