pathestimator.cpp

来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 895 行 · 第 1/2 页

CPP
895
字号
	if(goalBlock.x == startBlock.x && goalBlock.y == startBlock.y)
		return CantGetCloser;
	else
		return result;
}


/*
Performs the actual search.
*/
IPath::SearchResult CPathEstimator::DoSearch(const MoveData& moveData, const CPathFinderDef& peDef) {
	bool foundGoal = false;
	while(!openBlocks.empty() && (openBlockBufferPointer - openBlockBuffer) < (maxBlocksToBeSearched - 8)) {
		//Get the open block with lowest cost.
		OpenBlock* ob = openBlocks.top();
		openBlocks.pop();

		//Check if the block has been marked as unaccessable during it's time in queue.
		if(blockState[ob->blocknr].options & (PATHOPT_BLOCKED | PATHOPT_CLOSED | PATHOPT_FORBIDDEN))
			continue;

		//Check if the goal is reached.
		int xBSquare = blockState[ob->blocknr].sqrCenter[moveData.pathType].x;
		int zBSquare = blockState[ob->blocknr].sqrCenter[moveData.pathType].y;
		int xGSquare = ob->block.x * BLOCK_SIZE + goalSqrOffset.x;
		int zGSquare = ob->block.y * BLOCK_SIZE + goalSqrOffset.y;
		if(peDef.IsGoal(xBSquare, zBSquare) || peDef.IsGoal(xGSquare, zGSquare)) {
			goalBlock = ob->block;
			goalHeuristic = 0;
			foundGoal = true;
			break;
		}

		//Test the 8 surrounding blocks.
		TestBlock(moveData, peDef, *ob, PATHDIR_LEFT);
		TestBlock(moveData, peDef, *ob, PATHDIR_LEFT_UP);
		TestBlock(moveData, peDef, *ob, PATHDIR_UP);
		TestBlock(moveData, peDef, *ob, PATHDIR_RIGHT_UP);
		TestBlock(moveData, peDef, *ob, PATHDIR_RIGHT);
		TestBlock(moveData, peDef, *ob, PATHDIR_RIGHT_DOWN);
		TestBlock(moveData, peDef, *ob, PATHDIR_DOWN);
		TestBlock(moveData, peDef, *ob, PATHDIR_LEFT_DOWN);

		//Mark this block as closed.
		blockState[ob->blocknr].options |= PATHOPT_CLOSED;
	}

	//Returning search-result.
	if(foundGoal)
		return Ok;

	//Could not reach the goal.
	if(openBlockBufferPointer - openBlockBuffer >= (maxBlocksToBeSearched - 8))
		return GoalOutOfRange;

	//Search could not reach the goal, due to the unit being locked in.
	if(openBlocks.empty())
		return GoalOutOfRange;

	//Below shall never be runned.
	logOutput << "ERROR: CPathEstimator::DoSearch() - Unhandled end of search!\n";
	return Error;
}


/*
Test the accessability of a block and it's value
and possibly add it to the open-blocks-queue.
*/
void CPathEstimator::TestBlock(const MoveData& moveData, const CPathFinderDef &peDef, OpenBlock& parentOpenBlock, unsigned int direction) {
	testedBlocks++;

	//Initial calculations of the new block.
	int2 block;
	block.x = parentOpenBlock.block.x + directionVector[direction].x;
	block.y = parentOpenBlock.block.y + directionVector[direction].y;
	int vertexNbr = moveData.pathType * nbrOfBlocks * PATH_DIRECTION_VERTICES + parentOpenBlock.blocknr * PATH_DIRECTION_VERTICES + directionVertex[direction];

	//Outside map?
	if(/*block.x < 0 || block.x >= nbrOfBlocksX		//the blocks should never be able to become wrong due to the infinite vertices at the edges
	|| block.y < 0 || block.y >= nbrOfBlocksZ
	||*/ vertexNbr < 0 || vertexNbr >= nbrOfVertices)
		return;

	int blocknr = block.y * nbrOfBlocksX + block.x;
	float blockCost = vertex[vertexNbr];
	if(blockCost >= PATHCOST_INFINITY)
		return;

	//Check if the block is unavailable.
	if(blockState[blocknr].options & (PATHOPT_FORBIDDEN | PATHOPT_BLOCKED | PATHOPT_CLOSED))
		return;

	int xSquare = blockState[blocknr].sqrCenter[moveData.pathType].x;
	int zSquare = blockState[blocknr].sqrCenter[moveData.pathType].y;

	//Check if the block is blocked or out of constraints.
	if(!peDef.WithinConstraints(xSquare, zSquare)) {
		blockState[blocknr].options |= PATHOPT_BLOCKED;
		dirtyBlocks.push_back(blocknr);
		return;
	}

	//Evaluate this node.
	float heuristicCost = peDef.Heuristic(xSquare, zSquare);
	float currentCost = parentOpenBlock.currentCost + blockCost;
	float cost = currentCost + heuristicCost;

	//Check if the block is already in queue and better, then keep it.
	if(blockState[blocknr].options & PATHOPT_OPEN) {
		if(blockState[blocknr].cost <= cost)
			return;
		blockState[blocknr].options &= 255-7;
	}

	//Looking for improvements.
	if(heuristicCost < goalHeuristic) {
		goalBlock = block;
		goalHeuristic = heuristicCost;
	}

	//Store this block as open.
	OpenBlock* ob = ++openBlockBufferPointer;
	ob->block = block;
	ob->blocknr = blocknr;
	ob->cost = cost;
	ob->currentCost = currentCost;
	openBlocks.push(ob);

	//Mark the block as open, and it's parent.
	blockState[blocknr].cost = cost;
	blockState[blocknr].options |= (direction | PATHOPT_OPEN);
	blockState[blocknr].parentBlock = parentOpenBlock.block;
	dirtyBlocks.push_back(blocknr);
}


