Pathfind.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. /******************************************************************************
  2. Use 'PathMesh' to specify a path mesh for a single area.
  3. Use 'PathWorld' for pathfinding on many 'PathMesh'es.
  4. Use 'PathObstacle' for temporary obstacles in 'PathWorld's.
  5. /******************************************************************************/
  6. enum PATH_MESH_TYPE
  7. {
  8. PM_OBSTACLE, // can not be crossed
  9. PM_GROUND , // can be crossed if traveller supports PMF_WALK
  10. PM_WATER , // can be crossed if traveller supports PMF_SWIM
  11. #if EE_PRIVATE
  12. PM_BLOCKED=63, // covered by obstacles
  13. #endif
  14. };
  15. enum PATH_MESH_FLAG
  16. {
  17. PMF_WALK=0x0001,
  18. PMF_SWIM=0x0002,
  19. };
  20. /******************************************************************************/
  21. struct PathSettings
  22. {
  23. Flt areaSize ()C {return _area_size;} PathSettings& areaSize (Flt size ); // get/set area size (in meters ), 0..Inf , default=32
  24. Flt ctrlRadius()C {return _ctrl_r ;} PathSettings& ctrlRadius(Flt r ); // get/set controller radius (in meters ), 0..Inf , default=0.33f
  25. Flt ctrlHeight()C {return _ctrl_h ;} PathSettings& ctrlHeight(Flt h ); // get/set controller height (in meters ), 0..Inf , default=2.0f
  26. Flt maxClimb ()C {return _max_climb;} PathSettings& maxClimb (Flt climb); // get/set max climb height (in meters ), 0..Inf , default=0.7f
  27. Flt maxSlope ()C {return _max_slope;} PathSettings& maxSlope (Flt slope); // get/set max slope angle (in radians), 0..PI_2, default=PI_4
  28. Flt cellSize ()C {return _cell_size;} PathSettings& cellSize (Flt size ); // get/set path cell size (in meters ), 0..Inf , default=1.0f/3
  29. Flt cellHeight()C {return _cell_h ;} PathSettings& cellHeight(Flt h ); // get/set path cell height (in meters ), 0..Inf , default=0.1f
  30. // operations
  31. PathSettings& reset(); // reset to default settings
  32. Bool operator==(C PathSettings &path)C; // if settings are equal
  33. Bool operator!=(C PathSettings &path)C; // if settings are different
  34. // io
  35. Bool save(File &f)C; // save to file, false on fail
  36. Bool load(File &f) ; // load from file, false on fail
  37. PathSettings() {reset();}
  38. private:
  39. Flt _area_size, _ctrl_r, _ctrl_h, _max_climb, _max_slope, _cell_size, _cell_h;
  40. };
  41. /******************************************************************************/
  42. struct PathObstacle
  43. {
  44. // manage
  45. void del (); // delete manually , deleting an obstacle requires rebuilding path meshes (avoid calling this frequently as it may decrease performance)
  46. Bool create(C Shape &shape, C PathWorld &world); // create path obstacle from 'shape' in 'world', creating an obstacle requires rebuilding path meshes (avoid calling this frequently as it may decrease performance)
  47. // get / set
  48. Shape shape( ); // get obstacle shape, SHAPE_NONE on fail (if doesn't exist)
  49. void shape(C Shape &shape); // set obstacle shape, adjusting the shape of the obstacle requires rebuilding path meshes (avoid calling this frequently as it may decrease performance), only following shape types are supported: SHAPE_POINT, SHAPE_EDGE, SHAPE_BOX, SHAPE_BALL, SHAPE_CAPSULE, SHAPE_TUBE, SHAPE_OBOX, SHAPE_PYRAMID, attempting to set a different type of shape is equivalent to calling 'del' method
  50. ~PathObstacle() {del();}
  51. PathObstacle() {_world=null; _shape=null;}
  52. private:
  53. PathWorld *_world;
  54. Shape *_shape;
  55. NO_COPY_CONSTRUCTOR(PathObstacle);
  56. };
  57. /******************************************************************************/
  58. #if EE_PRIVATE
  59. struct RecastCompactHeightfield : rcCompactHeightfield
  60. {
  61. void del();
  62. Bool is()C;
  63. void clean();
  64. Bool save(File &f)C;
  65. Bool load(File &f) ;
  66. void operator=(C RecastCompactHeightfield &src);
  67. void zero() {Zero(T);}
  68. ~RecastCompactHeightfield() {del ();}
  69. RecastCompactHeightfield() {zero();}
  70. RecastCompactHeightfield(C RecastCompactHeightfield &src) {zero(); T=src;}
  71. };
  72. const_mem_addr struct _PathMesh
  73. {
  74. VecI2 xy;
  75. PathWorld *world;
  76. Mems<Byte> data, obstacle_data, chf_compressed;
  77. RecastCompactHeightfield chf;
  78. // manage
  79. void del();
  80. // operations
  81. void link(PathWorld *world);
  82. void preSave(); // compress data needed for saving
  83. // get
  84. Bool is ()C; // if has any mesh data
  85. Box box () ; // get mesh world box
  86. Bool getChf() ; // get chf (decompress if needed), false on fail
  87. // io
  88. Bool save(File &f)C; // save to file, false on fail
  89. Bool load(File &f) ; // load from file, false on fail
  90. ~_PathMesh() {del();}
  91. _PathMesh() {xy.zero(); world=null;}
  92. NO_COPY_CONSTRUCTOR(_PathMesh);
  93. };
  94. #endif
  95. /******************************************************************************/
  96. struct PathMesh
  97. {
  98. // manage
  99. void del (); // delete manually
  100. Bool create(MeshBase &mesh, C VecI2 &area_xy, C PathSettings &settings); // build path mesh from source 'mesh', at 'area_xy' area coordinates using 'settings' path build settings, false on fail ("mesh.tri.flag" and "mesh.quad.flag" can be manually set to PATH_MESH_TYPE to specify the type of the face)
  101. // get
  102. Bool is()C; // if has any mesh data
  103. // operation
  104. void preSave(); // saving 'PathMesh' typically requires compressing some data, which may take some time, you can call this method at an earlier stage to compress and prepare the data so saving later will be without any delays, this method is optional and does not need to be called
  105. // io
  106. Bool save(File &f)C; // save to file, false on fail
  107. Bool load(File &f) ; // load from file, false on fail
  108. ~PathMesh();
  109. PathMesh();
  110. private:
  111. #if EE_PRIVATE
  112. friend struct PathWorld;
  113. _PathMesh *_pm;
  114. #else
  115. Ptr _pm;
  116. #endif
  117. NO_COPY_CONSTRUCTOR(PathMesh);
  118. };
  119. /******************************************************************************/
  120. const_mem_addr struct PathWorld // !! must be stored in constant memory address !!
  121. {
  122. // manage
  123. void del ( ); // delete manually
  124. Bool create(Flt area_size); // initialize path world manager, 'area_size'=size of a single area (in meters), false on fail
  125. // operations
  126. Bool set(PathMesh *path_mesh, C VecI2 &area_xy); // set 'path_mesh' at specified 'area_xy' area coordinates (can be null for no path mesh at that location)
  127. #if EE_PRIVATE
  128. Bool _set (_PathMesh *path_mesh, C VecI2 &area_xy, Bool set_obstacles); // set 'path_mesh' at specified 'area_xy' area coordinates (can be null for no path mesh at that location), 'set_obstacles'=if set obstacles on that mesh before setting it
  129. void update ( ); // update changes in obstacles by rebuilding affected path meshes
  130. void changed (C Shape &shape ); // call when 'shape' obstacle was changed in the world
  131. void threadFunc();
  132. void zero ();
  133. VecI2 worldToArea(C Vec2 &xz )C {return Floor(xz/areaSize());} // convert World Position to Area Coordinates
  134. VecI2 worldToArea(C Vec &pos )C {return worldToArea(pos .xz());} // convert World Position to Area Coordinates
  135. RectI worldToArea(C Rect &rect )C {return RectI(worldToArea(rect.min), worldToArea(rect.max));} // convert World Position to Area Coordinates
  136. RectI worldToArea(C Box &box )C {return RectI(worldToArea(box .min), worldToArea(box .max));} // convert World Position to Area Coordinates
  137. Box obstacleBox(C Shape &shape )C;
  138. _PathMesh* pathMesh (C VecI2 &area_xy)C; // get PathMesh at 'area_xy' area coordinates
  139. #endif
  140. // get
  141. Flt areaSize()C {return _area_size;} // get area size
  142. Bool find(C Vec &start, C Vec &end, MemPtr<Vec> path, Int max_steps=-1, UInt walkable_flags=PMF_WALK, Bool allow_partial_paths=true, C Vec &end_extents=Vec(1, 16, 1))C; // find path from 'start' to 'end' world position, 'max_steps'=maximum number of allowed steps in the result path (use <=0 for unlimited), 'walkable_flags'=faces that are walkable (PATH_MESH_FLAG), 'allow_partial_paths'=if there is no direct path from 'start' to 'end' then return partial path to the point closest to the 'end', false on fail (path not found), 'end_extents'=extents used to find nearest walkable surface to the 'end' point
  143. Bool nearestSurface(C Vec &pos, C Vec &extents, Vec &surface_pos, UInt walkable_flags=PMF_WALK)C; // find nearest point on path surface, 'pos'=center position of the search, 'extents'=maximum distance to search in each dimension, 'surface_pos'=output position, 'walkable_flags'=faces that are walkable (PATH_MESH_FLAG), false on fail (point not found)
  144. Bool nearestWall(C Vec &pos, Flt max_distance, Flt *hit_distance=null, Vec *hit_pos=null, Vec *hit_normal=null, UInt walkable_flags=PMF_WALK)C; // calculate distance to nearest wall from 'pos' position, 'max_distance'=maximum distance to perform the search, 'hit_distance'=distance to wall, 'hit_pos'=hit position, 'hit_normal'=hit normal, 'walkable_flags'=faces that are walkable (PATH_MESH_FLAG), false on fail (wall not found)
  145. Bool ray(C Vec &start, C Vec &end, Flt *hit_frac=null, Vec *hit_pos=null, Vec *hit_normal=null, UInt walkable_flags=PMF_WALK)C; // perform a ray test on the path surface starting from 'start' towards 'end', 'hit_frac'=fraction of the movement (0..1), 'hit_pos'=hit position, 'hit_normal'=hit normal, 'walkable_flags'=faces that are walkable (PATH_MESH_FLAG), false on fail (no hit occurred)
  146. // draw
  147. void draw(Byte surface_color_alpha=64, Flt y_offset=0, C Color &outer_edge_color=Color(0,48,64,220), C Color &inner_edge_color=Color(0,48,64,32))C; // 'y_offset'=vertical offset applied when drawing paths (can be set to positive value to draw the paths above the ground, so they will not be occluded by ground meshes)
  148. ~PathWorld() {del();}
  149. PathWorld();
  150. #if !EE_PRIVATE
  151. private:
  152. #endif
  153. Flt _area_size, _ctrl_r, _ctrl_h, _max_climb;
  154. #if EE_PRIVATE
  155. struct Build
  156. {
  157. RecastCompactHeightfield chf;
  158. Mems<Shape> shapes;
  159. VecI2 xy;
  160. Ptr user;
  161. };
  162. struct Built
  163. {
  164. Mems<Byte> data;
  165. VecI2 xy;
  166. Ptr user;
  167. };
  168. dtNavMesh *_mesh;
  169. dtNavMeshQuery *_query;
  170. dtQueryFilter *_filter;
  171. Memc<_PathMesh*> _changed;
  172. Memc<Build> _build;
  173. Memc<Built> _built;
  174. #else
  175. Ptr _mesh, _query, _filter;
  176. _Memc _changed, _build, _built;
  177. #endif
  178. Memx<Shape> _obstacles;
  179. Thread _thread;
  180. SyncEvent _event;
  181. SyncLock _lock;
  182. NO_COPY_CONSTRUCTOR(PathWorld);
  183. };
  184. /******************************************************************************/