mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
P_TryMove: sweep collided lines to find nearest normal
This commit is contained in:
parent
5a62a07e54
commit
7861d51a7f
6 changed files with 238 additions and 54 deletions
|
|
@ -65,6 +65,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
|
|||
p_user.c
|
||||
p_slopes.c
|
||||
p_sweep.cpp
|
||||
p_test.cpp
|
||||
tables.c
|
||||
r_bsp.cpp
|
||||
r_data.c
|
||||
|
|
|
|||
|
|
@ -806,6 +806,7 @@ consvar_t cv_numlaps = OnlineCheat("numlaps", "Map default").values(numlaps_cons
|
|||
|
||||
consvar_t cv_restrictskinchange = OnlineCheat("restrictskinchange", "Yes").yes_no().description("Don't let players change their skin in the middle of gameplay");
|
||||
consvar_t cv_spbtest = OnlineCheat("spbtest", "Off").on_off().description("SPB can never target a player");
|
||||
consvar_t cv_showgremlins = OnlineCheat("showgremlins", "No").yes_no().description("Show line collision errors");
|
||||
consvar_t cv_timescale = OnlineCheat(cvlist_timer)("timescale", "1.0").floating_point().min_max(FRACUNIT/20, 20*FRACUNIT).description("Overclock or slow down the game");
|
||||
consvar_t cv_ufo_follow = OnlineCheat("ufo_follow", "0").min_max(0, MAXPLAYERS).description("Make UFO Catcher folow this player");
|
||||
consvar_t cv_ufo_health = OnlineCheat("ufo_health", "-1").min_max(-1, 100).description("Override UFO Catcher health -- applied at spawn or when value is changed");
|
||||
|
|
|
|||
|
|
@ -387,9 +387,16 @@ struct tm_t
|
|||
// so missiles don't explode against sky hack walls
|
||||
line_t *ceilingline;
|
||||
|
||||
// set by PIT_CheckLine() for any line that stopped the PIT_CheckLine()
|
||||
// that is, for any line which is 'solid'
|
||||
line_t *blockingline;
|
||||
// P_CheckPosition: this position blocks movement
|
||||
boolean blocking;
|
||||
|
||||
// P_CheckPosition: set this before each call to
|
||||
// P_CheckPosition to enable a line sweep on collided
|
||||
// lines
|
||||
boolean sweep;
|
||||
|
||||
// sweep: max step up at tm.x, tm.y
|
||||
fixed_t maxstep;
|
||||
};
|
||||
|
||||
extern tm_t tm;
|
||||
|
|
@ -415,6 +422,7 @@ struct TryMoveResult_t
|
|||
boolean success;
|
||||
line_t *line;
|
||||
mobj_t *mo;
|
||||
vector2_t normal;
|
||||
};
|
||||
|
||||
boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y, TryMoveResult_t *result);
|
||||
|
|
@ -422,6 +430,10 @@ boolean P_CheckMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff, T
|
|||
boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff, TryMoveResult_t *result);
|
||||
boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y, TryMoveResult_t *result);
|
||||
|
||||
void P_TestLine(line_t *ld);
|
||||
void P_ClearTestLines(void);
|
||||
line_t *P_SweepTestLines(fixed_t ax, fixed_t ay, fixed_t bx, fixed_t by, fixed_t r, vector2_t *return_normal);
|
||||
|
||||
boolean P_IsLineBlocking(const line_t *ld, const mobj_t *thing);
|
||||
boolean P_IsLineTripWire(const line_t *ld);
|
||||
boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam);
|
||||
|
|
|
|||
188
src/p_map.c
188
src/p_map.c
|
|
@ -1770,7 +1770,6 @@ static BlockItReturn_t PIT_CheckCameraLine(line_t *ld)
|
|||
// could be crossed in either order.
|
||||
|
||||
// this line is out of the if so upper and lower textures can be hit by a splat
|
||||
tm.blockingline = ld;
|
||||
if (!ld->backsector) // one sided line
|
||||
{
|
||||
if (P_PointOnLineSide(mapcampointer->x, mapcampointer->y, ld))
|
||||
|
|
@ -1841,6 +1840,22 @@ boolean P_IsLineTripWire(const line_t *ld)
|
|||
return ld->tripwire;
|
||||
}
|
||||
|
||||
static boolean P_UsingStepUp(mobj_t *thing)
|
||||
{
|
||||
if (thing->flags & MF_NOCLIP)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// orbits have no collision
|
||||
if (thing->player && thing->player->loop.radius)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// PIT_CheckLine
|
||||
// Adjusts tm.floorz and tm.ceilingz as lines are contacted
|
||||
|
|
@ -1898,14 +1913,20 @@ static BlockItReturn_t PIT_CheckLine(line_t *ld)
|
|||
// could be crossed in either order.
|
||||
|
||||
// this line is out of the if so upper and lower textures can be hit by a splat
|
||||
tm.blockingline = ld;
|
||||
|
||||
{
|
||||
UINT8 shouldCollide = LUA_HookMobjLineCollide(tm.thing, tm.blockingline); // checks hook for thing's type
|
||||
UINT8 shouldCollide = LUA_HookMobjLineCollide(tm.thing, ld); // checks hook for thing's type
|
||||
if (P_MobjWasRemoved(tm.thing))
|
||||
return BMIT_CONTINUE; // one of them was removed???
|
||||
if (shouldCollide == 1)
|
||||
return BMIT_ABORT; // force collide
|
||||
{
|
||||
if (tm.sweep)
|
||||
{
|
||||
P_TestLine(ld);
|
||||
}
|
||||
tm.blocking = true; // force collide
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
else if (shouldCollide == 2)
|
||||
return BMIT_CONTINUE; // force no collide
|
||||
}
|
||||
|
|
@ -1914,15 +1935,55 @@ static BlockItReturn_t PIT_CheckLine(line_t *ld)
|
|||
{
|
||||
if (P_PointOnLineSide(tm.thing->x, tm.thing->y, ld))
|
||||
return BMIT_CONTINUE; // don't hit the back side
|
||||
return BMIT_ABORT;
|
||||
|
||||
if (tm.sweep)
|
||||
{
|
||||
P_TestLine(ld);
|
||||
}
|
||||
tm.blocking = true;
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
|
||||
if (P_IsLineBlocking(ld, tm.thing))
|
||||
return BMIT_ABORT;
|
||||
{
|
||||
if (tm.sweep)
|
||||
{
|
||||
P_TestLine(ld);
|
||||
}
|
||||
tm.blocking = true;
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
|
||||
// set openrange, opentop, openbottom
|
||||
P_LineOpening(ld, tm.thing, &open);
|
||||
|
||||
if (tm.sweep && P_UsingStepUp(tm.thing))
|
||||
{
|
||||
// copied from P_TryMove
|
||||
// TODO: refactor this into one place
|
||||
if (open.range < tm.thing->height)
|
||||
{
|
||||
P_TestLine(ld);
|
||||
}
|
||||
else if (tm.maxstep > 0)
|
||||
{
|
||||
if (tm.thing->z < open.floor)
|
||||
{
|
||||
if (open.floorstep > tm.maxstep)
|
||||
{
|
||||
P_TestLine(ld);
|
||||
}
|
||||
}
|
||||
else if (open.ceiling < tm.thing->z + tm.thing->height)
|
||||
{
|
||||
if (open.ceilingstep > tm.maxstep)
|
||||
{
|
||||
P_TestLine(ld);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// adjust floor / ceiling heights
|
||||
if (open.ceiling < tm.ceilingz)
|
||||
{
|
||||
|
|
@ -2042,7 +2103,8 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y, TryMoveResult_t *re
|
|||
tm.bbox[BOXLEFT] = x - tm.thing->radius;
|
||||
|
||||
newsubsec = R_PointInSubsector(x, y);
|
||||
tm.ceilingline = tm.blockingline = NULL;
|
||||
tm.ceilingline = NULL;
|
||||
tm.blocking = false;
|
||||
|
||||
// The base floor / ceiling is from the subsector
|
||||
// that contains the point.
|
||||
|
|
@ -2314,23 +2376,33 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y, TryMoveResult_t *re
|
|||
|
||||
validcount++;
|
||||
|
||||
P_ClearTestLines();
|
||||
|
||||
// check lines
|
||||
for (bx = xl; bx <= xh; bx++)
|
||||
{
|
||||
for (by = yl; by <= yh; by++)
|
||||
{
|
||||
if (!P_BlockLinesIterator(bx, by, PIT_CheckLine))
|
||||
P_BlockLinesIterator(bx, by, PIT_CheckLine);
|
||||
}
|
||||
}
|
||||
|
||||
if (tm.blocking)
|
||||
{
|
||||
blockval = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result != NULL)
|
||||
{
|
||||
result->line = tm.blockingline;
|
||||
result->line = NULL;
|
||||
result->mo = tm.hitthing;
|
||||
}
|
||||
else
|
||||
{
|
||||
P_ClearTestLines();
|
||||
}
|
||||
|
||||
tm.sweep = false;
|
||||
|
||||
return blockval;
|
||||
}
|
||||
|
|
@ -2379,7 +2451,7 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam)
|
|||
tm.bbox[BOXLEFT] = x - thiscam->radius;
|
||||
|
||||
newsubsec = R_PointInSubsector(x, y);
|
||||
tm.ceilingline = tm.blockingline = NULL;
|
||||
tm.ceilingline = NULL;
|
||||
|
||||
mapcampointer = thiscam;
|
||||
|
||||
|
|
@ -2753,22 +2825,6 @@ fixed_t P_GetThingStepUp(mobj_t *thing, fixed_t destX, fixed_t destY)
|
|||
return maxstep;
|
||||
}
|
||||
|
||||
static boolean P_UsingStepUp(mobj_t *thing)
|
||||
{
|
||||
if (thing->flags & MF_NOCLIP)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// orbits have no collision
|
||||
if (thing->player && thing->player->loop.radius)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static boolean
|
||||
increment_move
|
||||
( mobj_t * thing,
|
||||
|
|
@ -2821,7 +2877,29 @@ increment_move
|
|||
tryy = y;
|
||||
}
|
||||
|
||||
if (!P_CheckPosition(thing, tryx, tryy, result))
|
||||
if (P_UsingStepUp(thing))
|
||||
{
|
||||
tm.maxstep = P_GetThingStepUp(thing, tryx, tryy);
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
tm.sweep = true;
|
||||
}
|
||||
|
||||
boolean move_ok = P_CheckPosition(thing, tryx, tryy, result);
|
||||
|
||||
if (P_MobjWasRemoved(thing))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
result->line = P_SweepTestLines(thing->x, thing->y, x, y, thing->radius, &result->normal);
|
||||
}
|
||||
|
||||
if (!move_ok)
|
||||
{
|
||||
return false; // solid wall or thing
|
||||
}
|
||||
|
|
@ -3466,30 +3544,27 @@ static void P_HitSlideLine(line_t *ld)
|
|||
//
|
||||
// HitBounceLine, for players
|
||||
//
|
||||
static void P_PlayerHitBounceLine(line_t *ld)
|
||||
static void P_PlayerHitBounceLine(line_t *ld, vector2_t* normal)
|
||||
{
|
||||
INT32 side;
|
||||
angle_t lineangle;
|
||||
fixed_t movelen;
|
||||
fixed_t x, y;
|
||||
|
||||
side = P_PointOnLineSide(slidemo->x, slidemo->y, ld);
|
||||
lineangle = ld->angle - ANGLE_90;
|
||||
|
||||
if (side == 1)
|
||||
lineangle += ANGLE_180;
|
||||
|
||||
lineangle >>= ANGLETOFINESHIFT;
|
||||
|
||||
movelen = P_AproxDistance(tmxmove, tmymove);
|
||||
|
||||
if (slidemo->player && movelen < (15*mapobjectscale))
|
||||
movelen = (15*mapobjectscale);
|
||||
|
||||
x = FixedMul(movelen, FINECOSINE(lineangle));
|
||||
y = FixedMul(movelen, FINESINE(lineangle));
|
||||
if (!ld)
|
||||
{
|
||||
angle_t th = R_PointToAngle2(0, 0, tmxmove, tmymove);
|
||||
normal->x = -FCOS(th);
|
||||
normal->y = -FSIN(th);
|
||||
}
|
||||
|
||||
if (P_IsLineTripWire(ld))
|
||||
x = FixedMul(movelen, normal->x);
|
||||
y = FixedMul(movelen, normal->y);
|
||||
|
||||
if (ld && P_IsLineTripWire(ld))
|
||||
{
|
||||
tmxmove = x * 4;
|
||||
tmymove = y * 4;
|
||||
|
|
@ -3958,6 +4033,8 @@ papercollision:
|
|||
|
||||
static void P_BouncePlayerMove(mobj_t *mo, TryMoveResult_t *result)
|
||||
{
|
||||
extern consvar_t cv_showgremlins;
|
||||
|
||||
fixed_t mmomx = 0, mmomy = 0;
|
||||
fixed_t oldmomx = mo->momx, oldmomy = mo->momy;
|
||||
|
||||
|
|
@ -3982,8 +4059,23 @@ static void P_BouncePlayerMove(mobj_t *mo, TryMoveResult_t *result)
|
|||
slidemo = mo;
|
||||
bestslideline = result->line;
|
||||
|
||||
if (bestslideline == NULL)
|
||||
return;
|
||||
if (bestslideline == NULL && cv_showgremlins.value)
|
||||
{
|
||||
// debug
|
||||
mobj_t*x = P_SpawnMobj(mo->x, mo->y, mo->z, MT_THOK);
|
||||
x->frame = FF_FULLBRIGHT | FF_ADD;
|
||||
x->renderflags = RF_ALWAYSONTOP;
|
||||
x->color = SKINCOLOR_RED;
|
||||
|
||||
CONS_Printf(
|
||||
"GREMLIN: leveltime=%u x=%f y=%f z=%f angle=%f\n",
|
||||
leveltime,
|
||||
FixedToFloat(mo->x),
|
||||
FixedToFloat(mo->y),
|
||||
FixedToFloat(mo->z),
|
||||
AngleToFloat(R_PointToAngle2(0, 0, oldmomx, oldmomy))
|
||||
);
|
||||
}
|
||||
|
||||
if (mo->eflags & MFE_JUSTBOUNCEDWALL) // Stronger push-out
|
||||
{
|
||||
|
|
@ -3996,7 +4088,7 @@ static void P_BouncePlayerMove(mobj_t *mo, TryMoveResult_t *result)
|
|||
tmymove = FixedMul(mmomy, (FRACUNIT - (FRACUNIT>>2) - (FRACUNIT>>3)));
|
||||
}
|
||||
|
||||
if (P_IsLineTripWire(bestslideline))
|
||||
if (bestslideline && P_IsLineTripWire(bestslideline))
|
||||
{
|
||||
// TRIPWIRE CANNOT BE MADE NONBOUNCY
|
||||
K_ApplyTripWire(mo->player, TRIPSTATE_BLOCKED);
|
||||
|
|
@ -4014,7 +4106,7 @@ static void P_BouncePlayerMove(mobj_t *mo, TryMoveResult_t *result)
|
|||
K_SpawnBumpEffect(mo);
|
||||
}
|
||||
|
||||
P_PlayerHitBounceLine(bestslideline);
|
||||
P_PlayerHitBounceLine(bestslideline, &result->normal);
|
||||
mo->eflags |= MFE_JUSTBOUNCEDWALL;
|
||||
|
||||
mo->momx = tmxmove;
|
||||
|
|
@ -4022,7 +4114,7 @@ static void P_BouncePlayerMove(mobj_t *mo, TryMoveResult_t *result)
|
|||
mo->player->cmomx = tmxmove;
|
||||
mo->player->cmomy = tmymove;
|
||||
|
||||
if (!P_IsLineTripWire(bestslideline))
|
||||
if (!bestslideline || !P_IsLineTripWire(bestslideline))
|
||||
{
|
||||
if (!P_TryMove(mo, mo->x + tmxmove, mo->y + tmymove, true, NULL))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1671,7 +1671,7 @@ void P_XYMovement(mobj_t *mo)
|
|||
// blocked move
|
||||
moved = false;
|
||||
|
||||
if (LUA_HookMobjMoveBlocked(mo, tm.hitthing, tm.blockingline))
|
||||
if (LUA_HookMobjMoveBlocked(mo, tm.hitthing, result.line))
|
||||
{
|
||||
if (P_MobjWasRemoved(mo))
|
||||
return;
|
||||
|
|
@ -1679,7 +1679,7 @@ void P_XYMovement(mobj_t *mo)
|
|||
else if (P_MobjWasRemoved(mo))
|
||||
return;
|
||||
|
||||
P_PushSpecialLine(tm.blockingline, mo);
|
||||
P_PushSpecialLine(result.line, mo);
|
||||
|
||||
if (mo->flags & MF_MISSILE)
|
||||
{
|
||||
|
|
|
|||
78
src/p_test.cpp
Normal file
78
src/p_test.cpp
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 by James Robert Roman
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include "math/fixed.hpp"
|
||||
#include "p_sweep.hpp"
|
||||
|
||||
#include "p_local.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
std::vector<line_t*> g_lines;
|
||||
|
||||
};
|
||||
|
||||
void P_TestLine(line_t* ld)
|
||||
{
|
||||
g_lines.emplace_back(ld);
|
||||
}
|
||||
|
||||
line_t* P_SweepTestLines(fixed_t ax, fixed_t ay, fixed_t bx, fixed_t by, fixed_t r, vector2_t* return_normal)
|
||||
{
|
||||
using namespace srb2::math;
|
||||
using namespace srb2::sweep;
|
||||
|
||||
struct Collision
|
||||
{
|
||||
unit z;
|
||||
vec2 normal;
|
||||
line_t* ld;
|
||||
|
||||
bool operator<(const Collision& b) const { return z < b.z; }
|
||||
};
|
||||
|
||||
std::optional<Collision> collision;
|
||||
|
||||
LineSegment<Fixed> l{{ax, ay}, {bx, by}};
|
||||
AABBvsLine sweep{r, l};
|
||||
|
||||
for (line_t* ld : g_lines)
|
||||
{
|
||||
LineSegment<Fixed> ls{{ld->v1->x, ld->v1->y}, {ld->v2->x, ld->v2->y}};
|
||||
Result rs = sweep(ls);
|
||||
if (rs.hit)
|
||||
{
|
||||
if (!collision || rs.hit->z < collision->z)
|
||||
{
|
||||
collision = {rs.hit->z, rs.hit->n, ld};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_lines.clear();
|
||||
|
||||
if (!collision)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return_normal->x = Fixed {collision->normal.x};
|
||||
return_normal->y = Fixed {collision->normal.y};
|
||||
|
||||
return collision->ld;
|
||||
}
|
||||
|
||||
void P_ClearTestLines(void)
|
||||
{
|
||||
g_lines.clear();
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue