00001 #include "BasicPre.hpp" 00002 #include "NavMeshArea.hpp" 00003 #include "NavMesh.hpp" 00004 #include "sim/pos/PosComponent.hpp" 00005 #include "sim/react/CollisionAreaComponent.hpp" 00006 00007 using namespace se_core; 00008 00009 namespace se_basic { 00010 NavMeshArea 00011 ::NavMeshArea(Composite* owner, const ComponentFactory* factory, coor_tile_t w, coor_tile_t h, const NavMesh* navMesh) 00012 : Area (owner, factory, w, h), navMesh_(navMesh) { 00013 //LogDetail(owner->name() << " area created with size " << w << ", " << h); 00014 navMesh_->walls(CollisionAreaComponent::Ptr(*this)->areaEdge()); 00015 } 00016 00017 00018 NavMeshArea 00019 ::~NavMeshArea() { 00020 //LogDetail(owner()->name() << " area destroyed."); 00021 } 00022 00023 00024 bool NavMeshArea 00025 ::isNeighbour(const Area& area) const { 00026 if(!Area::isNeighbour(area)) 00027 return false; 00028 00029 PosComponent::Ptr aPos(area); 00030 Point3 p(aPos->pos().worldCoor()); 00031 p.sub(posComponent_->pos().worldCoor()); 00032 BoundingBox toArea(p, aPos->pos().bounds_); 00033 00034 Point3 tmp; 00035 short index = navMesh_->findExit(toArea, tmp); 00036 00037 return (index >= 0); 00038 } 00039 00040 00041 coor_t NavMeshArea 00042 ::groundHeight(const Point3& coor, short index) const { 00043 static Tuple3 b; 00044 Point2 p(coor.x_, coor.z_); 00045 short tri = (index >= 0) ? index : navMesh_->find(p); 00046 AssertFatal(tri >= 0, "Make sure coor is legal before calling groundHeight"); 00047 if(tri < 0) 00048 return 0; 00049 navMesh_->barycentric(tri, p, b); 00050 return navMesh_->height(tri, b); 00051 } 00052 00053 00054 short NavMeshArea 00055 ::index(const se_core::Point3& worldCoor, short oldIndex) const { 00056 //Assert(nextPosition_.face().isIdentity() 00057 // && "Rotation of area not supported"); 00058 00059 Point2 p(worldCoor.x_ - posComponent_->nextPos().world_.coor_.x_ 00060 , worldCoor.z_ - posComponent_->nextPos().world_.coor_.z_); 00061 00062 //LogDetail(p.x_ << ", " << p.y_); 00063 00064 short index; 00065 if(oldIndex >= 0) { 00066 index = navMesh_->find(oldIndex, p); 00067 } 00068 else { 00069 index = navMesh_->find(p); 00070 } 00071 00072 //LogDetail(index); 00073 return index; 00074 } 00075 00076 00077 bool NavMeshArea 00078 ::doesTouchVoid(const Point3& wc, short index, coor_t radius) const { 00079 if(index < 0) 00080 return true; 00081 Point3 p(wc); 00082 p.sub(posComponent_->nextPos().worldCoor()); 00083 return navMesh_->doesTouchVoid(p, index, radius); 00084 } 00085 00086 void NavMeshArea 00087 ::force(const Point3& coor, Vector3& dest) const { 00088 // No up or down in NavMeshArea (yet) 00089 dest.set(0, 0, 0); 00090 } 00091 00092 00093 short NavMeshArea 00094 ::terrainStyle(const Point3& coor, short index) const { 00095 Point2 p(coor.x_, coor.z_); 00096 short tri = (index >= 0) ? index : navMesh_->find(p); 00097 //short tri = navMesh_->find(p); 00098 //LogDetail(tri << ": " << coor.x_ << ", " << coor.z_); 00099 00100 if(tri < 0) { 00101 return TS_VOID; 00102 } 00103 00104 return TS_WALKABLE; 00105 } 00106 00107 00108 short NavMeshArea 00109 ::nextTerrainStyle(bray_t direction, const Point3& coor) { 00110 // May be deprecated soon?? 00111 LogFatal("Not implemented"); 00112 return 0; 00113 } 00114 00115 00116 bool NavMeshArea 00117 ::isLineOfSight(const Pos& from, const Pos& to) { 00118 const NavMeshArea::Ptr toArea(const_cast<PosComponent*>(to.area())); 00119 00120 Point3 fromPoint, toPoint; 00121 short fromIndex, toIndex = -1; 00122 00123 fromPoint.sub(from.worldCoor(), posComponent_->nextPos().worldCoor()); 00124 fromIndex = from.index(); 00125 toPoint.sub(to.worldCoor(), posComponent_->nextPos().worldCoor()); 00126 if(toArea == this) { 00127 toIndex = to.index(); 00128 } 00129 int linkType = navMesh_->isInLineOfSight(fromPoint, fromIndex, toPoint, toIndex); 00130 00131 // Found correct triangle? 00132 if(linkType == 0) 00133 return true; 00134 00135 // Found wall? 00136 if(linkType == -1) 00137 return false; 00138 00139 // Found link to neighbour area? 00140 if(linkType == 1) { 00141 Assert(this != toArea); 00142 if(!Area::isNeighbour(*toArea)) 00143 return false; 00144 00145 Point3 offset, tmp; 00146 PosComponent::Ptr fromAreaPos(*posComponent_); 00147 PosComponent::Ptr toAreaPos(*toArea->posComponent_); 00148 offset.sub(toAreaPos->pos().worldCoor(), fromAreaPos->pos().worldCoor()); 00149 BoundingBox toAreaBounds(offset, toAreaPos->pos().bounds_); 00150 00151 fromPoint.sub(offset); 00152 fromIndex = toArea->navMesh_->findExit(toAreaBounds, tmp); 00153 toPoint.sub(offset); 00154 toIndex = to.index(); 00155 00156 linkType = toArea->navMesh_->isInLineOfSight(fromPoint, fromIndex, toPoint, toIndex); 00157 00158 // Found correct triangle? 00159 return (linkType == 0); 00160 } 00161 return false; 00162 } 00163 00164 00165 00166 coor_t NavMeshArea 00167 ::farthestLineOfSight(const Point3& from, short fromIndex, bray_t yaw, coor_t maxLen, coor_t maxOffNavMesh) const { 00168 Point2 p; 00169 short toIndex; 00170 Point3 toPoint; 00171 Point3 fromPoint(from); 00172 00173 toPoint.setForward(maxLen, yaw); 00174 toPoint.y_ = 0; 00175 toPoint.add(fromPoint); 00176 toIndex = index(toPoint, -1); 00177 00178 // Send world coor to CAC 00179 coor_t obstructionLen = CollisionAreaComponent::Ptr(*this)->farthestLineOfSight(fromPoint, toPoint); 00180 00181 00182 const NavMeshArea* toArea = static_cast<const NavMeshArea*>(neighbour(toPoint)); 00183 toPoint.sub(posComponent_->nextPos().worldCoor()); 00184 fromPoint.sub(posComponent_->nextPos().worldCoor()); 00185 00186 int linkType = navMesh_->farthestLineOfSightXZ(fromIndex, fromPoint, toPoint, toIndex, p); 00187 if(linkType == 1 && toArea && toArea != this) { 00188 00189 Point3 offset, tmp; 00190 PosComponent::Ptr fromAreaPos(*posComponent_); 00191 PosComponent::Ptr toAreaPos(*toArea->posComponent_); 00192 offset.sub(fromAreaPos->pos().worldCoor(), toAreaPos->pos().worldCoor()); 00193 BoundingBox toAreaBounds(offset, toAreaPos->pos().bounds_); 00194 00195 fromIndex = toArea->navMesh_->findExit(toAreaBounds, tmp); 00196 fromPoint.x_ = p.x_; 00197 fromPoint.z_ = p.y_; 00198 fromPoint.add(offset); 00199 00200 toPoint.add(posComponent_->nextPos().worldCoor()); 00201 toIndex = toArea->index(toPoint, -1); 00202 toPoint.sub(toAreaPos->nextPos().worldCoor()); 00203 00204 linkType = toArea->navMesh_->farthestLineOfSightXZ(fromIndex, fromPoint, toPoint, toIndex, p); 00205 toPoint.x_ = p.x_ + toAreaPos->nextPos().worldCoor().x_; 00206 toPoint.z_ = p.y_ + toAreaPos->nextPos().worldCoor().z_; 00207 } 00208 else { 00209 toPoint.x_ = p.x_ + posComponent_->nextPos().worldCoor().x_; 00210 toPoint.z_ = p.y_ + posComponent_->nextPos().worldCoor().z_; 00211 } 00212 00213 Vector3 dist; 00214 dist.sub(from, toPoint); 00215 dist.y_ = 0; 00216 coor_t len = dist.length(); 00217 len += maxOffNavMesh; 00218 00219 if(len > obstructionLen) 00220 len = obstructionLen; 00221 00222 if(len > maxLen) 00223 len = maxLen; 00224 00225 return len; 00226 } 00227 00228 00229 coor_t NavMeshArea 00230 ::farthestLineOfSight(const Pos& from, bray_t yaw, coor_t maxLen, coor_t maxOffNavMesh, Point3& dest) const { 00231 coor_t len = farthestLineOfSight(from.worldCoor(), from.index(), yaw, maxLen, maxOffNavMesh); 00232 Point3 toPoint; 00233 toPoint.setForward(len, yaw); 00234 toPoint.add(from.worldCoor()); 00235 if(toPoint.xzDistanceSquared(from.worldCoor()) < dest.xzDistanceSquared(from.worldCoor())) { 00236 dest.x_ = toPoint.x_; 00237 dest.z_ = toPoint.z_; 00238 } 00239 00240 return len; 00241 } 00242 00243 00244 void NavMeshArea 00245 ::farthestLineOfSight(const Pos& from, const Pos& to, Point3& dest) const { 00246 Point3 toPoint(to.worldCoor()); 00247 short toIndex = index(toPoint, from.index()); 00248 toPoint.sub(posComponent_->nextPos().worldCoor()); 00249 00250 short fromIndex = from.index(); 00251 Point3 fromPoint; 00252 fromPoint.sub(from.worldCoor(), posComponent_->nextPos().worldCoor()); 00253 00254 Point2 p; 00255 navMesh_->farthestLineOfSightXZ(fromIndex, fromPoint, toPoint, toIndex, p); 00256 dest.x_ = p.x_ + posComponent_->nextPos().worldCoor().x_; 00257 dest.z_ = p.y_ + posComponent_->nextPos().worldCoor().z_; 00258 } 00259 00260 00261 short NavMeshArea 00262 ::farthestLos(const Point3& from, short fromIndex, short toIndex) const { 00263 Point3 c; 00264 if(fromIndex == toIndex) { 00265 return toIndex; 00266 } 00267 00268 short via = navMesh_->path(fromIndex, toIndex); 00269 navMesh_->center(via, c); 00270 if(navMesh_->isInLineOfSight(from, fromIndex, c, via) < 0) { 00271 LogDetail("Gave path that was not in LOS"); 00272 return fromIndex; 00273 } 00274 if(via == toIndex) 00275 return via; 00276 00277 short next = navMesh_->path(via, toIndex); 00278 navMesh_->center(next, c); 00279 while(navMesh_->isInLineOfSight(from, fromIndex, c, next) == 0) { 00280 via = next; 00281 if(via == toIndex) 00282 break; 00283 00284 next = navMesh_->path(via, toIndex); 00285 navMesh_->center(next, c); 00286 } 00287 return via; 00288 } 00289 00290 00291 void NavMeshArea 00292 ::path(const Pos& from, const Pos& to, Point3& out) const { 00293 // In different areas - search for triangles in this navmesh that 00294 // is inside the other 00295 if(from.area() != to.area()) { 00296 if(!from.hasArea() || !to.hasArea()) { 00297 out.set(from.localCoor()); 00298 return; 00299 } 00300 Point3 p(to.area()->pos().worldCoor()); 00301 p.sub(from.area()->pos().worldCoor()); 00302 BoundingBox toArea(p, to.area()->pos().bounds_); 00303 short toIndex = navMesh_->findExit(toArea, out); 00304 //LogDetail(name() << p << toArea << " - " << out); 00305 00306 if(toIndex < 0) { 00307 out.set(to.localCoor()); 00308 return; 00309 } 00310 00311 // Already in same triangle 00312 if(from.index() == toIndex) { 00313 // At exit - walk to center of next area 00314 toArea.center(out); 00315 return; 00316 } 00317 if(navMesh_->isInLineOfSight(from.localCoor(), from.index(), out, toIndex) == 0) { 00318 // Out is already set 00319 return; 00320 } 00321 //short via = navMesh_->path(from.index(), toIndex); 00322 short via = farthestLos(from.localCoor(), from.index(), toIndex); 00323 navMesh_->center(via, out); 00324 00325 return; 00326 } 00327 // Already in same triangle 00328 if(from.index() == to.index()) { 00329 out.set(to.localCoor()); 00330 return; 00331 } 00332 if(to.index() < 0) { 00333 out.set(to.localCoor()); 00334 return; 00335 } 00336 // In line of sight 00337 if(navMesh_->isInLineOfSight(from, to) == 0) { 00338 out.set(to.localCoor()); 00339 return; 00340 } 00341 short via = farthestLos(from.localCoor(), from.index(), to.index()); 00342 //short via = navMesh_->path(from.index(), to.index()); 00343 //LogDetail("D:" << from.index() << ", " << to.index() << ": " << via); 00344 navMesh_->center(via, out); 00345 } 00346 00347 00348 bray_t NavMeshArea 00349 ::slideAngle(const se_core::Pos& from, const se_core::Point3& to) const { 00350 Point3 fromAc, toAc, np(posComponent_->nextPos().worldCoor()); 00351 fromAc.sub(from.worldCoor(), np); 00352 toAc.sub(to, np); 00353 bray_t angle = navMesh_->slideAngle(fromAc, from.index(), toAc); 00354 return angle; 00355 } 00356 00357 00358 bray_t NavMeshArea 00359 ::wallAngle(const se_core::Pos& from, const se_core::Point3& to) const { 00360 Point3 fromAc, toAc; 00361 fromAc.sub(from.worldCoor(), posComponent_->nextPos().worldCoor()); 00362 toAc.sub(to, posComponent_->nextPos().worldCoor()); 00363 bray_t angle = navMesh_->wallAngle(fromAc, from.index(), toAc); 00364 return angle; 00365 } 00366 00367 00368 coor_double_t NavMeshArea 00369 ::findNearest(const se_core::Point3& wc, se_core::Point3& out) const { 00370 Point3 p(wc); 00371 p.sub(posComponent_->nextPos().worldCoor()); 00372 return navMesh_->findNearest(p, out); 00373 } 00374 00375 }
Home Page | SagaEngine trunk (updated nightly) reference generated Sun Dec 2 20:06:02 2007 by Doxygen version 1.3.9.1.