pathestimator.cpp
来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 895 行 · 第 1/2 页
CPP
895 行
#include "StdAfx.h"
#include "PathEstimator.h"
#include "LogOutput.h"
#include "Rendering/GL/myGL.h"
#include "FileSystem/FileHandler.h"
#include <fstream>
#include <memory>
#ifndef _WIN32
#include <stdlib.h>
#include <sys/stat.h>
#endif
#include "Map/Ground.h"
#include "Game/SelectedUnits.h"
#include "Sim/Units/Unit.h"
#include "Sim/Units/UnitDef.h"
#include "Rendering/glFont.h"
#include "Game/Camera.h"
#include "TimeProfiler.h"
#include "Platform/FileSystem.h"
#include "lib/minizip/zip.h"
#include "FileSystem/ArchiveZip.h"
#include "mmgr.h"
#define PATHDEBUG false
const unsigned int PATHDIR_LEFT = 0; //+x
const unsigned int PATHDIR_LEFT_UP = 1; //+x+z
const unsigned int PATHDIR_UP = 2; //+z
const unsigned int PATHDIR_RIGHT_UP = 3; //-x+z
const unsigned int PATHDIR_RIGHT = 4; //-x
const unsigned int PATHDIR_RIGHT_DOWN = 5; //-x-z
const unsigned int PATHDIR_DOWN = 6; //-z
const unsigned int PATHDIR_LEFT_DOWN = 7; //+x-z
const unsigned int PATHOPT_OPEN = 8;
const unsigned int PATHOPT_CLOSED = 16;
const unsigned int PATHOPT_FORBIDDEN = 32;
const unsigned int PATHOPT_BLOCKED = 64;
const unsigned int PATHOPT_SEARCHRELATED = (PATHOPT_OPEN | PATHOPT_CLOSED | PATHOPT_FORBIDDEN | PATHOPT_BLOCKED);
const unsigned int PATHOPT_OBSOLETE = 128;
const unsigned int PATHESTIMATOR_VERSION = 34;
const float PATHCOST_INFINITY = 10000000;
const int SQUARES_TO_UPDATE = 600;
extern string stupidGlobalMapname;
/*
Constructor.
Loading precalculated data.
*/
CPathEstimator::CPathEstimator(CPathFinder* pf, unsigned int BSIZE, unsigned int mmOpt, string name) :
pathFinder(pf),
BLOCK_SIZE(BSIZE),
BLOCK_PIXEL_SIZE(BSIZE * SQUARE_SIZE),
BLOCKS_TO_UPDATE(SQUARES_TO_UPDATE / (BLOCK_SIZE * BLOCK_SIZE) + 1),
moveMathOptions(mmOpt)
{
//Gives the changes in (x,z) when moved one step in given direction.
//(Need to be placed befor pre-calculations)
directionVector[PATHDIR_LEFT].x = 1;
directionVector[PATHDIR_LEFT].y = 0;
directionVector[PATHDIR_LEFT_UP].x = 1;
directionVector[PATHDIR_LEFT_UP].y = 1;
directionVector[PATHDIR_UP].x = 0;
directionVector[PATHDIR_UP].y = 1;
directionVector[PATHDIR_RIGHT_UP].x = -1;
directionVector[PATHDIR_RIGHT_UP].y = 1;
directionVector[PATHDIR_RIGHT].x = -1;
directionVector[PATHDIR_RIGHT].y = 0;
directionVector[PATHDIR_RIGHT_DOWN].x = -1;
directionVector[PATHDIR_RIGHT_DOWN].y = -1;
directionVector[PATHDIR_DOWN].x = 0;
directionVector[PATHDIR_DOWN].y = -1;
directionVector[PATHDIR_LEFT_DOWN].x = 1;
directionVector[PATHDIR_LEFT_DOWN].y = -1;
goalSqrOffset.x=BLOCK_SIZE/2;
goalSqrOffset.y=BLOCK_SIZE/2;
//Creates the block-map and the vertices-map.
nbrOfBlocksX = gs->mapx / BLOCK_SIZE;
nbrOfBlocksZ = gs->mapy / BLOCK_SIZE;
nbrOfBlocks = nbrOfBlocksX * nbrOfBlocksZ;
blockState = SAFE_NEW BlockInfo[nbrOfBlocks];
nbrOfVertices = moveinfo->moveData.size() * nbrOfBlocks * PATH_DIRECTION_VERTICES;
vertex = SAFE_NEW float[nbrOfVertices];
openBlockBufferPointer=openBlockBuffer;
int i;
for(i = 0; i < nbrOfVertices; i++)
vertex[i] = PATHCOST_INFINITY;
//Initialize blocks.
int x, z;
for(z = 0; z < nbrOfBlocksZ; z++){
for(x = 0; x < nbrOfBlocksX; x++) {
int blocknr = z * nbrOfBlocksX + x;
blockState[blocknr].cost = PATHCOST_INFINITY;
blockState[blocknr].options = 0;
blockState[blocknr].parentBlock.x = -1;
blockState[blocknr].parentBlock.y = -1;
blockState[blocknr].sqrCenter = SAFE_NEW int2[moveinfo->moveData.size()];
}
}
//Pre-read/calculate data.
PrintLoadMsg("Reading estimate path costs");
if(!ReadFile(name)) {
//Generate text-message.
char calcMsg[1000], buffer[10];
strcpy(calcMsg, "Analyzing map accessability \"");
SNPRINTF(buffer,10,"%d",BLOCK_SIZE);
strcat(calcMsg, buffer);
strcat(calcMsg, "\"");
PrintLoadMsg(calcMsg);
//Calculating block-center-offsets.
for(z = 0; z < nbrOfBlocksZ; z++) {
for(x = 0; x < nbrOfBlocksX; x++) {
vector<MoveData*>::iterator mi;
for(mi = moveinfo->moveData.begin(); mi < moveinfo->moveData.end(); mi++) {
FindOffset(**mi, x, z);
}
}
}
//Calculating vectors.
vector<MoveData*>::iterator mi;
for(mi = moveinfo->moveData.begin(); mi < moveinfo->moveData.end(); mi++) {
//Generate text-message.
char calcMsg[10000];
sprintf(calcMsg,"Calculating estimate path costs \"%i\" %i/%i",BLOCK_SIZE,(*mi)->pathType,moveinfo->moveData.size());
PrintLoadMsg(calcMsg);
//Calculate
for(z = 0; z < nbrOfBlocksZ; z++) {
for(x = 0; x < nbrOfBlocksX; x++) {
CalculateVertices(**mi, x, z);
}
}
}
WriteFile(name);
}
//As all vertexes are bidirectional and having equal values
//in both directions, only one value are needed to be stored.
//This vector helps getting the right vertex.
//(Need to be placed after pre-calculations)
directionVertex[PATHDIR_LEFT] = PATHDIR_LEFT;
directionVertex[PATHDIR_LEFT_UP] = PATHDIR_LEFT_UP;
directionVertex[PATHDIR_UP] = PATHDIR_UP;
directionVertex[PATHDIR_RIGHT_UP] = PATHDIR_RIGHT_UP;
directionVertex[PATHDIR_RIGHT] = int(PATHDIR_LEFT) - PATH_DIRECTION_VERTICES;
directionVertex[PATHDIR_RIGHT_DOWN] = int(PATHDIR_LEFT_UP) - (nbrOfBlocksX * PATH_DIRECTION_VERTICES) - PATH_DIRECTION_VERTICES;
directionVertex[PATHDIR_DOWN] = int(PATHDIR_UP) - (nbrOfBlocksX * PATH_DIRECTION_VERTICES);
directionVertex[PATHDIR_LEFT_DOWN] = int(PATHDIR_RIGHT_UP) - (nbrOfBlocksX * PATH_DIRECTION_VERTICES) + PATH_DIRECTION_VERTICES;
pathCache=SAFE_NEW CPathCache(nbrOfBlocksX,nbrOfBlocksZ);
}
/*
Destructor
Free all used memory.
*/
CPathEstimator::~CPathEstimator() {
int i;
for(i = 0; i < nbrOfBlocks; i++) {
delete[] blockState[i].sqrCenter;
}
delete[] blockState;
delete[] vertex;
delete pathCache;
}
/*
Finds a square accessable by the given movedata within the given block.
*/
void CPathEstimator::FindOffset(const MoveData& moveData, int blockX, int blockZ) {
//Block lower corner position.
int lowerX = blockX * BLOCK_SIZE;
int lowerZ = blockZ * BLOCK_SIZE;
//Search for an accessable position.
float best=100000000;
int bestX=BLOCK_SIZE/2;
int bestZ=BLOCK_SIZE/2;
int x, z;
for(z = 1; z < BLOCK_SIZE; z += 2){
for(x = 1; x < BLOCK_SIZE; x += 2) {
int dx=x-BLOCK_SIZE/2;
int dz=z-BLOCK_SIZE/2;
float cost=dx*dx+dz*dz+(BLOCK_SIZE*BLOCK_SIZE/8)/(0.001f+moveData.moveMath->SpeedMod(moveData, lowerX+x, lowerZ+z));
if(moveData.moveMath->IsBlocked2(moveData, lowerX+x, lowerZ+z) & (CMoveMath::BLOCK_STRUCTURE | CMoveMath::BLOCK_TERRAIN))
cost+=1000000;
if(cost<best){
best=cost;
bestX=x;
bestZ=z;
}
}
}
//Store the offset found.
blockState[blockZ * nbrOfBlocksX + blockX].sqrCenter[moveData.pathType].x = blockX * BLOCK_SIZE + bestX;
blockState[blockZ * nbrOfBlocksX + blockX].sqrCenter[moveData.pathType].y = blockZ * BLOCK_SIZE + bestZ;
}
/*
Calculate all vertices connected from given block.
(Which is 4 out of 8 vertices connected to the block.)
*/
void CPathEstimator::CalculateVertices(const MoveData& moveData, int blockX, int blockZ) {
unsigned int dir;
for(dir = 0; dir < PATH_DIRECTION_VERTICES; dir++)
CalculateVertex(moveData, blockX, blockZ, dir);
}
/*
Calculate requested vertex.
*/
void CPathEstimator::CalculateVertex(const MoveData& moveData, int parentBlockX, int parentBlockZ, unsigned int direction) {
//Initial calculations.
int parentBlocknr = parentBlockZ * nbrOfBlocksX + parentBlockX;
int childBlockX = parentBlockX + directionVector[direction].x;
int childBlockZ = parentBlockZ + directionVector[direction].y;
int vertexNbr = moveData.pathType * nbrOfBlocks * PATH_DIRECTION_VERTICES + parentBlocknr * PATH_DIRECTION_VERTICES + direction;
//Outside map?
if(childBlockX < 0 || childBlockZ < 0
|| childBlockX >= nbrOfBlocksX || childBlockZ >= nbrOfBlocksZ) {
vertex[vertexNbr] = PATHCOST_INFINITY;
return;
}
//Starting position.
int parentXSquare = blockState[parentBlocknr].sqrCenter[moveData.pathType].x;
int parentZSquare = blockState[parentBlocknr].sqrCenter[moveData.pathType].y;
float3 startPos = SquareToFloat3(parentXSquare, parentZSquare);
//Goal position.
int childBlocknr = childBlockZ * nbrOfBlocksX + childBlockX;
int childXSquare = blockState[childBlocknr].sqrCenter[moveData.pathType].x;
int childZSquare = blockState[childBlocknr].sqrCenter[moveData.pathType].y;
float3 goalPos = SquareToFloat3(childXSquare, childZSquare);
//PathFinder definiton.
CRangedGoalWithCircularConstraint pfDef(startPos, goalPos, 0, 1.1f,2);
//Path
Path path;
//Performs the search.
SearchResult result = pathFinder->GetPath(moveData, startPos, pfDef, path, false, true,10000,false);
//Store the result.
if(result == Ok) {
vertex[vertexNbr] = path.pathCost;
} else {
vertex[vertexNbr] = PATHCOST_INFINITY;
}
}
/*
Mark affected blocks as obsolete.
*/
void CPathEstimator::MapChanged(unsigned int x1, unsigned int z1, unsigned int x2, unsigned z2) {
//Finding the upper and lower corner of the rectangular area.
int lowerX, upperX, lowerZ, upperZ;
if(x1 < x2) {
lowerX = x1 / BLOCK_SIZE-1;
upperX = x2 / BLOCK_SIZE;
} else {
lowerX = x2 / BLOCK_SIZE-1;
upperX = x1 / BLOCK_SIZE;
}
if(z1 < z2) {
lowerZ = z1 / BLOCK_SIZE-1;
upperZ = z2 / BLOCK_SIZE;
} else {
lowerZ = z2 / BLOCK_SIZE-1;
upperZ = z1 / BLOCK_SIZE;
}
//Error-check.
upperX = min(upperX, nbrOfBlocksX - 1);
upperZ = min(upperZ, nbrOfBlocksZ - 1);
if(lowerX<0) lowerX=0;
if(lowerZ<0) lowerZ=0;
//Marking the blocks inside the rectangle.
//Enqueing them from upper to lower becourse of
//the placement of the bi-directional vertices.
for(int z = upperZ; z >= lowerZ; z--){
for(int x = upperX; x >= lowerX; x--) {
if(!(blockState[z * nbrOfBlocksX + x].options & PATHOPT_OBSOLETE)){
vector<MoveData*>::iterator mi;
for(mi = moveinfo->moveData.begin(); mi < moveinfo->moveData.end(); mi++) {
SingleBlock sb;
sb.block.x = x;
sb.block.y = z;
sb.moveData = *mi;
needUpdate.push_back(sb);
blockState[z * nbrOfBlocksX + x].options |= PATHOPT_OBSOLETE;
}
}
}
}
}
/*
Updating some obsolete blocks.
Using FIFO-principle.
*/
void CPathEstimator::Update() {
pathCache->Update();
int counter = 0;
while(!needUpdate.empty() && counter < BLOCKS_TO_UPDATE) {
//Next block in line.
SingleBlock sb = needUpdate.front();
needUpdate.pop_front();
int blocknr = sb.block.y * nbrOfBlocksX + sb.block.x;
//Check if already updated.
if(!(blockState[blocknr].options & PATHOPT_OBSOLETE))
continue;
//Update the block.
FindOffset(*sb.moveData, sb.block.x, sb.block.y);
CalculateVertices(*sb.moveData, sb.block.x, sb.block.y);
//Mark as updated.
if(sb.moveData==moveinfo->moveData.back()){
blockState[blocknr].options &= ~PATHOPT_OBSOLETE;
}
//One block updated.
counter++;
}
}
/*
Storing data and doing some top-administration.
*/
IPath::SearchResult CPathEstimator::GetPath(const MoveData& moveData, float3 start, const CPathFinderDef& peDef, Path& path, unsigned int maxSearchedBlocks) {
start.CheckInBounds();
//Clear path.
path.path.clear();
path.pathCost = PATHCOST_INFINITY;
//Initial calculations.
maxBlocksToBeSearched = std::min(maxSearchedBlocks, (unsigned int) MAX_SEARCHED_BLOCKS);
startBlock.x = (int)(start.x / BLOCK_PIXEL_SIZE);
startBlock.y = (int)(start.z / BLOCK_PIXEL_SIZE);
startBlocknr = startBlock.y * nbrOfBlocksX + startBlock.x;
int2 goalBlock;
goalBlock.x=peDef.goalSquareX/BLOCK_SIZE;
goalBlock.y=peDef.goalSquareZ/BLOCK_SIZE;
CPathCache::CacheItem* ci=pathCache->GetCachedPath(startBlock,goalBlock,peDef.sqGoalRadius,moveData.pathType);
if(ci){
// logOutput.Print("Using cached path %i",BLOCK_SIZE);
path=ci->path;
/* if(BLOCK_SIZE==8){
}else{
}*/
return ci->result;
}
// logOutput.Print("----Creating new path %i",BLOCK_SIZE);
//Search
SearchResult result = InitSearch(moveData, peDef);
//If successful, generate path.
if(result == Ok || result == GoalOutOfRange) {
FinishSearch(moveData, path);
pathCache->AddPath(&path,result,startBlock,goalBlock,peDef.sqGoalRadius,moveData.pathType); //only add succesfull paths to the cache
if(PATHDEBUG) {
logOutput << "PE: Search completed.\n";
logOutput << "Tested blocks: " << testedBlocks << "\n";
logOutput << "Open blocks: " << (float)(openBlockBufferPointer - openBlockBuffer) << "\n";
logOutput << "Path length: " << (int)(path.path.size()) << "\n";
logOutput << "Path cost: " << path.pathCost << "\n";
}
} else {
if(PATHDEBUG) {
logOutput << "PE: Search failed!\n";
logOutput << "Tested blocks: " << testedBlocks << "\n";
logOutput << "Open blocks: " << (float)(openBlockBufferPointer - openBlockBuffer) << "\n";
}
}
/* if(BLOCK_SIZE==8){
}else{
}*/
return result;
}
/*
Making some initial calculations and preparations.
*/
IPath::SearchResult CPathEstimator::InitSearch(const MoveData& moveData, const CPathFinderDef& peDef) {
//Starting square is inside goal area?
int xSquare = blockState[startBlocknr].sqrCenter[moveData.pathType].x;
int zSquare = blockState[startBlocknr].sqrCenter[moveData.pathType].y;
if(peDef.IsGoal(xSquare, zSquare))
return CantGetCloser;
//Cleaning the system from last search.
ResetSearch();
//Marks and store the start-block.
blockState[startBlocknr].options |= PATHOPT_OPEN;
blockState[startBlocknr].cost = 0;
dirtyBlocks.push_back(startBlocknr);
//Adding the starting block to the open-blocks-queue.
OpenBlock* ob = openBlockBufferPointer = openBlockBuffer;
ob->cost = 0;
ob->currentCost = 0;
ob->block = startBlock;
ob->blocknr = startBlocknr;
openBlocks.push(ob);
//Mark starting point as best found position.
goalBlock = startBlock;
goalHeuristic = peDef.Heuristic(xSquare, zSquare);
//Gets goal square offset.
goalSqrOffset = peDef.GoalSquareOffset(BLOCK_SIZE);
//Performs the search.
SearchResult result = DoSearch(moveData, peDef);
//If no improvements are found, then return CantGetCloser instead.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?