fire bullets from weapon position

This commit is contained in:
jacob 2026-02-01 14:39:31 -06:00
parent 80f9434af8
commit 399f3a1528
2 changed files with 219 additions and 38 deletions

View File

@ -2460,34 +2460,60 @@ void P_StepFrame(P_Frame *frame)
{
P_Shape firer_world_shape = P_WorldShapeFromEnt(firer);
Vec2 base_pos = P_EdgePointFromShape(firer_world_shape, firer->control.look);
Vec2 base_dir = firer->control.look;
// Vec2 fire_pos = P_EdgePointFromShape(firer_world_shape, firer->control.look);
// Vec2 fire_dir = firer->control.look;
// Xform base_xf = Zi;
// {
// P_Anim anim = P_AnimFromEnt(firer, frame->time_ns);
Vec2 fire_pos = Zi;
Vec2 fire_dir = Zi;
{
Vec2 look = firer->control.look;
P_Anim anim = P_AnimFromEnt(firer, frame->time_ns);
SPR_Sprite body = SPR_SpriteFromSheet(anim.sheet, anim.span, anim.frame_seq);
SPR_Sprite wep = SPR_SpriteFromSheet(anim.wep_sheet, anim.span, anim.frame_seq);
// SPR_LayerKey origin_layer = SPR_LayerKeyFromName(Lit(".origin"));
// SPR_LayerKey ap_layer = SPR_LayerKeyFromName(Lit(".ap"));
//- Compute sprite transforms
Affine ent_to_world_af = MulAffineXform(AffineIdentity, firer->xf);
Affine body_pix_to_world_af = AffineIdentity;
Affine wep_pix_to_world_af = AffineIdentity;
{
Vec2 pix_scale = VEC2(1.0 / P_CellsPerMeter, 1.0 / P_CellsPerMeter);
// Xform firer_to_body_origin_xf = SPR_XformFromSheet(anim.sheet, origin_layer, anim.span, anim.frame_seq);
// Xform firer_to_body_ap_xf = SPR_XformFromSheet(anim.sheet, ap_layer, anim.span, anim.frame_seq);
//- Compute body transform
Affine body_pix_to_ent_af = AffineIdentity;
{
body_pix_to_ent_af = ScaleAffine(body_pix_to_ent_af, pix_scale);
// Xform body_ap_to_wep_origin_xf = SPR_XformFromSheet(anim.wep_sheet, origin_layer, anim.span, anim.frame_seq);
// Xform body_ap_to_wep_ap_xf = SPR_XformFromSheet(anim.wep_sheet, ap_layer, anim.span, anim.frame_seq);
SPR_Ray anchor_ray = body.rays[SPR_RayKind_Anchor];
body_pix_to_ent_af = RotateAffine(body_pix_to_ent_af, InvertRot(anchor_ray.dir));
body_pix_to_ent_af = TranslateAffine(body_pix_to_ent_af, NegVec2(anchor_ray.pos));
}
// // Xform fo2w = SubVec2(firer_
// Xform firer_to_world_xf = firer->xf;
// Xform bullet_xf = MulXform(firer_to_world_xf, firer_to_body_ap_xf);
// base_pos = bullet_xf.t;
//- Compute weapon transform
Affine wep_pix_to_ent_af = AffineIdentity;
{
wep_pix_to_ent_af = ScaleAffine(wep_pix_to_ent_af, pix_scale);
// // FIXME: Real dir
// // base_dir = firer->control.look;
// base_dir = bullet_xf.r;
// }
SPR_Ray body_anchor_ray = body.rays[SPR_RayKind_Anchor];
SPR_Ray body_ap_ray = body.rays[SPR_RayKind_Ap];
wep_pix_to_ent_af = RotateAffine(wep_pix_to_ent_af, InvertRot(body_anchor_ray.dir));
wep_pix_to_ent_af = TranslateAffine(wep_pix_to_ent_af, SubVec2(body_ap_ray.pos, body_anchor_ray.pos));
wep_pix_to_ent_af = RotateAffine(wep_pix_to_ent_af, InvertRot(body_ap_ray.dir));
SPR_Ray anchor_ray = wep.rays[SPR_RayKind_Anchor];
wep_pix_to_ent_af = RotateAffine(wep_pix_to_ent_af, anchor_ray.dir);
wep_pix_to_ent_af = TranslateAffine(wep_pix_to_ent_af, NegVec2(anchor_ray.pos));
}
body_pix_to_world_af = MulAffine(ent_to_world_af, body_pix_to_ent_af);
wep_pix_to_world_af = MulAffine(ent_to_world_af, wep_pix_to_ent_af);
}
SPR_Ray fire_ray = wep.rays[SPR_RayKind_Ap];
fire_pos = MulAffineVec2(wep_pix_to_world_af, fire_ray.pos);
fire_dir = NormRot(MulAffineBasisVec2(wep_pix_to_world_af, fire_ray.dir));
}
// FIXME: Prevent obstructed weapons from firing through walls
for (i64 bullet_idx = 0; bullet_idx < tick_bullets_count; ++bullet_idx)
{
P_Ent *bullet = P_PushTempEnt(scratch.arena, &bullets_to_spawn);
@ -2498,14 +2524,14 @@ void P_StepFrame(P_Frame *frame)
f32 rand_angle = ((f32)P_RandU64FromEnt(firer) / (f32)0xFFFFFFFFFFFFFFFFull) - 0.5;
f32 speed = tweak_speed * sim_dt;
f32 angle = AngleFromVec2(base_dir);
f32 angle = AngleFromVec2(fire_dir);
speed += (speed * 0.5) * rand_speed;
angle += rand_angle * spread;
Vec2 dir = Vec2FromAngle(angle);
bullet->bullet_start = base_pos;
bullet->bullet_start = fire_pos;
bullet->bullet_end = AddVec2(bullet->bullet_start, MulVec2(dir, speed));
bullet->bullet_firer = firer->key;
}

View File

@ -577,6 +577,7 @@ void V_TickForever(WaveLaneCtx *lane)
frame->sim_key = prev_frame->sim_key;
frame->desired_sim_key = prev_frame->desired_sim_key;
frame->predict_tick_accum = prev_frame->predict_tick_accum;
frame->af = prev_frame->af;
frame->tick = V.current_frame_tick;
frame->time_ns = TimeNs();
@ -830,6 +831,17 @@ void V_TickForever(WaveLaneCtx *lane)
//////////////////////////////
//- Compute movement & look
f32 look_radius = 0;
{
Vec2 world_screen_dims = MulAffineBasisVec2(prev_frame->af.screen_to_world, prev_frame->screen_dims);
// look_radius = MinF32(world_screen_dims.x, world_screen_dims.y) * 0.5;
look_radius = MinF32(world_screen_dims.x, world_screen_dims.y) * 0.75;
// FIXME: Lower
f32 max_look_radius = 10;
look_radius = ClampF32(look_radius, 1, max_look_radius);
}
if (!frame->is_editing && !frame->palette.is_showing)
{
WND_PushCmd(window_frame, .kind = WND_CmdKind_SetLockedCursor, .v = 1);
@ -849,14 +861,11 @@ void V_TickForever(WaveLaneCtx *lane)
Vec2 look = Zi;
f32 fire_presses = fire_held && !prev_frame->held_buttons[Button_M1];
{
// Vec2 center = P_WorldShapeFromEnt(local_guy).centroid;
// look = SubVec2(frame->world_cursor, center);
// TODO: Adjustable sensitivity
f32 mouse_scale_factor = 0.005;
look = frame->look;
look = AddVec2(look, MulVec2(mouse_delta, mouse_scale_factor));
look = ClampVec2Len(look, look_radius);
}
if (frame->is_editing)
{
@ -923,14 +932,63 @@ void V_TickForever(WaveLaneCtx *lane)
}
else
{
// // Vec2 look_ratio = VEC2(0.5, 0.5);
// Vec2 look_ratio = VEC2(0.75, 0.75);
// // Vec2 look_ratio = VEC2(1.0, 1.0);
// {
// // look_ratio.y = 0.5;
// // look_ratio.x = look_ratio.y / (16.0 / 9.0);
// }
// Vec2 look_ratio = Zi;
// {
// Vec2 max_look = Vec2WithLen(frame->look, look_radius);
// Vec2 look_ratio_of_max = DivVec2Vec2(frame->look, Vec2WithLen(frame->look, look_radius));
// look_ratio = look_ratio_of_max;
// // Vec2 screen_look = MulAffineVec2(frame->af.world_to_screen, frame->look);
// // Vec2 screen_max_look = MulAffineVec2(frame->af.world_to_screen, frame->look)
// // look_ratio.x = screen_look.x / frame->screen_dims.x;
// // look_ratio.x = frame->look.x / look_radius;
// if (IsNan(look_ratio.x) || IsNan(look_ratio.y))
// {
// look_ratio = VEC2(0, 0);
// }
// }
Vec2 look_ratio = Zi;
look_ratio.y = 0.5;
look_ratio.x = look_ratio.y / (16.0 / 9.0);
{
Vec2 max_look = Vec2WithLen(frame->look, look_radius);
Vec2 look_ratio_of_radius = DivVec2Vec2(frame->look, Vec2WithLen(frame->look, look_radius));
look_ratio = look_ratio_of_radius;
// Vec2 screen_look = MulAffineVec2(frame->af.world_to_screen, frame->look);
// Vec2 screen_max_look = MulAffineVec2(frame->af.world_to_screen, frame->look)
// look_ratio.x = screen_look.x / frame->screen_dims.x;
// look_ratio.x = frame->look.x / look_radius;
if (IsNan(look_ratio.x) || IsNan(look_ratio.y))
{
look_ratio = VEC2(0, 0);
}
// look_ratio = MulVec2(look_ratio, 0.5);
look_ratio = VEC2(0.5, 0.5);
}
P_Ent *player = P_EntFromKey(local_world->last_frame, V.player_key);
P_Ent *guy = P_EntFromKey(local_world->last_frame, player->guy);
Vec2 guy_center = P_WorldShapeFromEnt(guy).centroid;
Vec2 screen_center = MulVec2(frame->screen_dims, 0.5);
// Vec2 look = MulAffineBasisVec2(prev_frame->af.screen_to_world, SubVec2(ui_frame->cursor_pos, screen_center));
target_camera_pos = guy_center;
target_camera_pos = AddVec2(target_camera_pos, MulVec2Vec2(frame->look, look_ratio));
target_camera_zoom = 1;
@ -1932,6 +1990,93 @@ void V_TickForever(WaveLaneCtx *lane)
//////////////////////////////
//- Draw crosshair
// // TODO: Alive / weapon check
// if (!P_IsEntNil(local_guy))
// {
// P_Ent *ent = local_guy;
// P_Anim anim = P_AnimFromEnt(ent, local_frame->time_ns);
// SPR_Sprite body = SPR_SpriteFromSheet(anim.sheet, anim.span, anim.frame_seq);
// SPR_Sprite wep = SPR_SpriteFromSheet(anim.wep_sheet, anim.span, anim.frame_seq);
// Vec2 look = ent->control.look;
// if (P_MatchKey(ent->key, local_guy->key))
// {
// // Late latch local player aim direction for lower-latency
// look = frame->look;
// }
// //- Compute sprite transforms
// Affine cur_ent_to_world_af = MulAffineXform(AffineIdentity, ent->xf);
// Affine desired_ent_to_world_af = MulAffineXform(AffineIdentity, XformTR(ent->xf.t, NormRot(look)));
// Affine cur_body_pix_to_world_af = AffineIdentity;
// Affine cur_wep_pix_to_world_af = AffineIdentity;
// Affine desired_body_pix_to_world_af = AffineIdentity;
// Affine desired_wep_pix_to_world_af = AffineIdentity;
// {
// Vec2 pix_scale = VEC2(1.0 / P_CellsPerMeter, 1.0 / P_CellsPerMeter);
// //- Compute body transform
// Affine body_pix_to_ent_af = AffineIdentity;
// {
// body_pix_to_ent_af = ScaleAffine(body_pix_to_ent_af, pix_scale);
// SPR_Ray anchor_ray = body.rays[SPR_RayKind_Anchor];
// body_pix_to_ent_af = RotateAffine(body_pix_to_ent_af, InvertRot(anchor_ray.dir));
// body_pix_to_ent_af = TranslateAffine(body_pix_to_ent_af, NegVec2(anchor_ray.pos));
// }
// //- Compute weapon transform
// Affine wep_pix_to_ent_af = AffineIdentity;
// {
// wep_pix_to_ent_af = ScaleAffine(wep_pix_to_ent_af, pix_scale);
// SPR_Ray body_anchor_ray = body.rays[SPR_RayKind_Anchor];
// SPR_Ray body_ap_ray = body.rays[SPR_RayKind_Ap];
// wep_pix_to_ent_af = RotateAffine(wep_pix_to_ent_af, InvertRot(body_anchor_ray.dir));
// wep_pix_to_ent_af = TranslateAffine(wep_pix_to_ent_af, SubVec2(body_ap_ray.pos, body_anchor_ray.pos));
// wep_pix_to_ent_af = RotateAffine(wep_pix_to_ent_af, InvertRot(body_ap_ray.dir));
// SPR_Ray anchor_ray = wep.rays[SPR_RayKind_Anchor];
// wep_pix_to_ent_af = RotateAffine(wep_pix_to_ent_af, anchor_ray.dir);
// wep_pix_to_ent_af = TranslateAffine(wep_pix_to_ent_af, NegVec2(anchor_ray.pos));
// }
// cur_body_pix_to_world_af = MulAffine(cur_ent_to_world_af, body_pix_to_ent_af);
// cur_wep_pix_to_world_af = MulAffine(cur_ent_to_world_af, wep_pix_to_ent_af);
// desired_body_pix_to_world_af = MulAffine(desired_ent_to_world_af, body_pix_to_ent_af);
// desired_wep_pix_to_world_af = MulAffine(desired_ent_to_world_af, wep_pix_to_ent_af);
// }
// SPR_Ray fire_ray = wep.rays[SPR_RayKind_Ap];
// Vec2 cur_fire_pos = MulAffineVec2(cur_wep_pix_to_world_af, fire_ray.pos);
// Vec2 cur_fire_dir = NormRot(MulAffineBasisVec2(cur_wep_pix_to_world_af, fire_ray.dir));
// Vec2 desired_fire_pos = MulAffineVec2(desired_wep_pix_to_world_af, fire_ray.pos);
// Vec2 desired_fire_dir = NormRot(MulAffineBasisVec2(desired_wep_pix_to_world_af, fire_ray.dir));
// Vec2 look_rot = NormRot(look);
// Vec2 line_start = cur_fire_pos;
// Vec2 line_end = AddVec2(line_start, cur_fire_dir);
// P_DebugDrawLine(line_start, line_end, Color_Yellow);
// // Vec2 cross = fire_pos;
// // Vec2 cross = MulAffineVec2(frame->af.screen_to_world, look);
// // f32 cross_dist = 1.0;
// f32 cross_dist = Vec2Len(look);
// Vec2 cross = AddVec2(desired_fire_pos, MulVec2(look_rot, cross_dist));
// // P_DebugDrawPoint(AddVec2(MulAffineVec2(frame->af.screen_to_world, MulVec2(frame->screen_dims, 0.5)), look), Color_Red);
// P_DebugDrawPoint(AddVec2(cur_ent_to_world_af.og, look), Color_Red);
// P_DebugDrawPoint(cross, Color_Green);
// }
// TODO: Alive / weapon check
if (!P_IsEntNil(local_guy))
{
@ -1941,8 +2086,16 @@ void V_TickForever(WaveLaneCtx *lane)
SPR_Sprite body = SPR_SpriteFromSheet(anim.sheet, anim.span, anim.frame_seq);
SPR_Sprite wep = SPR_SpriteFromSheet(anim.wep_sheet, anim.span, anim.frame_seq);
//- Compute sprite transforms
Vec2 look = ent->control.look;
if (P_MatchKey(ent->key, local_guy->key))
{
// Late latch local player aim direction for lower-latency
look = frame->look;
}
//- Compute sprite transforms
Affine cur_ent_to_world_af = MulAffineXform(AffineIdentity, ent->xf);
Affine desired_ent_to_world_af = MulAffineXform(AffineIdentity, XformTR(ent->xf.t, NormRot(look)));
Affine cur_body_pix_to_world_af = AffineIdentity;
Affine cur_wep_pix_to_world_af = AffineIdentity;
Affine desired_body_pix_to_world_af = AffineIdentity;
@ -1950,9 +2103,6 @@ void V_TickForever(WaveLaneCtx *lane)
{
Vec2 pix_scale = VEC2(1.0 / P_CellsPerMeter, 1.0 / P_CellsPerMeter);
Affine cur_ent_to_world_af = MulAffineXform(AffineIdentity, ent->xf);
Affine desired_ent_to_world_af = MulAffineXform(AffineIdentity, XformTR(ent->xf.t, NormRot(ent->control.look)));
//- Compute body transform
Affine body_pix_to_ent_af = AffineIdentity;
{
@ -1992,26 +2142,31 @@ void V_TickForever(WaveLaneCtx *lane)
Vec2 desired_fire_pos = MulAffineVec2(desired_wep_pix_to_world_af, fire_ray.pos);
Vec2 desired_fire_dir = NormRot(MulAffineBasisVec2(desired_wep_pix_to_world_af, fire_ray.dir));
Vec2 look_dir = NormRot(frame->look);
Vec2 look_rot = NormRot(look);
Vec2 line_start = cur_fire_pos;
Vec2 line_end = AddVec2(line_start, cur_fire_dir);
P_DebugDrawLine(line_start, line_end, Color_Yellow);
// P_DebugDrawLine(line_start, line_end, Color_Yellow);
// Vec2 cross = fire_pos;
// Vec2 cross = MulAffineVec2(frame->af.screen_to_world, frame->look);
// Vec2 cross = MulAffineVec2(frame->af.screen_to_world, look);
// f32 cross_dist = 1.0;
f32 cross_dist = Vec2Len(frame->look);
f32 cross_dist = Vec2Len(look) - Vec2Len(SubVec2(desired_fire_pos, desired_ent_to_world_af.og));
Vec2 cross = AddVec2(desired_fire_pos, MulVec2(look_dir, cross_dist));
Vec2 cross = AddVec2(desired_fire_pos, MulVec2(look_rot, cross_dist));
// P_DebugDrawPoint(AddVec2(MulAffineVec2(frame->af.screen_to_world, MulVec2(frame->screen_dims, 0.5)), frame->look), Color_Red);
// P_DebugDrawPoint(AddVec2(MulAffineVec2(frame->af.screen_to_world, MulVec2(frame->screen_dims, 0.5)), look), Color_Red);
// P_DebugDrawPoint(AddVec2(desired_ent_to_world_af.og, look), Color_Red);
P_DebugDrawPoint(cross, Color_Green);
}
//////////////////////////////
//- Push test bullet particles