/*
Recreate the path taken to the goal.
*/
void CPathEstimator::FinishSearch(const MoveData& moveData, Path& path) {
	int2 block = goalBlock;
	while(block.x != startBlock.x || block.y != startBlock.y) {
		int blocknr = block.y * nbrOfBlocksX + block.x;
/*		int xGSquare = block.x * BLOCK_SIZE + goalSqrOffset.x;
		int zGSquare = block.y * BLOCK_SIZE + goalSqrOffset.y;
		//In first case trying to use a by goal defined offset...
		if(!moveData.moveMath->IsBlocked(moveData, moveMathOptions, xGSquare, zGSquare)) {
			float3 pos = SquareToFloat3(xGSquare, zGSquare);
			pos.y = moveData.moveMath->yLevel(xGSquare, zGSquare);
			path.path.push_back(pos);
		}
		//...if not possible, then use offset defined by the block.
		else */{
			int xBSquare = blockState[blocknr].sqrCenter[moveData.pathType].x;
			int zBSquare = blockState[blocknr].sqrCenter[moveData.pathType].y;
			float3 pos = SquareToFloat3(xBSquare, zBSquare);
			path.path.push_back(pos);
		}

		//Next step backwards.
		block = blockState[blocknr].parentBlock;
	}

	//Additional information.
	path.pathCost = blockState[goalBlock.y * nbrOfBlocksX + goalBlock.x].cost - goalHeuristic;
	path.pathGoal = path.path.front();
}


/*
Cleaning lists from last search.
*/
void CPathEstimator::ResetSearch() {
	while(!openBlocks.empty())
		openBlocks.pop();
	while(!dirtyBlocks.empty()) {
		blockState[dirtyBlocks.back()].cost = PATHCOST_INFINITY;
		blockState[dirtyBlocks.back()].parentBlock.x = -1;
		blockState[dirtyBlocks.back()].parentBlock.y = -1;
		blockState[dirtyBlocks.back()].options &= 128;//~PATHOPT_SEARCHRELATED;
		dirtyBlocks.pop_back();
	}
	testedBlocks = 0;
}


/*
Trying to read offset and vertices data from file.
Return false if failed.
TODO: Read-error-check.
*/
bool CPathEstimator::ReadFile(string name)
{
	unsigned int hash=Hash();
	char hashString[50];
	sprintf(hashString,"%u",hash);

	string filename = string("maps/paths/") + stupidGlobalMapname.substr(0, stupidGlobalMapname.find_last_of('.') + 1) + hashString + "." + name + ".zip";

	// open file for reading from a suitable location (where the file exists)
	CArchiveZip* pfile = SAFE_NEW CArchiveZip(filesystem.LocateFile(filename));

	if (!pfile || !pfile->IsOpen()) {
		delete pfile;
		return false;
	}

	std::auto_ptr<CArchiveZip> auto_pfile(pfile);
	CArchiveZip& file(*pfile);

	int fh = file.OpenFile("pathinfo");

	if (fh) {
		unsigned int filehash = 0;
 		//Check hash.
//		logOutput.Print("%i",hash);
		file.ReadFile(fh, &filehash, 4);
		if(filehash != hash)
			return false;

		//Read block-center-offset data.
		int blocknr;
		for(blocknr = 0; blocknr < nbrOfBlocks; blocknr++) {
			file.ReadFile(fh, blockState[blocknr].sqrCenter, moveinfo->moveData.size() * sizeof(int2));
		}

		//Read vertices data.
		file.ReadFile(fh, vertex, nbrOfVertices * sizeof(float));

		//File read successful.
		return true;
	} else {
		return false;
	}
}


