- reimplemented the wall collision check for clipmove.

This commit is contained in:
Christoph Oelckers 2022-10-22 23:12:29 +02:00
parent aed69bd4c2
commit 9b8252e2da
4 changed files with 85 additions and 25 deletions

View file

@ -221,8 +221,6 @@ CollisionBase clipmove_(vec3_t * const pos, int * const sectnum, int32_t xvect,
if ((xvect|yvect) == 0 || *sectnum < 0) if ((xvect|yvect) == 0 || *sectnum < 0)
return b; return b;
DCoreActor* curspr=NULL; // non-NULL when handling sprite with sector-like clipping
int const initialsectnum = *sectnum; int const initialsectnum = *sectnum;
int32_t const dawalclipmask = (cliptype & 65535); // CLIPMASK0 = 0x00010001 (in desperate need of getting fixed!) int32_t const dawalclipmask = (cliptype & 65535); // CLIPMASK0 = 0x00010001 (in desperate need of getting fixed!)
@ -237,6 +235,16 @@ CollisionBase clipmove_(vec3_t * const pos, int * const sectnum, int32_t xvect,
int32_t const rad = ksqrt((int64_t)diff.X * diff.X + (int64_t)diff.Y * diff.Y) + MAXCLIPDIST + walldist + 8; int32_t const rad = ksqrt((int64_t)diff.X * diff.X + (int64_t)diff.Y * diff.Y) + MAXCLIPDIST + walldist + 8;
vec2_t const clipMin = { cent.X - rad, cent.Y - rad }; vec2_t const clipMin = { cent.X - rad, cent.Y - rad };
vec2_t const clipMax = { cent.X + rad, cent.Y + rad }; vec2_t const clipMax = { cent.X + rad, cent.Y + rad };
MoveClipper clip;
clip.moveDelta = { (xvect >> 14) * inttoworld, (yvect >> 14) * inttoworld }; // beware of excess precision here!
clip.rect.min = { clipMin.X * inttoworld, clipMin.Y * inttoworld };
clip.rect.max = { clipMax.X * inttoworld, clipMax.Y * inttoworld };
clip.wallflags = EWallFlags::FromInt(dawalclipmask);
clip.ceilingdist = ceildist * zinttoworld;
clip.floordist = flordist * zinttoworld;
clip.walldist = walldist * inttoworld;
int clipsectcnt = 0; int clipsectcnt = 0;
int clipspritecnt = 0; int clipspritecnt = 0;
@ -255,33 +263,44 @@ CollisionBase clipmove_(vec3_t * const pos, int * const sectnum, int32_t xvect,
do do
{ {
int const dasect = clipsectorlist[clipsectcnt++]; int const dasect = clipsectorlist[clipsectcnt++];
//if (curspr)
// Printf("sprite %d/%d: sect %d/%d (%d)\n", clipspritecnt,clipspritenum, clipsectcnt,clipsectnum,dasect);
////////// Walls ////////// ////////// Walls //////////
auto const sec = &sector[dasect]; auto const sec = &sector[dasect];
for (auto& wal : sec->walls) for (auto& wal : sec->walls)
{ {
clip.pos = { pos->X * inttoworld, pos->Y * inttoworld, pos->Z * zinttoworld};
int clipyou2 = checkClipWall(clip, &wal);
auto const wal2 = wal.point2Wall(); auto const wal2 = wal.point2Wall();
vec2_t p1 = wal.wall_int_pos(); vec2_t p1 = wal.wall_int_pos();
vec2_t p2 = wal2->wall_int_pos(); vec2_t p2 = wal2->wall_int_pos();
if ((p1.X < clipMin.X && p2.X < clipMin.X) || (p1.X > clipMax.X && p2.X > clipMax.X) || if ((p1.X < clipMin.X && p2.X < clipMin.X) || (p1.X > clipMax.X && p2.X > clipMax.X) ||
(p1.Y < clipMin.Y && p2.Y < clipMin.Y) || (p1.Y > clipMax.Y && p2.Y > clipMax.Y)) (p1.Y < clipMin.Y && p2.Y < clipMin.Y) || (p1.Y > clipMax.Y && p2.Y > clipMax.Y))
{
assert(clipyou2 != 1);
continue; continue;
}
vec2_t d = { p2.X-p1.X, p2.Y-p1.Y }; vec2_t d = { p2.X-p1.X, p2.Y-p1.Y };
if (d.X * (pos->Y-p1.Y) < (pos->X-p1.X) * d.Y) if (d.X * (pos->Y-p1.Y) < (pos->X-p1.X) * d.Y)
continue; //If wall's not facing you {
assert(clipyou2 != 1);
continue;
}
vec2_t const r = { (d.Y > 0) ? clipMax.X : clipMin.X, (d.X > 0) ? clipMin.Y : clipMax.Y }; vec2_t const r = { (d.Y > 0) ? clipMax.X : clipMin.X, (d.X > 0) ? clipMin.Y : clipMax.Y };
vec2_t v = { d.X * (r.Y - p1.Y), d.Y * (r.X - p1.X) }; vec2_t v = { d.X * (r.Y - p1.Y), d.Y * (r.X - p1.X) };
if (v.X >= v.Y) if (v.X >= v.Y)
{
assert(clipyou2 != 1);
continue; continue;
}
int clipyou = 0; int clipyou = 0;
@ -297,31 +316,14 @@ CollisionBase clipmove_(vec3_t * const pos, int * const sectnum, int32_t xvect,
ceildist * zinttoworld, flordist * zinttoworld, enginecompatibility_mode == ENGINECOMPATIBILITY_NONE); ceildist * zinttoworld, flordist * zinttoworld, enginecompatibility_mode == ENGINECOMPATIBILITY_NONE);
v.X = int(ipos.X * worldtoint); v.X = int(ipos.X * worldtoint);
v.Y = int(ipos.Y * worldtoint); v.Y = int(ipos.Y * worldtoint);
} }
// We're not interested in any sector reached by portal traversal that we're "inside" of.
if (enginecompatibility_mode == ENGINECOMPATIBILITY_NONE && !curspr && dasect != initialsectnum
&& inside(pos->X * inttoworld, pos->Y * inttoworld, sec) == 1)
{
bool found = false;
for (auto& wwal : sec->walls)
{
if (wwal.nextsector == initialsectnum)
{
found = true;
break;
}
}
if (!found)
break;
}
assert(clipyou == clipyou2);
if (clipyou) if (clipyou)
{ {
CollisionBase objtype; CollisionBase objtype;
if (curspr) objtype.setSprite(curspr); objtype.setWall(&wal);
else objtype.setWall(&wal);
//Add 2 boxes at endpoints //Add 2 boxes at endpoints
int32_t bsz = walldist; if (diff.X < 0) bsz = -bsz; int32_t bsz = walldist; if (diff.X < 0) bsz = -bsz;
@ -331,6 +333,7 @@ CollisionBase clipmove_(vec3_t * const pos, int * const sectnum, int32_t xvect,
addclipline(p1.X+bsz, p1.Y-bsz, p1.X-bsz, p1.Y-bsz, objtype, false); addclipline(p1.X+bsz, p1.Y-bsz, p1.X-bsz, p1.Y-bsz, objtype, false);
addclipline(p2.X+bsz, p2.Y-bsz, p2.X-bsz, p2.Y-bsz, objtype, false); addclipline(p2.X+bsz, p2.Y-bsz, p2.X-bsz, p2.Y-bsz, objtype, false);
vec2_t v;
v.X = walldist; if (d.Y > 0) v.X = -v.X; v.X = walldist; if (d.Y > 0) v.X = -v.X;
v.Y = walldist; if (d.X < 0) v.Y = -v.Y; v.Y = walldist; if (d.X < 0) v.Y = -v.Y;

View file

@ -232,3 +232,11 @@ inline bool BoxInRange(const DVector2& boxtl, const DVector2& boxbr, const DVect
boxtl.Y < max(start.Y, end.Y) && boxtl.Y < max(start.Y, end.Y) &&
boxbr.Y > min(start.Y, end.Y); boxbr.Y > min(start.Y, end.Y);
} }
inline bool BoxInRange2(const DVector2& boxtl, const DVector2& boxbr, const DVector2& start, const DVector2& end)
{
return boxtl.X <= max(start.X, end.X) &&
boxbr.X >= min(start.X, end.X) &&
boxtl.Y <= max(start.Y, end.Y) &&
boxbr.Y >= min(start.Y, end.Y);
}

View file

@ -1230,6 +1230,38 @@ int pushmove(DVector3& pos, sectortype** pSect, double walldist, double ceildist
// //
//========================================================================== //==========================================================================
int checkClipWall(const MoveClipper& clip, walltype* wal)
{
auto wal2 = wal->point2Wall();
auto waldelta = wal->delta();
// out of reach?
if (!BoxInRange2(clip.rect.min, clip.rect.max, wal->pos, wal2->pos)) return -1;
// facing back side?
if (PointOnLineSide(clip.pos.XY(), wal) > 0) return -1;
// do we touch it?
if (BoxOnLineSide(clip.rect.min, clip.rect.max, wal->pos, waldelta) != -1) return -1;
if (!wal->twoSided() || (wal->cstat & clip.wallflags))
return 1;
else
{
DVector2 intersect;
double factor = InterceptLineSegments(clip.pos.X, clip.pos.Y, clip.moveDelta.X, clip.moveDelta.Y, wal->pos.X, wal->pos.Y, waldelta.X, waldelta.Y);
if (factor < 0) intersect = clip.pos.XY();
else intersect = clip.pos.XY() + clip.moveDelta * factor;
return checkOpening(intersect, clip.pos.Z, wal->sectorp(), wal->nextSector(), clip.ceilingdist, clip.floordist);
}
}
//==========================================================================
//
//
//
//==========================================================================
int FindBestSector(const DVector3& pos) int FindBestSector(const DVector3& pos)
{ {
int bestnum = -1; int bestnum = -1;

View file

@ -234,8 +234,25 @@ inline int pushmove(DVector2& pos, double z, sectortype** pSect, double walldist
pos = vect.XY(); pos = vect.XY();
return result; return result;
} }
struct ClipRect
{
DVector2 min;
DVector2 max;
};
struct MoveClipper
{
DVector3 pos;
DVector2 pest;
DVector2 moveDelta;
ClipRect rect;
EWallFlags wallflags;
double ceilingdist;
double floordist;
double walldist;
};
int checkClipWall(const MoveClipper& clip, walltype* wal);
int FindBestSector(const DVector3& pos); int FindBestSector(const DVector3& pos);