Path 2D Walker.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. namespace Game{
  5. /******************************************************************************/
  6. Path2DWalker& Path2DWalker::clear()
  7. {
  8. points.clear();
  9. return T;
  10. }
  11. /******************************************************************************/
  12. static void SetWalkable(AreaPath2D &path, Int ofs_x, Int ofs_y)
  13. {
  14. REPD(y, path._map.h())
  15. REPD(x, path._map.w())World._path_find.pixelFlag(ofs_x+x, ofs_y+y, path.walkable(x, y) ? PFP_WALKABLE : 0);
  16. }
  17. static void SetNonwalkable(Int ofs_x, Int ofs_y)
  18. {
  19. REP(World.settings().path2DRes())
  20. {
  21. World._path_find.pixelFlag(ofs_x+i, ofs_y , 0);
  22. World._path_find.pixelFlag(ofs_x+i, ofs_y+World.settings().path2DRes()-1, 0);
  23. World._path_find.pixelFlag(ofs_x , ofs_y+i, 0);
  24. World._path_find.pixelFlag(ofs_x+World.settings().path2DRes()-1, ofs_y+i, 0);
  25. }
  26. }
  27. /******************************************************************************/
  28. static Bool PathWalkerFind(Int start_node, Int target_node, C VecI2 &start_xy, C VecI2 &target_xy, Memc<Vec2> &points)
  29. {
  30. PathNode & start_pn=World._path_node[ start_node],
  31. &target_pn=World._path_node[target_node];
  32. if(start_pn.type==PN_AREA && target_pn.type==PN_AREA)
  33. if(Cell<Area> * start_g= World._grid.find( start_pn.area.xy))
  34. if(Cell<Area> *target_g=((start_pn.area.xy==target_pn.area.xy) ? start_g : World._grid.find(target_pn.area.xy)))
  35. {
  36. if(Abs(start_g->x()-target_g->x())>1
  37. || Abs(start_g->y()-target_g->y())>1)return false; // too far away
  38. AreaPath2D & start_path=* start_g->data()->_data->path2D(),
  39. &target_path=*target_g->data()->_data->path2D();
  40. // valid range
  41. World._path_find.border(0, 0, (start_g->x()==target_g->x()) ? World.settings().path2DRes() : World.settings().path2DRes()*2,
  42. (start_g->y()==target_g->y()) ? World.settings().path2DRes() : World.settings().path2DRes()*2);
  43. // start offset
  44. Int start_ofs_x=((start_g->x()>target_g->x()) ? World.settings().path2DRes() : 0),
  45. start_ofs_y=((start_g->y()>target_g->y()) ? World.settings().path2DRes() : 0);
  46. // target offset
  47. Int target_ofs_x=((target_g->x()>start_g->x()) ? World.settings().path2DRes() : 0),
  48. target_ofs_y=((target_g->y()>start_g->y()) ? World.settings().path2DRes() : 0);
  49. // set path map
  50. {
  51. // set path find flag to walkable
  52. SetWalkable( start_path, start_ofs_x, start_ofs_y);
  53. if(start_g!=target_g){SetWalkable(target_path, target_ofs_x, target_ofs_y);
  54. if(start_g->x()!=target_g->x()
  55. && start_g->y()!=target_g->y()) // diagonal
  56. {
  57. Cell<Area> *cell;
  58. AreaPath2D *path;
  59. path=null; if(cell=World._grid.find(target_g->xy()))if(cell->data()->loaded() && cell->data()->_data)path=cell->data()->_data->path2D(); if(path)SetWalkable(*path, target_ofs_x, start_ofs_y);else SetNonwalkable(target_ofs_x, start_ofs_y);
  60. path=null; if(cell=World._grid.find( start_g->xy()))if(cell->data()->loaded() && cell->data()->_data)path=cell->data()->_data->path2D(); if(path)SetWalkable(*path, start_ofs_x, target_ofs_y);else SetNonwalkable( start_ofs_x, target_ofs_y);
  61. }
  62. }
  63. // include path find target flag
  64. if(InRange(target_xy.x, World.settings().path2DRes())
  65. && InRange(target_xy.y, World.settings().path2DRes()))World._path_find.pixel(target_ofs_x+target_xy.x, target_ofs_y+target_xy.y).flag|=PFP_TARGET;else // we have precise target position
  66. {
  67. REPD(y, target_path._map.h())
  68. REPD(x, target_path._map.w())if(target_path._map.pixB(x, y)==target_pn.area.index)World._path_find.pixel(target_ofs_x+x, target_ofs_y+y).flag|=PFP_TARGET; // target is the whole node
  69. }
  70. }
  71. // find path
  72. Memc<VecI2> path;
  73. if(World._path_find.find(&VecI2(start_xy.x+start_ofs_x, start_xy.y+start_ofs_y), null, path, -1, true, true))
  74. {
  75. // convert local VecI2 to world Vec2
  76. Vec2 mul=World.areaSize()/World.settings().path2DRes(),
  77. add=Vec2(start_g->xy())*World.areaSize() + Vec2(0.5f-start_ofs_x, 0.5f-start_ofs_y)*mul;
  78. FREPA(path)points.add(Vec2(path[i])*mul + add);
  79. return true;
  80. }
  81. }
  82. return false;
  83. }
  84. /******************************************************************************/
  85. static inline Bool PathWalkerFind(Int start_node, Int target_node, C VecI2 &start_xy, Memc<Vec2> &points)
  86. {
  87. return PathWalkerFind(start_node, target_node, start_xy, VecI2(-1), points);
  88. }
  89. /******************************************************************************/
  90. static Bool PathWalkerFindStraight(C Vec &start, C Vec &target, Memc<Vec2> &points, Flt allowed_range=World.areaSize())
  91. {
  92. if(Dist2(start.xz(), target.xz())<=Sqr(allowed_range))
  93. {
  94. AreaPath2D *path =null;
  95. VecI2 area_cur =SIGN_BIT,
  96. area_start =World.worldToArea(start);
  97. Vec2 path_start =(start .xz()/World.areaSize()-Vec2(area_start))*World.settings().path2DRes(),
  98. path_target=(target.xz()/World.areaSize()-Vec2(area_start))*World.settings().path2DRes();
  99. for(PixelWalker ew(path_start, path_target); ew.active(); ew.step())
  100. {
  101. VecI2 path_pos =ew.pos(),
  102. area_new =area_start+VecI2(DivFloor(path_pos.x, World.settings().path2DRes()), DivFloor(path_pos.y, World.settings().path2DRes()));
  103. if( area_new!=area_cur)
  104. {
  105. Area::Data *data=World._grid.get(area_cur=area_new).data()->_data; if(!data)return false;
  106. path=data->path2D(); if(!path)return false;
  107. }
  108. if(!path->walkable(Mod(path_pos.x, World.settings().path2DRes()), Mod(path_pos.y, World.settings().path2DRes())))return false;
  109. }
  110. points.add(target.xz());
  111. return true;
  112. }
  113. return false;
  114. }
  115. /******************************************************************************/
  116. Bool Path2DWalker::find(C Vec &start, C Vec &target, C Vec *alternate_start)
  117. {
  118. clear();
  119. T.target=target;
  120. if(Dist2(start.xz(), target.xz())<=Sqr(0.1f))return true; // we're already at the target
  121. Int start_node, target_node;
  122. VecI2 start_xy , target_xy ;
  123. start_node=World.pathGetNode( start, start_xy);
  124. if(start_node<0 && alternate_start)start_node=World.pathGetNode(*alternate_start, start_xy); // if current start position is invalid try using last known position (if given)
  125. if(start_node>=0)
  126. {
  127. target_node =World.pathGetNode(target, target_xy);
  128. if(target_node>=0)
  129. {
  130. if(PathWalkerFindStraight(start, target, points))return true; // try first going straight
  131. if(start_node==target_node && start_xy==target_xy)return true; // we're already at the target
  132. Memc<UInt> node;
  133. if(World.pathFind(start_node, target_node, node)) // find in nodes
  134. {
  135. if((node.elms()<=1) // start and target are located in the same or adjacent nodes
  136. ? PathWalkerFind(start_node, target_node, start_xy, target_xy, points)
  137. : PathWalkerFind(start_node, node.last(), start_xy, points))
  138. {
  139. return true;
  140. }
  141. }
  142. }
  143. }
  144. return false;
  145. }
  146. /******************************************************************************/
  147. }}
  148. /******************************************************************************/