pathfinder.cpp
来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 648 行 · 第 1/2 页
CPP
648 行
if(down){
if(right)
TestSquare(moveData, pfDef, os, (PATHOPT_RIGHT | PATHOPT_DOWN));
if(left)
TestSquare(moveData, pfDef, os, (PATHOPT_LEFT | PATHOPT_DOWN));
}
//Mark this square as closed.
squareState[os->sqr].status |= PATHOPT_CLOSED;
}
//Returning search-result.
if(foundGoal)
return Ok;
//Could not reach the goal.
if(openSquareBufferPointer - openSquareBuffer >= (maxNodesToBeSearched - 8))
return GoalOutOfRange;
//Search could not reach the goal, due to the unit being locked in.
if(openSquares.empty())
return GoalOutOfRange;
//Below shall never be runned.
logOutput << "ERROR: CPathFinder::DoSearch() - Unhandled end of search!\n";
return Error;
}
/**
Test the availability and value of a square,
and possibly add it to the queue of open squares.
*/
bool CPathFinder::TestSquare(const MoveData& moveData, const CPathFinderDef& pfDef, OpenSquare* parentOpenSquare, unsigned int enterDirection) {
testedNodes++;
//Calculate the new square.
int2 square;
square.x = parentOpenSquare->square.x + directionVector[enterDirection].x;
square.y = parentOpenSquare->square.y + directionVector[enterDirection].y;
//Inside map?
if(square.x < 0 || square.y < 0 || square.x >= gs->mapx || square.y >= gs->mapy)
return false;
int sqr = square.x + square.y * gs->mapx;
//Check if the square is unaccessable or used.
if(squareState[sqr].status & (PATHOPT_CLOSED | PATHOPT_FORBIDDEN | PATHOPT_BLOCKED)){
if(squareState[sqr].status & PATHOPT_BLOCKED)
return false;
else
return false;
}
int blockStatus=moveData.moveMath->IsBlocked2(moveData, square.x, square.y);
//Check if square are out of constraints or blocked by something.
//Don't need to be done on open squares, as whose are already tested.
if(!(squareState[sqr].status & PATHOPT_OPEN) && (!pfDef.WithinConstraints(square.x, square.y) || (blockStatus & (CMoveMath::BLOCK_STRUCTURE | CMoveMath::BLOCK_TERRAIN)))){
squareState[sqr].status |= PATHOPT_BLOCKED;
dirtySquares.push_back(sqr);
return false;
}
//Evaluate this node.
float squareSpeedMod = moveData.moveMath->SpeedMod(moveData, square.x, square.y);
if(squareSpeedMod==0){
squareState[sqr].status |= PATHOPT_FORBIDDEN;
dirtySquares.push_back(sqr);
return false;
}
if(testMobile && (blockStatus & (CMoveMath::BLOCK_MOBILE | CMoveMath::BLOCK_MOVING | CMoveMath::BLOCK_MOBILE_BUSY))){
if(blockStatus & CMoveMath::BLOCK_MOVING)
squareSpeedMod*=0.65f;
else if(blockStatus & CMoveMath::BLOCK_MOBILE)
squareSpeedMod*=0.35f;
else
squareSpeedMod*=0.10f;
}
float squareCost = moveCost[enterDirection] / squareSpeedMod;
float heuristicCost = pfDef.Heuristic(square.x, square.y);
//Summarize cost.
float currentCost = parentOpenSquare->currentCost + squareCost;
float cost = currentCost + heuristicCost;
//Checks if this square are in que already.
//If the old one is better then keep it, else change it.
if(squareState[sqr].status & PATHOPT_OPEN) {
if(squareState[sqr].cost <= cost)
return true;
squareState[sqr].status &= ~PATHOPT_DIRECTION;
}
//Looking for improvements.
if(!exactPath && heuristicCost < goalHeuristic) {
goalSquare = sqr;
goalHeuristic = heuristicCost;
}
//Store this square as open.
OpenSquare *os = ++openSquareBufferPointer; //Take the next OpenSquare in buffer.
os->square = square;
os->sqr = sqr;
os->currentCost = currentCost;
os->cost = cost;
openSquares.push(os);
//Set this one as open and the direction from which it was reached.
squareState[sqr].cost = os->cost;
squareState[sqr].status |= (PATHOPT_OPEN | enterDirection);
dirtySquares.push_back(sqr);
return true;
}
/**
Recreates the path found by pathfinder.
Starting at goalSquare and tracking backwards.
*/
void CPathFinder::FinishSearch(const MoveData& moveData, Path& foundPath) {
//Backtracking the path.
if(needPath)
{
int2 square;
square.x = goalSquare % gs->mapx;
square.y = goalSquare / gs->mapx;
do {
int sqr = square.x + square.y * gs->mapx;
if(squareState[sqr].status & PATHOPT_START)
break;
float3 cs;
cs.x = (square.x/2/* + 0.5f*/) * SQUARE_SIZE*2+SQUARE_SIZE;
cs.z = (square.y/2/* + 0.5f*/) * SQUARE_SIZE*2+SQUARE_SIZE;
cs.y = moveData.moveMath->yLevel(square.x, square.y);
foundPath.path.push_back(cs);
int2 oldSquare;
oldSquare.x = square.x;
oldSquare.y = square.y;
square.x -= directionVector[squareState[sqr].status & PATHOPT_DIRECTION].x;
square.y -= directionVector[squareState[sqr].status & PATHOPT_DIRECTION].y;
}
while(true);
if (foundPath.path.size() > 0)
{
foundPath.pathGoal = foundPath.path.front();
}
}
//Adds the cost of the path.
foundPath.pathCost = squareState[goalSquare].cost;
}
/**
Clear things up from last search.
*/
void CPathFinder::ResetSearch() {
openSquares.DeleteAll();
// while(!openSquares.empty())
// openSquares.pop();
while(!dirtySquares.empty()){
int lsquare = dirtySquares.back();
squareState[lsquare].status = 0;
squareState[lsquare].cost = PATHCOST_INFINITY;
dirtySquares.pop_back();
}
testedNodes = 0;
}
////////////////////
// CPathFinderDef //
////////////////////
/**
Constructor.
*/
CPathFinderDef::CPathFinderDef(float3 goalCenter, float goalRadius) :
goal(goalCenter),
sqGoalRadius(goalRadius)
{
//Makes sure that the goal could be reached with 2-square resolution.
if(sqGoalRadius < SQUARE_SIZE*SQUARE_SIZE*2)
sqGoalRadius = SQUARE_SIZE*SQUARE_SIZE*2;
goalSquareX=(int)(goalCenter.x/SQUARE_SIZE);
goalSquareZ=(int)(goalCenter.z/SQUARE_SIZE);
}
/**
Tells whenever the goal is in range.
*/
bool CPathFinderDef::IsGoal(int xSquare, int zSquare) const {
return ((SquareToFloat3(xSquare, zSquare)-goal).SqLength2D() <= sqGoalRadius);
}
/**
Distance to goal center in mapsquares.
*/
float CPathFinderDef::Heuristic(int xSquare, int zSquare) const
{
int min=abs(xSquare-goalSquareX);
int max=abs(zSquare-goalSquareZ);
if(min>max){
int temp=min;
min=max;
max=temp;
}
return max*0.5f+min*0.2f;
}
/**
Tells if the goal are is unaccessable.
If the goal area is small and blocked then it's considered blocked, else not.
*/
bool CPathFinderDef::GoalIsBlocked(const MoveData& moveData, unsigned int moveMathOptions) const {
if((sqGoalRadius < SQUARE_SIZE*SQUARE_SIZE*4 || sqGoalRadius <= (moveData.size/2)*(moveData.size/2)*1.5f*SQUARE_SIZE*SQUARE_SIZE)
&& (moveData.moveMath->IsBlocked(moveData, goal) & moveMathOptions))
return true;
else
return false;
}
int2 CPathFinderDef::GoalSquareOffset(int blockSize) const {
int blockPixelSize = blockSize * SQUARE_SIZE;
int2 offset;
offset.x = ((int)goal.x % blockPixelSize) / SQUARE_SIZE;
offset.y = ((int)goal.z % blockPixelSize) / SQUARE_SIZE;
return offset;
}
/**
Draw a circle around the goal, indicating the goal area.
*/
void CPathFinderDef::Draw() const {
glColor4f(0, 1, 1, 1);
glSurfaceCircle(goal, sqrt(sqGoalRadius), 20);
}
void CPathFinder::Draw(void)
{
glColor3f(0.7f,0.2f,0.2f);
glDisable(GL_TEXTURE_2D);
glBegin(GL_LINES);
for(OpenSquare* os=openSquareBuffer;os!=openSquareBufferPointer;++os){
int2 sqr=os->square;
int square = os->sqr;
if(squareState[square].status & PATHOPT_START)
continue;
float3 p1;
p1.x=sqr.x*SQUARE_SIZE;
p1.z=sqr.y*SQUARE_SIZE;
p1.y=ground->GetHeight(p1.x,p1.z)+15;
float3 p2;
int obx=sqr.x-directionVector[squareState[square].status & PATHOPT_DIRECTION].x;
int obz=sqr.y-directionVector[squareState[square].status & PATHOPT_DIRECTION].y;
int obsquare = obz * gs->mapx + obx;
if(obsquare>=0){
p2.x=obx*SQUARE_SIZE;
p2.z=obz*SQUARE_SIZE;
p2.y=ground->GetHeight(p2.x,p2.z)+15;
glVertexf3(p1);
glVertexf3(p2);
}
}
glEnd();
}
//////////////////////////////////////////
// CRangedGoalWithCircularConstraintPFD //
//////////////////////////////////////////
/**
Constructor
Calculating the center and radius of the constrainted area.
*/
CRangedGoalWithCircularConstraint::CRangedGoalWithCircularConstraint(float3 start, float3 goal, float goalRadius,float searchSize,int extraSize) :
CPathFinderDef(goal, goalRadius)
{
int startX=(int)(start.x/SQUARE_SIZE);
int startZ=(int)(start.z/SQUARE_SIZE);
float3 halfWay = (start + goal) / 2;
halfWayX = (int)(halfWay.x/SQUARE_SIZE);
halfWayZ = (int)(halfWay.z/SQUARE_SIZE);
int dx=startX-halfWayX;
int dz=startZ-halfWayZ;
searchRadiusSq=dx*dx+dz*dz;
searchRadiusSq*=(int)(searchSize*searchSize);
searchRadiusSq+=extraSize;
}
/**
Tests if a square is inside is the circular constrainted area.
*/
bool CRangedGoalWithCircularConstraint::WithinConstraints(int xSquare, int zSquare) const
{
int dx=halfWayX-xSquare;
int dz=halfWayZ-zSquare;
return (dx*dx+dz*dz <= searchRadiusSq);
}
void CPathFinder::myPQ::DeleteAll()
{
// while(!c.empty())
// c.pop_back();
c.clear();
// c.reserve(1000);
}
CPathFinderDef::~CPathFinderDef() {
}
CRangedGoalWithCircularConstraint::~CRangedGoalWithCircularConstraint() {
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?