rotation-agnostic crosshair movement

This commit is contained in:
jacob 2026-02-10 21:36:37 -06:00
parent 8405d039af
commit f1eb4ea855
7 changed files with 87 additions and 103 deletions

View File

@ -453,7 +453,7 @@ Vec2 Vec2WithLen(Vec2 a, f32 len)
return a; return a;
} }
Vec2 ClampVec2Len(Vec2 a, f32 max) Vec2 ClampVec2Len(Vec2 a, f32 min, f32 max)
{ {
f32 l_sq = a.x * a.x + a.y * a.y; f32 l_sq = a.x * a.x + a.y * a.y;
if (l_sq > max * max) if (l_sq > max * max)
@ -462,6 +462,12 @@ Vec2 ClampVec2Len(Vec2 a, f32 max)
a.x *= denom; a.x *= denom;
a.y *= denom; a.y *= denom;
} }
else if (l_sq < min * min)
{
f32 denom = min / SqrtF32(l_sq);
a.x *= denom;
a.y *= denom;
}
return a; return a;
} }

View File

@ -366,7 +366,7 @@ f32 Vec2LenSq(Vec2 a);
Vec2 Vec2WithLen(Vec2 a, f32 len); Vec2 Vec2WithLen(Vec2 a, f32 len);
f32 Vec2Distance(Vec2 a, Vec2 b); f32 Vec2Distance(Vec2 a, Vec2 b);
Vec2 NormVec2(Vec2 a); Vec2 NormVec2(Vec2 a);
Vec2 ClampVec2Len(Vec2 a, f32 max); Vec2 ClampVec2Len(Vec2 a, f32 min, f32 max);
//- Clamp //- Clamp
Vec2 ClampVec2(Vec2 v, Rng2 r); Vec2 ClampVec2(Vec2 v, Rng2 r);

View File