/*
Trying to write offset and vertices data to file.
*/
void CPathEstimator::WriteFile(string name) {
	// We need this directory to exist
	if (!filesystem.CreateDirectory("maps/paths"))
		return;

	unsigned int hash = Hash();
	char hashString[50];
	sprintf(hashString,"%u",hash);

	string filename = string("maps/paths/") + stupidGlobalMapname.substr(0, stupidGlobalMapname.find_last_of('.') + 1) + hashString + "." + name + ".zip";
	zipFile file;

	// open file for writing in a suitable location
	file = zipOpen(filesystem.LocateFile(filename, FileSystem::WRITE).c_str(), APPEND_STATUS_CREATE);

	if (file) {
		zipOpenNewFileInZip(file, "pathinfo", NULL, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_BEST_COMPRESSION);

		//Write hash.
		unsigned int hash = Hash();
		zipWriteInFileInZip(file, (void*)&hash, 4);

		//Write block-center-offsets.
		int blocknr;
		for(blocknr = 0; blocknr < nbrOfBlocks; blocknr++) {
			zipWriteInFileInZip(file, (void*)blockState[blocknr].sqrCenter, moveinfo->moveData.size() * sizeof(int2));
			//file.write((char*)blockState[blocknr].sqrCenter, moveinfo->moveData.size() * sizeof(int2));
		}

		//Write vertices.
		zipWriteInFileInZip(file, (void*)vertex, nbrOfVertices * sizeof(float));
		//file.write((char*)vertex, nbrOfVertices * sizeof(float));

		zipCloseFileInZip(file);
		zipClose(file, NULL);
	}
}


/*
Gives a hash-code identifying the dataset of this estimator.
*/
unsigned int CPathEstimator::Hash() {
	return readmap->mapChecksum + moveinfo->moveInfoChecksum + BLOCK_SIZE + moveMathOptions + PATHESTIMATOR_VERSION;
}

