equip/fire beginnings. player input cmd change.
This commit is contained in:
parent
eb3c59ac13
commit
f5400b0205
21
src/entity.h
21
src/entity.h
@ -12,6 +12,11 @@ enum entity_prop {
|
||||
ENTITY_PROP_CAMERA,
|
||||
ENTITY_PROP_CAMERA_ACTIVE,
|
||||
|
||||
ENTITY_PROP_EQUIPPER,
|
||||
ENTITY_PROP_EQUIPABLE,
|
||||
|
||||
ENTITY_PROP_FIRING_EQUIPPED,
|
||||
|
||||
/* Test props */
|
||||
|
||||
ENTITY_PROP_TEST,
|
||||
@ -58,17 +63,26 @@ struct entity {
|
||||
struct entity_handle last;
|
||||
|
||||
/* ====================================================================== */
|
||||
/* Position */
|
||||
|
||||
/* Access with xform getters/setters */
|
||||
struct xform local_xform; /* Transform in relation to parent entity (or the world if entity has no parent) */
|
||||
struct xform cached_global_xform; /* Calculated from entity tree */
|
||||
b32 cached_global_xform_dirty;
|
||||
|
||||
/* ====================================================================== */
|
||||
/* Control */
|
||||
|
||||
struct {
|
||||
struct v2 move;
|
||||
struct v2 focus;
|
||||
} control;
|
||||
|
||||
/* ====================================================================== */
|
||||
/* Physics */
|
||||
|
||||
struct v2 acceleration;
|
||||
struct v2 velocity;
|
||||
struct v2 focus; /* Focus is a vector relative to the entity */
|
||||
|
||||
/* ENTITY_PROP_PLAYER_CONTROLLED */
|
||||
f32 player_max_speed;
|
||||
@ -90,6 +104,11 @@ struct entity {
|
||||
f64 animation_time_in_frame;
|
||||
u32 animation_frame;
|
||||
|
||||
/* ====================================================================== */
|
||||
/* Equip */
|
||||
|
||||
struct entity_handle equipped;
|
||||
|
||||
/* ====================================================================== */
|
||||
/* Testing */
|
||||
|
||||
|
||||
146
src/game.c
146
src/game.c
@ -121,9 +121,10 @@ INTERNAL void spawn_test_entities(void)
|
||||
entity_enable_prop(e, ENTITY_PROP_PLAYER_CONTROLLED);
|
||||
e->player_max_speed = 4.f;
|
||||
e->player_acceleration = 20.0f;
|
||||
e->focus = V2(0, -1);
|
||||
e->control.focus = V2(0, -1);
|
||||
|
||||
entity_enable_prop(e, ENTITY_PROP_ANIMATING);
|
||||
entity_enable_prop(e, ENTITY_PROP_EQUIPPER);
|
||||
|
||||
player_ent = e;
|
||||
|
||||
@ -132,41 +133,21 @@ INTERNAL void spawn_test_entities(void)
|
||||
|
||||
/* Child 1 */
|
||||
{
|
||||
struct v2 pos = V2(0.15, -0.05);
|
||||
struct v2 pos = V2(1, -1);
|
||||
struct v2 size = V2(1, 1);
|
||||
f32 r = 0;
|
||||
|
||||
struct xform xf = XFORM_TRS(.t = pos, .r = r, .s = size);
|
||||
|
||||
struct entity *e = entity_alloc_child(player_ent);
|
||||
struct entity *e = entity_alloc_top(G.world.entity_store);
|
||||
entity_set_local_xform(e, xf);
|
||||
|
||||
e->sprite = sprite_tag_from_path(STR("res/graphics/gun.ase"));
|
||||
//e->sprite_tint = RGBA_32_F(0, 0, 0, 1);
|
||||
|
||||
entity_enable_prop(e, ENTITY_PROP_ANIMATING);
|
||||
|
||||
entity_enable_prop(e, ENTITY_PROP_PLAYER_CONTROLLED);
|
||||
}
|
||||
|
||||
/* Child 2 */
|
||||
{
|
||||
struct v2 pos = V2(-0.15, -0.05);
|
||||
struct v2 size = V2(-0.25, 0.5);
|
||||
f32 r = 0;
|
||||
|
||||
struct xform xf = XFORM_TRS(.t = pos, .r = r, .s = size);
|
||||
|
||||
struct entity *e = entity_alloc_child(player_ent);
|
||||
entity_set_local_xform(e, xf);
|
||||
|
||||
e->sprite = sprite_tag_from_path(STR("res/graphics/tim.ase"));
|
||||
e->sprite_span_name = STR("idle.two_handed");
|
||||
e->sprite_tint = RGBA_32_F(0, 0, 0, 1);
|
||||
|
||||
entity_enable_prop(e, ENTITY_PROP_ANIMATING);
|
||||
|
||||
entity_enable_prop(e, ENTITY_PROP_PLAYER_CONTROLLED);
|
||||
entity_enable_prop(e, ENTITY_PROP_EQUIPABLE);
|
||||
player_ent->equipped = e->handle;
|
||||
}
|
||||
|
||||
/* Camera ent */
|
||||
@ -203,10 +184,8 @@ INTERNAL void game_update(void)
|
||||
|
||||
struct temp_arena scratch = scratch_begin_no_conflict();
|
||||
|
||||
struct entity_store *store = G.world.entity_store;
|
||||
|
||||
/* ========================== *
|
||||
* Begin frame cache scopes
|
||||
* Begin frame
|
||||
* ========================== */
|
||||
|
||||
struct sprite_scope *sprite_frame_scope = sprite_scope_begin();
|
||||
@ -225,23 +204,20 @@ INTERNAL void game_update(void)
|
||||
G.world.time += G.world.dt;
|
||||
|
||||
/* ========================== *
|
||||
* Process game cmds
|
||||
* Pull cmds
|
||||
* ========================== */
|
||||
|
||||
struct entity_store *store = G.world.entity_store;
|
||||
struct game_cmd_array game_cmds = pop_cmds(scratch.arena);
|
||||
|
||||
/* ========================== *
|
||||
* Pre-sim game cmds
|
||||
* ========================== */
|
||||
|
||||
for (u64 cmd_index = 0; cmd_index < game_cmds.count; ++cmd_index) {
|
||||
struct game_cmd cmd = game_cmds.cmds[cmd_index];
|
||||
|
||||
switch (cmd.kind) {
|
||||
/* Movement */
|
||||
case GAME_CMD_KIND_PLAYER_MOVE: {
|
||||
G.world.player_move_dir = cmd.move_dir;
|
||||
} break;
|
||||
|
||||
case GAME_CMD_KIND_PLAYER_AIM: {
|
||||
G.world.camera_focus = cmd.aim;
|
||||
} break;
|
||||
|
||||
/* Clear level */
|
||||
case GAME_CMD_KIND_CLEAR_ALL: {
|
||||
logf_info("Clearing level");
|
||||
@ -263,11 +239,6 @@ INTERNAL void game_update(void)
|
||||
};
|
||||
}
|
||||
|
||||
if (v2_len(G.world.player_move_dir) > 1.f) {
|
||||
/* Clamp movement magnitude */
|
||||
G.world.player_move_dir = v2_norm(G.world.player_move_dir);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
@ -284,7 +255,7 @@ INTERNAL void game_update(void)
|
||||
if (sprite_tag_is_nil(ent->sprite)) continue;
|
||||
|
||||
/* ========================== *
|
||||
* Update animation
|
||||
* Update sprite animation
|
||||
* ========================== */
|
||||
|
||||
if (entity_has_prop(ent, ENTITY_PROP_ANIMATING)) {
|
||||
@ -332,31 +303,15 @@ INTERNAL void game_update(void)
|
||||
|
||||
|
||||
/* ========================== *
|
||||
* Update entities pre-physics
|
||||
* Update entities pre-simulation
|
||||
* ========================== */
|
||||
|
||||
/* Find active camera */
|
||||
struct entity *active_camera;
|
||||
{
|
||||
enum entity_prop props[] = { ENTITY_PROP_CAMERA, ENTITY_PROP_CAMERA_ACTIVE };
|
||||
active_camera = entity_find_first_match_all(store, (struct entity_prop_array) { .count = ARRAY_COUNT(props), .props = props });
|
||||
}
|
||||
|
||||
/* Update camera focus */
|
||||
if (active_camera->valid) {
|
||||
active_camera->focus = G.world.camera_focus;
|
||||
}
|
||||
|
||||
/* Calculate player aim pos from camera focus */
|
||||
struct v2 player_aim_pos = v2_add(entity_get_xform(active_camera).og, G.world.camera_focus);
|
||||
(UNUSED)player_aim_pos;
|
||||
|
||||
for (u64 entity_index = 0; entity_index < entities_array.count; ++entity_index) {
|
||||
struct entity *ent = &entities_array.entities[entity_index];
|
||||
if (!ent->valid) continue;
|
||||
|
||||
/* ========================== *
|
||||
* Initialize
|
||||
* Initialize test
|
||||
* ========================== */
|
||||
|
||||
/* ENTITY_PROP_TEST */
|
||||
@ -367,15 +322,50 @@ INTERNAL void game_update(void)
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Calculate player aim angle
|
||||
* Update control from player cmds
|
||||
* ========================== */
|
||||
|
||||
if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) {
|
||||
for (u64 i = 0; i < game_cmds.count; ++i) {
|
||||
struct game_cmd cmd = game_cmds.cmds[i];
|
||||
b32 start = cmd.state == 1;
|
||||
b32 stop = cmd.state == -1;
|
||||
|
||||
/* TODO: Combine movement from multiple inputs? E.G. a sudden
|
||||
* start and immediate stop cmd should still move the player a
|
||||
* tad. */
|
||||
|
||||
switch (cmd.kind) {
|
||||
case GAME_CMD_KIND_PLAYER_MOVE: {
|
||||
struct v2 move = cmd.move_dir;
|
||||
if (v2_len_squared(move) > 1) {
|
||||
/* Cap movement vector magnitude at 1 */
|
||||
move = v2_norm(move);
|
||||
}
|
||||
ent->control.move = move;
|
||||
ent->control.focus = v2_sub(cmd.aim_pos, entity_get_xform(ent).og);
|
||||
} break;
|
||||
|
||||
case GAME_CMD_KIND_PLAYER_FIRE: {
|
||||
if (start) {
|
||||
entity_enable_prop(ent, ENTITY_PROP_FIRING_EQUIPPED);
|
||||
} else if (stop) {
|
||||
entity_disable_prop(ent, ENTITY_PROP_FIRING_EQUIPPED);
|
||||
}
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Update player angle
|
||||
* ========================== */
|
||||
|
||||
if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) {
|
||||
struct xform xf = entity_get_xform(ent);
|
||||
|
||||
/* Update focus */
|
||||
ent->focus = v2_sub(player_aim_pos, xf.og);
|
||||
|
||||
/* Solve for final angle using law of sines */
|
||||
f32 final_xf_angle;
|
||||
{
|
||||
@ -390,7 +380,7 @@ INTERNAL void game_update(void)
|
||||
}
|
||||
|
||||
struct v2 ent_pos = xf.og;
|
||||
struct v2 focus_pos = v2_add(ent_pos, ent->focus);
|
||||
struct v2 focus_pos = v2_add(ent_pos, ent->control.focus);
|
||||
|
||||
struct v2 hold_pos;
|
||||
{
|
||||
@ -451,10 +441,22 @@ INTERNAL void game_update(void)
|
||||
xf= xform_with_scale(xf, s);
|
||||
entity_set_local_xform(ent, xf);
|
||||
}
|
||||
|
||||
/* ENTITY_PROP_FIRING_EQUIPPED */
|
||||
{
|
||||
struct entity *eq = entity_from_handle(store, ent->equipped);
|
||||
if (eq->valid) {
|
||||
if (entity_has_prop(ent, ENTITY_PROP_FIRING_EQUIPPED)) {
|
||||
eq->sprite_tint = RGBA_32_F(1, 0, 0, 1);
|
||||
} else {
|
||||
eq->sprite_tint = RGBA_32_F(1, 1, 1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Update entity physics
|
||||
* Simulate entities
|
||||
* ========================== */
|
||||
|
||||
for (u64 entity_index = 0; entity_index < entities_array.count; ++entity_index) {
|
||||
@ -462,14 +464,14 @@ INTERNAL void game_update(void)
|
||||
if (!ent->valid) continue;
|
||||
|
||||
/* ========================== *
|
||||
* Player movement
|
||||
* Player control
|
||||
* ========================== */
|
||||
|
||||
if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) {
|
||||
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(G.world.player_move_dir, max_speed);
|
||||
struct v2 target_velocity = v2_mul(ent->control.move, max_speed);
|
||||
struct v2 target_acceleration = v2_sub(target_velocity, ent->velocity);
|
||||
ent->acceleration = v2_mul(target_acceleration, acceleration_rate);
|
||||
}
|
||||
@ -493,7 +495,7 @@ INTERNAL void game_update(void)
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Update entities post-physics
|
||||
* Update entities post-simulation
|
||||
* ========================== */
|
||||
|
||||
for (u64 entity_index = 0; entity_index < entities_array.count; ++entity_index) {
|
||||
@ -521,7 +523,7 @@ INTERNAL void game_update(void)
|
||||
}
|
||||
f32 ratio_y = 0.33f;
|
||||
f32 ratio_x = ratio_y / aspect_ratio;
|
||||
struct v2 camera_focus_dir = v2_mul_v2(follow->focus, V2(ratio_x, ratio_y));
|
||||
struct v2 camera_focus_dir = v2_mul_v2(follow->control.focus, V2(ratio_x, ratio_y));
|
||||
struct v2 camera_focus_pos = v2_add(entity_get_xform(follow).og, camera_focus_dir);
|
||||
ent->camera_xform_target = xf;
|
||||
ent->camera_xform_target.og = camera_focus_pos;
|
||||
|
||||
@ -10,7 +10,7 @@ enum game_cmd_kind {
|
||||
GAME_CMD_KIND_NONE,
|
||||
|
||||
GAME_CMD_KIND_PLAYER_MOVE,
|
||||
GAME_CMD_KIND_PLAYER_AIM,
|
||||
GAME_CMD_KIND_PLAYER_FIRE,
|
||||
|
||||
/* Testing */
|
||||
GAME_CMD_KIND_CLEAR_ALL,
|
||||
@ -22,11 +22,12 @@ enum game_cmd_kind {
|
||||
struct game_cmd {
|
||||
enum game_cmd_kind kind;
|
||||
|
||||
/* 1 = start, -1 = stop */
|
||||
i32 state;
|
||||
|
||||
/* GAME_CMD_KIND_PLAYER_MOVE */
|
||||
struct v2 move_dir;
|
||||
|
||||
/* GAME_CMD_KIND_PLAYER_AIM */
|
||||
struct v2 aim;
|
||||
struct v2 aim_pos;
|
||||
};
|
||||
|
||||
struct game_cmd_array {
|
||||
|
||||
35
src/user.c
35
src/user.c
@ -80,6 +80,7 @@ GLOBAL READONLY enum user_bind_kind g_binds[SYS_BTN_COUNT] = {
|
||||
[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_M1] = USER_BIND_KIND_FIRE,
|
||||
|
||||
/* Testing */
|
||||
|
||||
@ -440,11 +441,13 @@ INTERNAL void user_update(void)
|
||||
tick_blend = clamp_f32(tick_blend, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
/* TODO: Should we actually be basing interpolated tick on t1 rather
|
||||
* than t0? This means un-interpolated values will use the newer frame's
|
||||
* value, while still interpolating from the older frame. */
|
||||
world_copy_replace(&G.world, t1);
|
||||
|
||||
/* Blend world globals */
|
||||
G.world.time = math_lerp64(t0->time, t1->time, (f64)tick_blend);
|
||||
G.world.camera_focus = v2_lerp(t0->camera_focus, t1->camera_focus, tick_blend);
|
||||
|
||||
/* Blend entities */
|
||||
struct entity_array t0_entities = entity_store_as_array(t0->entity_store);
|
||||
@ -466,7 +469,9 @@ INTERNAL void user_update(void)
|
||||
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(e0->player_acceleration, e1->player_acceleration, tick_blend);
|
||||
e->focus = v2_lerp(e0->focus, e1->focus, tick_blend);
|
||||
|
||||
e->control.move = v2_lerp(e0->control.move, e1->control.move, tick_blend);
|
||||
e->control.focus = v2_lerp(e0->control.focus, e1->control.focus, tick_blend);
|
||||
|
||||
e->sprite_local_xform = xform_lerp(e0->sprite_local_xform, e1->sprite_local_xform, tick_blend);
|
||||
e->animation_time_in_frame = math_lerp64(e0->animation_time_in_frame, e1->animation_time_in_frame, (f64)tick_blend);
|
||||
@ -848,13 +853,13 @@ INTERNAL void user_update(void)
|
||||
debug_draw_xform(xf);
|
||||
}
|
||||
|
||||
/* Draw aim arrow */
|
||||
/* Draw focus arrow */
|
||||
if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) {
|
||||
struct sprite_sheet *sheet = sprite_sheet_from_tag_async(sprite_frame_scope, ent->sprite);
|
||||
struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, STR("hold"), ent->animation_frame);
|
||||
struct v2 start = xform_mul_v2(sprite_xform, slice.center);
|
||||
start = xform_mul_v2(G.world_view, start);
|
||||
struct v2 end = v2_add(xf.og, ent->focus);
|
||||
struct v2 end = v2_add(xf.og, ent->control.focus);
|
||||
end = xform_mul_v2(G.world_view, end);
|
||||
draw_solid_arrow_line(G.viewport_canvas, start, end, 3, 10, RGBA_32_F(1, 1, 1, 0.5));
|
||||
}
|
||||
@ -946,10 +951,11 @@ INTERNAL void user_update(void)
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Construct movement input
|
||||
* Construct player control cmd
|
||||
* ========================== */
|
||||
|
||||
/* Movement */
|
||||
{
|
||||
struct v2 input_move_dir = { 0 };
|
||||
{
|
||||
for (enum user_bind_kind bind = 0; bind < (i32)ARRAY_COUNT(G.bind_states); ++bind) {
|
||||
@ -985,20 +991,27 @@ INTERNAL void user_update(void)
|
||||
input_move_dir = v2_norm(input_move_dir);
|
||||
}
|
||||
|
||||
/* Queue move cmd */
|
||||
struct v2 input_aim_pos = G.world_cursor;
|
||||
|
||||
i32 cmd_fire = (G.bind_states[USER_BIND_KIND_FIRE].num_presses > 0 || G.bind_states[USER_BIND_KIND_FIRE].is_held) ? 1 : -1;
|
||||
|
||||
if (!G.debug_camera) {
|
||||
/* Queue player move cmd */
|
||||
queue_game_cmd(&cmd_list, (struct game_cmd) {
|
||||
.kind = GAME_CMD_KIND_PLAYER_MOVE,
|
||||
.move_dir = input_move_dir,
|
||||
.aim_pos = input_aim_pos
|
||||
});
|
||||
|
||||
/* Queue aim cmd */
|
||||
if (!G.debug_camera) {
|
||||
struct v2 input_aim = v2_sub(G.world_cursor, entity_get_xform(active_camera).og);
|
||||
/* Queue player fire cmd */
|
||||
if (cmd_fire) {
|
||||
queue_game_cmd(&cmd_list, (struct game_cmd) {
|
||||
.kind = GAME_CMD_KIND_PLAYER_AIM,
|
||||
.aim = input_aim,
|
||||
.kind = GAME_CMD_KIND_PLAYER_FIRE,
|
||||
.state = cmd_fire
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
@ -18,6 +18,7 @@ enum user_bind_kind {
|
||||
USER_BIND_KIND_MOVE_DOWN,
|
||||
USER_BIND_KIND_MOVE_LEFT,
|
||||
USER_BIND_KIND_MOVE_RIGHT,
|
||||
USER_BIND_KIND_FIRE,
|
||||
|
||||
/* Testing */
|
||||
|
||||
|
||||
@ -12,9 +12,6 @@ struct world {
|
||||
f64 dt;
|
||||
f64 time;
|
||||
|
||||
struct v2 player_move_dir;
|
||||
struct v2 camera_focus;
|
||||
|
||||
struct entity_store *entity_store;
|
||||
};
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user