From 932ccec21b76b7f0c4f32e65d843eeeb73acd5b4 Mon Sep 17 00:00:00 2001 From: Daniel Schepler Date: Mon, 28 Mar 2005 01:56:40 +0000 Subject: [PATCH] Preliminary version of wall handling. Manny still gets stuck at walls, but he now turns until he can move forward again. --- actor.cpp | 66 ++++++++++++++++++++++++++++++++++++++++++++------- actor.h | 2 ++ lua.cpp | 9 ++++++- vector3d.h | 4 ++++ walkplane.cpp | 35 +++++++++++++++++++++++++++ walkplane.h | 9 +++++++ 6 files changed, 116 insertions(+), 9 deletions(-) diff --git a/actor.cpp b/actor.cpp index c4c0740b108..98fd1531145 100644 --- a/actor.cpp +++ b/actor.cpp @@ -34,6 +34,7 @@ Actor::Actor(const char *name) : _name(name), _talkColor(255, 255, 255), _pos(0, 0, 0), _pitch(0), _yaw(0), _roll(0), _walkRate(0), _turnRate(0), + _reflectionAngle(80), _visible(true), _lipSynch(NULL), _turning(false), _walking(false), _restCostume(NULL), _restChore(-1), _walkCostume(NULL), _walkChore(-1), _walkedLast(false), _walkedCur(false), @@ -98,16 +99,65 @@ void Actor::walkForward() { std::sin(pitch_rad)); Vector3d destPos = _pos + forwardVec * dist; - if (!_constrain) { - _pos = destPos; + if (! _constrain) { + _pos += forwardVec * dist; _walkedCur = true; - } else { - Sector *sector = g_engine->currScene()->findPointSector(destPos, 0x1000); - if (sector != NULL) { - _pos = sector->projectToPlane(destPos); - _walkedCur = true; - } + return; } + + if (dist < 0) { + dist = -dist; + forwardVec = -forwardVec; + } + + Sector *currSector = NULL, *prevSector = NULL; + Sector::ExitInfo ei; + + g_engine->currScene()->findClosestSector(_pos, &currSector, &_pos); + if (currSector == NULL) { // Shouldn't happen... + _pos += forwardVec * dist; + _walkedCur = true; + return; + } + + while (currSector != NULL) { + prevSector = currSector; + Vector3d puckVector = currSector->projectToPuckVector(forwardVec); + puckVector /= puckVector.magnitude(); + currSector->getExitInfo(_pos, puckVector, &ei); + float exitDist = (ei.exitPoint - _pos).magnitude(); + if (dist < exitDist) { + _pos += puckVector * dist; + _walkedCur = true; + return; + } + _pos = ei.exitPoint; + dist -= exitDist; + if (exitDist > 0.0001) + _walkedCur = true; + + // Check for an adjacent sector which can continue + // the path + currSector = g_engine->currScene()->findPointSector(ei.exitPoint + 0.0001 * puckVector, 0x1000); + if (currSector == prevSector) + break; + } + + ei.angleWithEdge *= (180.0 / M_PI); + int turnDir = 1; + if (ei.angleWithEdge > 90) { + ei.angleWithEdge = 180 - ei.angleWithEdge; + ei.edgeDir = -ei.edgeDir; + turnDir = -1; + } + if (ei.angleWithEdge > _reflectionAngle) + return; + + ei.angleWithEdge += 0.1; + float turnAmt = g_engine->perSecond(_turnRate); + if (turnAmt > ei.angleWithEdge) + turnAmt = ei.angleWithEdge; + _yaw += turnAmt * turnDir; } Vector3d Actor::puckVector() const { diff --git a/actor.h b/actor.h index f8220efd8fd..11978df8ade 100644 --- a/actor.h +++ b/actor.h @@ -66,6 +66,7 @@ public: return _setName == name; } void walkForward(); + void setReflection(float angle) { _reflectionAngle = angle; } Vector3d puckVector() const; void turn(int dir); @@ -125,6 +126,7 @@ private: float _walkRate, _turnRate; bool _constrain; // Constrain to walkboxes + float _reflectionAngle; // Maximum angle to turn by at walls bool _visible; bool _lookingMode; std::string _talkSoundName; diff --git a/lua.cpp b/lua.cpp index 85d6f07bf51..f86698fa8ed 100644 --- a/lua.cpp +++ b/lua.cpp @@ -457,6 +457,12 @@ static void WalkActorForward() { act->walkForward(); } +static void SetActorReflection() { + Actor *act = check_actor(1); + float angle = luaL_check_number(2); + act->setReflection(angle); +} + static void GetActorPuckVector() { Actor *act = check_actor(1); Vector3d result = act->puckVector(); @@ -1584,7 +1590,6 @@ STUB_FUNC(SetActorWalkDominate) STUB_FUNC(GetCameraActor) STUB_FUNC(DriveActorTo) STUB_FUNC(WalkActorVector) -STUB_FUNC(SetActorReflection) STUB_FUNC(GetActorRect) STUB_FUNC(GetActorNodeLocation) STUB_FUNC(SetActorTimeScale) @@ -1924,6 +1929,8 @@ struct luaL_reg mainOpcodes[] = { { "PutActorInSet", PutActorInSet }, { "WalkActorVector", WalkActorVector }, { "WalkActorForward", WalkActorForward }, + { "SetActorReflection", SetActorReflection }, + { "GetActorPuckVector", GetActorPuckVector }, { "DriveActorTo", DriveActorTo }, { "WalkActorTo", WalkActorTo }, { "WalkActorToAvoiding", WalkActorToAvoiding }, diff --git a/vector3d.h b/vector3d.h index 6c11193413e..e6163751e0f 100644 --- a/vector3d.h +++ b/vector3d.h @@ -125,6 +125,10 @@ inline Vector3d operator *(float s, const Vector3d& v) { return result; } +inline Vector3d operator -(const Vector3d& v) { + return (-1.0f) * v; +} + inline Vector3d operator *(const Vector3d& v, float s) { return s * v; } diff --git a/walkplane.cpp b/walkplane.cpp index f036062a265..21c1fac2fba 100644 --- a/walkplane.cpp +++ b/walkplane.cpp @@ -160,3 +160,38 @@ Vector3d Sector::closestPoint(Vector3d point) const { } return _vertices[index]; } + +void Sector::getExitInfo(Vector3d start, Vector3d dir, + struct ExitInfo *result) { + start = projectToPlane(start); + dir = projectToPuckVector(dir); + + // First find the edge the ray exits through: this is where + // the z-component of (v_i - start) x dir changes sign from + // positive to negative. + + // First find a vertex such that the cross product has + // positive z-component. + int i; + for (i = 0; i < _numVertices; i++) { + Vector3d delta = _vertices[i] - start; + if (delta.x() * dir.y() > delta.y() * dir.x()) + break; + } + + // Now continue until the cross product has negative + // z-component. + while (i < _numVertices) { + i++; + Vector3d delta = _vertices[i] - start; + if (delta.x() * dir.y() <= delta.y() * dir.x()) + break; + } + + result->edgeDir = _vertices[i] - _vertices[i - 1]; + result->angleWithEdge = angle(dir, result->edgeDir); + + Vector3d edgeNormal(result->edgeDir.y(), -result->edgeDir.x(), 0); + result->exitPoint = start + (dot(_vertices[i] - start, edgeNormal) / + dot(dir, edgeNormal)) * dir; +} diff --git a/walkplane.h b/walkplane.h index 4cdd58eb13f..737e4c23b26 100644 --- a/walkplane.h +++ b/walkplane.h @@ -46,6 +46,15 @@ public: Vector3d closestPoint(Vector3d point) const; + // Interface to trace a ray to its exit from the polygon + struct ExitInfo { + Vector3d exitPoint; + float angleWithEdge; + Vector3d edgeDir; + }; + void getExitInfo(Vector3d start, Vector3d dir, + struct ExitInfo *result); + private: int _numVertices, _id;