void CPathEstimator::Draw(void)
{
	MoveData* md=moveinfo->GetMoveDataFromName("TANKSH2");
	if(!selectedUnits.selectedUnits.empty() && (*selectedUnits.selectedUnits.begin())->unitDef->movedata)
		md=(*selectedUnits.selectedUnits.begin())->unitDef->movedata;

	glDisable(GL_TEXTURE_2D);
	glColor3f(1,1,0);
/*	float blue=BLOCK_SIZE==32?1:0;
	glBegin(GL_LINES);
	for(int z = 0; z < nbrOfBlocksZ; z++) {
		for(int x = 0; x < nbrOfBlocksX; x++) {
			int blocknr = z * nbrOfBlocksX + x;
			float3 p1;
			p1.x=(blockState[blocknr].sqrCenter[md->pathType].x)*8;
			p1.z=(blockState[blocknr].sqrCenter[md->pathType].y)*8;
			p1.y=ground->GetHeight(p1.x,p1.z)+10;

			glColor3f(1,1,blue);
			glVertexf3(p1);
			glVertexf3(p1-UpVector*10);
			for(int dir = 0; dir < PATH_DIRECTION_VERTICES; dir++){
				int obx = x + directionVector[dir].x;
				int obz = z + directionVector[dir].y;

				if(obx >= 0 && obz >= 0 && obx < nbrOfBlocksX && obz < nbrOfBlocksZ) {
					float3 p2;
					int obblocknr = obz * nbrOfBlocksX + obx;

					p2.x=(blockState[obblocknr].sqrCenter[md->pathType].x)*8;
					p2.z=(blockState[obblocknr].sqrCenter[md->pathType].y)*8;
					p2.y=ground->GetHeight(p2.x,p2.z)+10;

					int vertexNbr = md->pathType * nbrOfBlocks * PATH_DIRECTION_VERTICES + blocknr * PATH_DIRECTION_VERTICES + directionVertex[dir];
					float cost=vertex[vertexNbr];

					glColor3f(1/(sqrt(cost/BLOCK_SIZE)),1/(cost/BLOCK_SIZE),blue);
					glVertexf3(p1);
					glVertexf3(p2);
				}
			}
		}

	}
	glEnd();/**/
/*	glEnable(GL_TEXTURE_2D);
	for(int z = 0; z < nbrOfBlocksZ; z++) {
		for(int x = 0; x < nbrOfBlocksX; x++) {
			int blocknr = z * nbrOfBlocksX + x;
			float3 p1;
			p1.x=(blockState[blocknr].sqrCenter[md->pathType].x)*SQUARE_SIZE;
			p1.z=(blockState[blocknr].sqrCenter[md->pathType].y)*SQUARE_SIZE;
			p1.y=ground->GetHeight(p1.x,p1.z)+10;

			glColor3f(1,1,blue);
			for(int dir = 0; dir < PATH_DIRECTION_VERTICES; dir++){
				int obx = x + directionVector[dir].x;
				int obz = z + directionVector[dir].y;

				if(obx >= 0 && obz >= 0 && obx < nbrOfBlocksX && obz < nbrOfBlocksZ) {
					float3 p2;
					int obblocknr = obz * nbrOfBlocksX + obx;

					p2.x=(blockState[obblocknr].sqrCenter[md->pathType].x)*SQUARE_SIZE;
					p2.z=(blockState[obblocknr].sqrCenter[md->pathType].y)*SQUARE_SIZE;
					p2.y=ground->GetHeight(p2.x,p2.z)+10;

					int vertexNbr = md->pathType * nbrOfBlocks * PATH_DIRECTION_VERTICES + blocknr * PATH_DIRECTION_VERTICES + directionVertex[dir];
					float cost=vertex[vertexNbr];

					glColor3f(1,1/(cost/BLOCK_SIZE),blue);

					p2=(p1+p2)/2;
					if(camera->pos.distance(p2)<500){
						glPushMatrix();
						glTranslatef3(p2);
						glScalef(5,5,5);
						font->glWorldPrint("%.0f",cost);
						glPopMatrix();
					}
				}
			}
		}
	}
*/
	if(BLOCK_SIZE==8)
		glColor3f(0.2f,0.7f,0.2f);
	else
		glColor3f(0.2f,0.2f,0.7f);
	glDisable(GL_TEXTURE_2D);
	glBegin(GL_LINES);
	for(OpenBlock*  ob=openBlockBuffer;ob!=openBlockBufferPointer;++ob){
		int blocknr = ob->blocknr;
		float3 p1;
		p1.x=(blockState[blocknr].sqrCenter[md->pathType].x)*SQUARE_SIZE;
		p1.z=(blockState[blocknr].sqrCenter[md->pathType].y)*SQUARE_SIZE;
		p1.y=ground->GetHeight(p1.x,p1.z)+15;

		float3 p2;
		int obx=blockState[ob->blocknr].parentBlock.x;
		int obz=blockState[ob->blocknr].parentBlock.y;
		int obblocknr =  obz * nbrOfBlocksX + obx;

		if(obblocknr>=0){
			p2.x=(blockState[obblocknr].sqrCenter[md->pathType].x)*SQUARE_SIZE;
			p2.z=(blockState[obblocknr].sqrCenter[md->pathType].y)*SQUARE_SIZE;
			p2.y=ground->GetHeight(p2.x,p2.z)+15;

			glVertexf3(p1);
			glVertexf3(p2);
		}
	}
	glEnd();
/*	glEnable(GL_TEXTURE_2D);
	glEnable(GL_BLEND);
	glColor4f(1,0,blue,0.7f);
	glAlphaFunc(GL_GREATER,0.05f);
	int a=0;
	for(OpenBlock*  ob=openBlockBuffer;ob!=openBlockBufferPointer;++ob){
		int blocknr = ob->blocknr;
		float3 p1;
		p1.x=(ob->block.x * BLOCK_SIZE + blockState[blocknr].sqrCenter[md->pathType].x)*SQUARE_SIZE;
		p1.z=(ob->block.y * BLOCK_SIZE + blockState[blocknr].sqrCenter[md->pathType].y)*SQUARE_SIZE;
		p1.y=ground->GetHeight(p1.x,p1.z)+15;

		if(camera->pos.distance(p1)<500){
			glPushMatrix();
			glTranslatef3(p1);
			glScalef(5,5,5);
			font->glWorldPrint("%.0f %.0f",ob->cost,ob->currentCost);
			glPopMatrix();
		}
		++a;
	}
	glDisable(GL_BLEND);*/
}

float3 CPathEstimator::FindBestBlockCenter(const MoveData* moveData, float3 pos)
{
	int pathType=moveData->pathType;
	CRangedGoalWithCircularConstraint rangedGoal(pos,pos, 0,0,SQUARE_SIZE*BLOCK_SIZE*SQUARE_SIZE*BLOCK_SIZE*4);
	IPath::Path path;

	std::vector<float3> startPos;

	int xm=(int)(pos.x/(SQUARE_SIZE*BLOCK_SIZE));
	int ym=(int)(pos.z/(SQUARE_SIZE*BLOCK_SIZE));

	for(int y=max(0,ym-1);y<=min(nbrOfBlocksZ-1,ym+1);++y){
		for(int x=max(0,xm-1);x<=min(nbrOfBlocksX-1,xm+1);++x){
			startPos.push_back(float3(blockState[y*nbrOfBlocksX+x].sqrCenter[pathType].x*SQUARE_SIZE,0,blockState[y*nbrOfBlocksX+x].sqrCenter[pathType].y*SQUARE_SIZE));
		}
	}
	IPath::SearchResult result = pathFinder->GetPath(*moveData, startPos, rangedGoal, path);
	if(result == IPath::Ok && !path.path.empty()) {
		return path.path.back();
	}
	return ZeroVector;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?