prevent players from firing through walls

This commit is contained in:
jacob 2026-02-10 19:31:34 -06:00
parent 45ac2bf1af
commit 8405d039af
2 changed files with 84 additions and 38 deletions

View File

@ -1378,7 +1378,8 @@ P_Space P_SpaceFromWalls(Arena *arena, P_Frame *frame)
{
Vec2 p0 = VEC2(wall->start.x / P_TilesPerMeter - P_WorldPitch / 2, wall->start.y / P_TilesPerMeter - P_WorldPitch / 2);
Vec2 p1 = VEC2(wall->end.x / P_TilesPerMeter - P_WorldPitch / 2, wall->end.y / P_TilesPerMeter - P_WorldPitch / 2);
P_Shape shape = P_ShapeFromDesc(.count = 2, .points = { p0, p1 }, .radius = 0.01 );
// P_Shape shape = P_ShapeFromDesc(.count = 2, .points = { p0, p1 }, .radius = 0.01 );
P_Shape shape = P_ShapeFromDesc(.count = 2, .points = { p0, p1 }, .radius = 0.0 );
Rng2 aabb = P_BoundingBoxFromShape(shape);
aabb = AddRng2Vec2(aabb, VEC2(P_WorldPitch / 2.0, P_WorldPitch / 2.0));
aabb.p0 = FloorVec2(aabb.p0);
@ -1729,6 +1730,7 @@ void P_SpawnEntsFromList(P_Frame *frame, P_EntList ents)
dst->next_in_bin = old_next_in_bin;
dst->prev_in_bin = old_prev_in_bin;
dst->created_at_ns = frame->time_ns;
dst->created_at_tick = frame->tick;
++frame->ents_count;
}
}
@ -2717,6 +2719,7 @@ void P_StepFrame(P_Frame *frame)
Vec2 fire_pos = Zi;
Vec2 fire_dir = Zi;
Vec2 fire_base = Zi;
if (can_fire)
{
Vec2 look = firer->control.look;
@ -2764,6 +2767,13 @@ void P_StepFrame(P_Frame *frame)
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));
fire_base = MulVec2(PerpVec2(NegVec2(firer->xf.r)), WedgeVec2(firer->xf.r, SubVec2(firer->xf.t, fire_pos)));
fire_base = AddVec2(fire_base, firer->xf.t);
P_DebugDrawLine(fire_base, fire_pos, Color_Yellow);
P_DebugDrawPoint(fire_base, Color_Yellow);
P_DebugDrawPoint(fire_pos, Color_Red);
}
// FIXME: Prevent obstructed weapons from firing through walls
@ -2795,6 +2805,7 @@ void P_StepFrame(P_Frame *frame)
Vec2 dir = Vec2FromAngle(angle);
bullet->bullet_base = fire_base;
bullet->bullet_start = fire_pos;
bullet->bullet_end = AddVec2(bullet->bullet_start, MulVec2(dir, speed));
bullet->bullet_firer = firer->key;
@ -2817,60 +2828,93 @@ void P_StepFrame(P_Frame *frame)
if (bullet->is_bullet)
{
bullet->has_hit = 0;
Vec2 ray_start = bullet->bullet_start;
Vec2 ray_end = bullet->bullet_end;
Vec2 ray_dir = SubVec2(ray_end, ray_start);
Struct(BulletPath)
{
BulletPath *next;
Vec2 start;
Vec2 end;
};
BulletPath *first_bullet_path = 0;
BulletPath *last_bullet_path = 0;
if (bullet->created_at_tick == frame->tick)
{
// On bullet's first tick, we want to ensure that the firer/weapon
// 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
// its actual firing path
BulletPath *path = PushStruct(scratch.arena, BulletPath);
SllQueuePush(first_bullet_path, last_bullet_path, path);
path->start = bullet->bullet_base;
path->end = bullet->bullet_start;
}
{
BulletPath *path = PushStruct(scratch.arena, BulletPath);
SllQueuePush(first_bullet_path, last_bullet_path, path);
path->start = bullet->bullet_start;
path->end = bullet->bullet_end;
}
P_DebugDrawLine(bullet->bullet_start, bullet->bullet_end, Color_Red);
P_Space *cast_spaces[] = {
&world->walls_space,
&post_solve_ents_space,
};
P_SpaceEntryList cast_entries = Zi;
P_UniqueSpaceEntriesFromRay(
scratch.arena,
&cast_entries,
countof(cast_spaces),
cast_spaces,
ray_start,
ray_end
);
P_EntKey victim_key = Zi;
P_RaycastResult victim_raycast = Zi;
{
f32 closest_len_sq = Inf;
for (P_SpaceEntryNode *entry_node = cast_entries.first; entry_node; entry_node = entry_node->next)
for (BulletPath *path = first_bullet_path; path; path = path->next)
{
P_SpaceEntry *entry = &entry_node->entry;
P_EntKey potential_victim_key = (P_EntKey) { .v = entry->shape_id };
if (!P_MatchEntKey(potential_victim_key, bullet->bullet_firer))
Vec2 path_dir = SubVec2(path->end, path->start);
P_Space *cast_spaces[] = {
&world->walls_space,
&post_solve_ents_space,
};
P_SpaceEntryList cast_entries = Zi;
P_UniqueSpaceEntriesFromRay(
scratch.arena,
&cast_entries,
countof(cast_spaces),
cast_spaces,
path->start,
path->end
);
f32 closest_len_sq = Inf;
for (P_SpaceEntryNode *entry_node = cast_entries.first; entry_node; entry_node = entry_node->next)
{
P_Shape potential_victim_shape = entry->shape;
P_RaycastResult entrance_raycast = P_RaycastShape(potential_victim_shape, ray_start, ray_dir);
Vec2 entrance = entrance_raycast.p;
if (entrance_raycast.is_intersecting)
P_SpaceEntry *entry = &entry_node->entry;
P_EntKey potential_victim_key = (P_EntKey) { .v = entry->shape_id };
if (!P_MatchEntKey(potential_victim_key, bullet->bullet_firer))
{
P_RaycastResult exit_raycast = P_RaycastShape(potential_victim_shape, ray_start, NegVec2(ray_dir));
Vec2 exit = exit_raycast.p;
f32 da = DotVec2(ray_dir, SubVec2(entrance, ray_start));
f32 db = DotVec2(ray_dir, SubVec2(exit, ray_start));
if (db > 0 && (da <= Vec2LenSq(ray_dir) || da <= 0))
P_Shape potential_victim_shape = entry->shape;
P_RaycastResult entrance_raycast = P_RaycastShape(potential_victim_shape, path->start, path_dir);
Vec2 entrance = entrance_raycast.p;
if (entrance_raycast.is_intersecting)
{
f32 len_sq = Vec2LenSq(SubVec2(entrance_raycast.p, ray_start));
if (len_sq < closest_len_sq)
P_RaycastResult exit_raycast = P_RaycastShape(potential_victim_shape, path->start, NegVec2(path_dir));
Vec2 exit = exit_raycast.p;
f32 da = DotVec2(path_dir, SubVec2(entrance, path->start));
f32 db = DotVec2(path_dir, SubVec2(exit, path->start));
if (db > 0 && (da <= Vec2LenSq(path_dir) || da <= 0))
{
closest_len_sq = len_sq;
victim_key = potential_victim_key;
victim_raycast = entrance_raycast;
f32 len_sq = Vec2LenSq(SubVec2(entrance_raycast.p, path->start));
if (len_sq < closest_len_sq)
{
closest_len_sq = len_sq;
victim_key = potential_victim_key;
victim_raycast = entrance_raycast;
}
}
}
}
}
if (!P_IsEntKeyNil(victim_key))
{
// No need to check future paths if this path hit
break;
}
}
}
P_Ent *victim = P_EntFromKey(frame, victim_key);
// TODO: Truncate bullet trail

View File

@ -110,6 +110,7 @@ Struct(P_Ent)
P_EntKey key;
u64 rand_seq;
i64 created_at_ns;
i64 created_at_tick;
//- Build data
@ -129,6 +130,7 @@ Struct(P_Ent)
P_EntKey bullet_firer;
b32 is_bullet;
Vec2 bullet_base;
Vec2 bullet_start;
Vec2 bullet_end;