prevent players from firing through walls
This commit is contained in:
parent
45ac2bf1af
commit
8405d039af
120
src/pp/pp.c
120
src/pp/pp.c
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user