@ -2082,7 +2082,7 @@ void P_StepFrame(P_Frame *frame)
// Normalize controls // Normalize controls
for (P_Ent *ent = P_FirstEnt(frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) for (P_Ent *ent = P_FirstEnt(frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
{ {
ent->control.move = ClampVec2Len(ent->control.move, 1); ent->control.move = ClampVec2Len(ent->control.move, 0, 1);
} }
} }
@ -2133,7 +2133,7 @@ void P_StepFrame(P_Frame *frame)
} }
} }
} }
\
////////////////////////////// //////////////////////////////
//- Setup constraints store //- Setup constraints store
@ -2719,7 +2719,8 @@ void P_StepFrame(P_Frame *frame)
Vec2 fire_pos = Zi; Vec2 fire_pos = Zi;
Vec2 fire_dir = Zi; Vec2 fire_dir = Zi;
Vec2 fire_base = Zi; Vec2 fire_base0 = Zi;
Vec2 fire_base1 = Zi;
if (can_fire) if (can_fire)
{ {
Vec2 look = firer->control.look; Vec2 look = firer->control.look;
@ -2753,7 +2754,7 @@ void P_StepFrame(P_Frame *frame)
SPR_Ray body_ap_ray = body.rays[SPR_RayKind_Ap]; 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 = 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 = 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)); wep_pix_to_ent_af = RotateAffine(wep_pix_to_ent_af, NegVec2(body_ap_ray.dir));
SPR_Ray anchor_ray = wep.rays[SPR_RayKind_Anchor]; 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 = RotateAffine(wep_pix_to_ent_af, anchor_ray.dir);
@ -2768,11 +2769,18 @@ void P_StepFrame(P_Frame *frame)
fire_pos = MulAffineVec2(wep_pix_to_world_af, fire_ray.pos); fire_pos = MulAffineVec2(wep_pix_to_world_af, fire_ray.pos);
fire_dir = NormRot(MulAffineBasisVec2(wep_pix_to_world_af, fire_ray.dir)); fire_dir = NormRot(MulAffineBasisVec2(wep_pix_to_world_af, fire_ray.dir));
fire_base = MulVec2(PerpVec2(NegVec2(firer->xf.r)), WedgeVec2(firer->xf.r, SubVec2(firer->xf.t, fire_pos))); fire_base0 = MulVec2(PerpVec2(NegVec2(firer->xf.r)), WedgeVec2(firer->xf.r, SubVec2(firer->xf.t, fire_pos)));
fire_base = AddVec2(fire_base, firer->xf.t); fire_base0 = AddVec2(fire_base0, firer->xf.t);
P_DebugDrawLine(fire_base, fire_pos, Color_Yellow); Vec2 chamber_pos = MulAffineVec2(body_pix_to_world_af, body.rays[SPR_RayKind_Ap].pos);
P_DebugDrawPoint(fire_base, Color_Yellow);
fire_base1 = MulVec2(PerpVec2(fire_dir), WedgeVec2(fire_dir, SubVec2(fire_pos, chamber_pos)));
fire_base1 = AddVec2(fire_base1, chamber_pos);
P_DebugDrawLine(fire_base0, fire_base1, Color_Yellow);
P_DebugDrawLine(fire_base1, fire_pos, Color_Green);
P_DebugDrawPoint(fire_base0, Color_Yellow);
P_DebugDrawPoint(fire_base1, Color_Green);
P_DebugDrawPoint(fire_pos, Color_Red); P_DebugDrawPoint(fire_pos, Color_Red);
} }
@ -2805,7 +2813,8 @@ void P_StepFrame(P_Frame *frame)
Vec2 dir = Vec2FromAngle(angle); Vec2 dir = Vec2FromAngle(angle);
bullet->bullet_base = fire_base; bullet->bullet_base0 = fire_base0;
bullet->bullet_base1 = fire_base1;
bullet->bullet_start = fire_pos; bullet->bullet_start = fire_pos;
bullet->bullet_end = AddVec2(bullet->bullet_start, MulVec2(dir, speed)); bullet->bullet_end = AddVec2(bullet->bullet_start, MulVec2(dir, speed));
bullet->bullet_firer = firer->key; bullet->bullet_firer = firer->key;
@ -2844,11 +2853,21 @@ void P_StepFrame(P_Frame *frame)
// wasn't obstructed (e.g. to prevent shooting through walls), so we // wasn't obstructed (e.g. to prevent shooting through walls), so we
// insert a path from the bullet's base to its starting position before // insert a path from the bullet's base to its starting position before
// its actual firing path // its actual firing path
{
// Firer origin -> weapon base path
BulletPath *path = PushStruct(scratch.arena, BulletPath); BulletPath *path = PushStruct(scratch.arena, BulletPath);
SllQueuePush(first_bullet_path, last_bullet_path, path); SllQueuePush(first_bullet_path, last_bullet_path, path);
path->start = bullet->bullet_base; path->start = bullet->bullet_base0;
path->end = bullet->bullet_base1;
}
{
// Weapon base -> bullet start path
BulletPath *path = PushStruct(scratch.arena, BulletPath);
SllQueuePush(first_bullet_path, last_bullet_path, path);
path->start = bullet->bullet_base1;
path->end = bullet->bullet_start; path->end = bullet->bullet_start;
} }
}
{ {
BulletPath *path = PushStruct(scratch.arena, BulletPath); BulletPath *path = PushStruct(scratch.arena, BulletPath);

View File

@ -130,7 +130,8 @@ Struct(P_Ent)
P_EntKey bullet_firer; P_EntKey bullet_firer;
b32 is_bullet; b32 is_bullet;
Vec2 bullet_base; Vec2 bullet_base0;
Vec2 bullet_base1;
Vec2 bullet_start; Vec2 bullet_start;
Vec2 bullet_end; Vec2 bullet_end;

BIN
src/pp/pp_res/sprite/bla3.ase (Stored with Git LFS)

Binary file not shown.

View File

@ -841,7 +841,8 @@ void V_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Compute movement & look //- Compute movement & look
f32 look_radius = 5; f32 max_look_radius = 5;
f32 min_look_radius = 0.01;
frame->is_looking = !frame->is_editing && !frame->palette.is_showing && !frame->held_buttons[Button_Alt]; frame->is_looking = !frame->is_editing && !frame->palette.is_showing && !frame->held_buttons[Button_Alt];
frame->is_moving = !frame->is_editing; frame->is_moving = !frame->is_editing;
@ -854,17 +855,26 @@ void V_TickForever(WaveLaneCtx *lane)
if (frame->held_buttons[Button_W]) move.y -= 1; if (frame->held_buttons[Button_W]) move.y -= 1;
if (frame->held_buttons[Button_S]) move.y += 1; if (frame->held_buttons[Button_S]) move.y += 1;
} }
move = ClampVec2Len(move, 1); move = ClampVec2Len(move, 0, 1);
f32 fire_held = frame->held_buttons[Button_M1]; f32 fire_held = frame->held_buttons[Button_M1];
Vec2 look = Zi; Vec2 look = Zi;
f32 fire_presses = fire_held && !prev_frame->held_buttons[Button_M1]; f32 fire_presses = fire_held && !prev_frame->held_buttons[Button_M1];
{ {
// TODO: Adjustable sensitivity
f32 mouse_sensitivity = TweakFloat("Mouse sensitivity", 1.0, 0.1, 5.0); f32 mouse_sensitivity = TweakFloat("Mouse sensitivity", 1.0, 0.1, 5.0);
f32 mouse_scale_factor = 0.007; f32 mouse_scale_factor = 0.007;
Vec2 look_delta = mouse_delta;
look_delta = MulVec2(look_delta, mouse_sensitivity * mouse_scale_factor);
Vec2 prev_crosshair_rot = NormRot(SubVec2(prev_frame->world_crosshair, prev_frame->world_crosshair_base));
Vec2 prev_look_rot = NormRot(prev_frame->look);
Vec2 rot = RotateVec2(prev_look_rot, InvertRot(prev_crosshair_rot));
look_delta = RotateVec2(look_delta, rot);
look = frame->look; look = frame->look;
look = AddVec2(look, MulVec2(mouse_delta, mouse_sensitivity * mouse_scale_factor)); look = AddVec2(look, look_delta);
look = ClampVec2Len(look, look_radius); look = ClampVec2Len(look, min_look_radius, max_look_radius);
} }
if (frame->is_looking) if (frame->is_looking)
@ -931,86 +941,24 @@ void V_TickForever(WaveLaneCtx *lane)
} }
else 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;
// {
// 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);
// }
Vec2 look_ratio = Zi; Vec2 look_ratio = Zi;
{ {
look_ratio = VEC2(0.5, 0.5); look_ratio = VEC2(0.5, 0.5);
// look_ratio = VEC2(0.5, 0.5 * (16.0 / 9.0));
} }
Vec2 prev_crosshair_rot = NormRot(SubVec2(prev_frame->world_crosshair, prev_frame->world_crosshair_base));
Vec2 prev_look_rot = NormRot(prev_frame->look);
Vec2 rot = RotateVec2(prev_look_rot, InvertRot(prev_crosshair_rot));
Vec2 look_pos = frame->look;
look_pos = RotateVec2(look_pos, InvertRot(rot));
P_Ent *player = P_EntFromKey(local_world->last_frame, V.player_key); P_Ent *player = P_EntFromKey(local_world->last_frame, V.player_key);
P_Ent *guy = P_EntFromKey(local_world->last_frame, player->guy); P_Ent *guy = P_EntFromKey(local_world->last_frame, player->guy);
Vec2 guy_center = P_WorldShapeFromEnt(guy).centroid; Vec2 guy_center = P_WorldShapeFromEnt(guy).centroid;
Vec2 screen_center = MulVec2(frame->screen_dims, 0.5); Vec2 screen_center = MulVec2(frame->screen_dims, 0.5);
target_camera_pos = guy_center; target_camera_pos = guy_center;
target_camera_pos = AddVec2(target_camera_pos, MulVec2Vec2(frame->look, look_ratio)); target_camera_pos = AddVec2(target_camera_pos, MulVec2Vec2(look_pos, look_ratio));
target_camera_zoom = 1; target_camera_zoom = 1;
} }
target_camera_pos.x = ClampF32(target_camera_pos.x, -world_pitch / 2, world_pitch / 2); target_camera_pos.x = ClampF32(target_camera_pos.x, -world_pitch / 2, world_pitch / 2);
@ -1872,6 +1820,7 @@ void V_TickForever(WaveLaneCtx *lane)
//- Compute crosshair position //- Compute crosshair position
// TODO: Alive / weapon check // TODO: Alive / weapon check
if (!P_IsEntNil(local_guy)) if (!P_IsEntNil(local_guy))
{ {
P_Ent *ent = local_guy; P_Ent *ent = local_guy;
@ -1916,7 +1865,7 @@ void V_TickForever(WaveLaneCtx *lane)
SPR_Ray body_ap_ray = body.rays[SPR_RayKind_Ap]; 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 = 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 = 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)); wep_pix_to_ent_af = RotateAffine(wep_pix_to_ent_af, NegVec2(body_ap_ray.dir));
SPR_Ray anchor_ray = wep.rays[SPR_RayKind_Anchor]; 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 = RotateAffine(wep_pix_to_ent_af, anchor_ray.dir);
@ -1936,25 +1885,31 @@ void V_TickForever(WaveLaneCtx *lane)
Vec2 desired_fire_pos = MulAffineVec2(desired_wep_pix_to_world_af, fire_ray.pos); 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 desired_fire_dir = NormRot(MulAffineBasisVec2(desired_wep_pix_to_world_af, fire_ray.dir));
Vec2 desired_hold_pos = MulAffineVec2(desired_body_pix_to_world_af, body.rays[SPR_RayKind_Ap].pos);
Vec2 desired_chamber_pos = MulVec2(PerpVec2(desired_fire_dir), WedgeVec2(desired_fire_dir, SubVec2(desired_fire_pos, desired_hold_pos)));
desired_chamber_pos = AddVec2(desired_chamber_pos, desired_hold_pos);
Vec2 desired_crosshair_base = MulVec2(PerpVec2(NegVec2(desired_ent_to_world_af.bx)), WedgeVec2(desired_ent_to_world_af.bx, SubVec2(desired_ent_to_world_af.og, desired_chamber_pos)));
desired_crosshair_base = AddVec2(desired_crosshair_base, desired_ent_to_world_af.og);
frame->world_guy_origin = desired_ent_to_world_af.og;
frame->world_crosshair_base = desired_crosshair_base;
Vec2 look_rot = NormRot(look); Vec2 look_rot = NormRot(look);
Vec2 line_start = cur_fire_pos; Vec2 line_start = cur_fire_pos;
Vec2 line_end = AddVec2(line_start, cur_fire_dir); Vec2 line_end = AddVec2(line_start, cur_fire_dir);
// P_DebugDrawLine(line_start, line_end, Color_Yellow);
// Vec2 cross = fire_pos; f32 cross_dist = Vec2Len(look);
// Vec2 cross = MulAffineVec2(frame->af.screen_to_world, look);
// f32 cross_dist = 1.0; frame->world_crosshair = AddVec2(frame->world_crosshair_base, MulVec2(NormVec2(desired_fire_dir), cross_dist));
f32 cross_dist = Vec2Len(look) - Vec2Len(SubVec2(desired_fire_pos, desired_ent_to_world_af.og));
frame->world_crosshair = AddVec2(desired_fire_pos, MulVec2(look_rot, cross_dist));
frame->screen_crosshair = MulAffineVec2(frame->af.world_to_screen, frame->world_crosshair); frame->screen_crosshair = MulAffineVec2(frame->af.world_to_screen, frame->world_crosshair);
frame->shade_crosshair = MulAffineVec2(frame->af.world_to_shade, frame->world_crosshair); frame->shade_crosshair = MulAffineVec2(frame->af.world_to_shade, frame->world_crosshair);
// 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(AddVec2(desired_ent_to_world_af.og, look), Color_Red); P_DebugDrawPoint(frame->world_crosshair_base, Color_Yellow);
// P_DebugDrawPoint(frame->crosshair, Color_Green);
} }
////////////////////////////// //////////////////////////////
@ -2150,7 +2105,8 @@ void V_TickForever(WaveLaneCtx *lane)
SPR_Ray body_ap_ray = body.rays[SPR_RayKind_Ap]; SPR_Ray body_ap_ray = body.rays[SPR_RayKind_Ap];
wep_pix_to_world_af = RotateAffine(wep_pix_to_world_af, InvertRot(body_anchor_ray.dir)); wep_pix_to_world_af = RotateAffine(wep_pix_to_world_af, InvertRot(body_anchor_ray.dir));
wep_pix_to_world_af = TranslateAffine(wep_pix_to_world_af, SubVec2(body_ap_ray.pos, body_anchor_ray.pos)); wep_pix_to_world_af = TranslateAffine(wep_pix_to_world_af, SubVec2(body_ap_ray.pos, body_anchor_ray.pos));
wep_pix_to_world_af = RotateAffine(wep_pix_to_world_af, InvertRot(body_ap_ray.dir)); // wep_pix_to_world_af = RotateAffine(wep_pix_to_world_af, InvertRot(body_ap_ray.dir));
wep_pix_to_world_af = RotateAffine(wep_pix_to_world_af, NegVec2(body_ap_ray.dir));
SPR_Ray anchor_ray = wep.rays[SPR_RayKind_Anchor]; SPR_Ray anchor_ray = wep.rays[SPR_RayKind_Anchor];
wep_pix_to_world_af = RotateAffine(wep_pix_to_world_af, anchor_ray.dir); wep_pix_to_world_af = RotateAffine(wep_pix_to_world_af, anchor_ray.dir);

View File

@ -115,9 +115,11 @@ Struct(V_SharedFrame)
//- Crosshair //- Crosshair
Vec2 world_guy_origin;
Vec2 world_crosshair_base;
Vec2 world_crosshair;
Vec2 screen_crosshair; Vec2 screen_crosshair;
Vec2 shade_crosshair; Vec2 shade_crosshair;
Vec2 world_crosshair;
//- Control //- Control