quadfield.cpp

来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 568 行

CPP
568
字号
#include "StdAfx.h"
// QuadField.cpp: implementation of the CQuadField class.
//
//////////////////////////////////////////////////////////////////////

#include "QuadField.h"

#include "Sim/Units/Unit.h"
#include "LogOutput.h"
#include "Feature.h"
#include "creg/STL_List.h"
#include "mmgr.h"


CR_BIND(CQuadField, );
CR_REG_METADATA(CQuadField, (
		CR_MEMBER(numQuadsX),
		CR_MEMBER(numQuadsZ),
//		CR_MEMBER(baseQuads),
		CR_RESERVED(8),
		CR_SERIALIZER(Serialize)
		));


void CQuadField::Serialize(creg::ISerializer& s)
{
	// no need to alloc quad array, this has already been done in constructor
	for(int y=0;y<numQuadsZ;++y)
		for(int x=0;x<numQuadsX;++x)
			s.SerializeObjectInstance(&baseQuads[y*numQuadsX+x], Quad::StaticClass());
}



CR_BIND(CQuadField::Quad, );

CR_REG_METADATA_SUB(CQuadField, Quad, (
		//float startx;  // constant, assigned in constructor
		//float starty;
		CR_MEMBER(units),
		CR_MEMBER(teamUnits),
		CR_MEMBER(features)
		));


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CQuadField* qf;

CQuadField::CQuadField()
{
	numQuadsX=gs->mapx*SQUARE_SIZE/QUAD_SIZE;
	numQuadsZ=gs->mapy*SQUARE_SIZE/QUAD_SIZE;

	baseQuads.resize(numQuadsX*numQuadsZ);

	for(int y=0;y<numQuadsZ;++y){
		for(int x=0;x<numQuadsX;++x){
			baseQuads[y*numQuadsX+x].startx=x*QUAD_SIZE;
			baseQuads[y*numQuadsX+x].starty=y*QUAD_SIZE;
		}
	}

	tempQuads = new int[1000];
//	tempUnitsArray.resize(MAX_UNITS);
//	tempFeaturesArray.resize(MAX_UNITS);
}

CQuadField::~CQuadField()
{
	delete[] tempQuads;
}

vector<int> CQuadField::GetQuads(float3 pos,float radius)
{
	pos.CheckInBounds();

	vector<int> ret;
	int maxx=min(((int)(pos.x+radius))/QUAD_SIZE+1,numQuadsX-1);
	int maxy=min(((int)(pos.z+radius))/QUAD_SIZE+1,numQuadsZ-1);

	int minx=max(((int)(pos.x-radius))/QUAD_SIZE,0);
	int miny=max(((int)(pos.z-radius))/QUAD_SIZE,0);

	if(maxy<miny || maxx<minx)
		return ret;

	float maxSqLength=(radius+QUAD_SIZE*0.72f)*(radius+QUAD_SIZE*0.72f);
	ret.reserve((maxy-miny)*(maxx-minx));
	for(int y=miny;y<=maxy;++y)
		for(int x=minx;x<=maxx;++x)
			if((pos-float3(x*QUAD_SIZE+QUAD_SIZE*0.5f,0,y*QUAD_SIZE+QUAD_SIZE*0.5f)).SqLength2D()<maxSqLength)
				ret.push_back(y*numQuadsX+x);

	return ret;
}


void CQuadField::GetQuads(float3 pos,float radius, int*& dst)
{
	pos.CheckInBounds();

	int maxx=min(((int)(pos.x+radius))/QUAD_SIZE+1,numQuadsX-1);
	int maxy=min(((int)(pos.z+radius))/QUAD_SIZE+1,numQuadsZ-1);

	int minx=max(((int)(pos.x-radius))/QUAD_SIZE,0);
	int miny=max(((int)(pos.z-radius))/QUAD_SIZE,0);

	if(maxy<miny || maxx<minx)
		return;

	float maxSqLength=(radius+QUAD_SIZE*0.72f)*(radius+QUAD_SIZE*0.72f);
	for(int y=miny;y<=maxy;++y)
		for(int x=minx;x<=maxx;++x)
			if((pos-float3(x*QUAD_SIZE+QUAD_SIZE*0.5f,0,y*QUAD_SIZE+QUAD_SIZE*0.5f)).SqLength2D()<maxSqLength)
			{
				*dst = y*numQuadsX+x;
				++dst;
			}
}


void CQuadField::MovedUnit(CUnit *unit)
{
	vector<int> newQuads=GetQuads(unit->pos,unit->radius);

	if(newQuads.size()==unit->quads.size()){
		vector<int>::iterator qi1,qi2;
		qi1=unit->quads.begin();
		for(qi2=newQuads.begin();qi2!=newQuads.end();++qi2){
			if(*qi1!=*qi2)
				break;
			++qi1;
		}
		if(qi2==newQuads.end())
			return;
	}
	vector<int>::iterator qi;
	for(qi=unit->quads.begin();qi!=unit->quads.end();++qi){
		list<CUnit*>::iterator ui;
		for(ui=baseQuads[*qi].units.begin();ui!=baseQuads[*qi].units.end();++ui){
			if(*ui==unit){
				baseQuads[*qi].units.erase(ui);
				break;
			}
		}
		for(ui=baseQuads[*qi].teamUnits[unit->allyteam].begin();ui!=baseQuads[*qi].teamUnits[unit->allyteam].end();++ui){
			if(*ui==unit){
				baseQuads[*qi].teamUnits[unit->allyteam].erase(ui);
				break;
			}
		}
	}
	for(qi=newQuads.begin();qi!=newQuads.end();++qi){
		baseQuads[*qi].units.push_front(unit);
		baseQuads[*qi].teamUnits[unit->allyteam].push_front(unit);
	}
	unit->quads=newQuads;
}

vector<CUnit*> CQuadField::GetUnits(const float3& pos,float radius)
{
	vector<CUnit*> units;

	int* endQuad=tempQuads;
	GetQuads(pos,radius,endQuad);

	int tempNum=gs->tempNum++;

	for(int* a=tempQuads;a!=endQuad;++a){
		Quad& quad = baseQuads[*a];
		for(list<CUnit*>::iterator ui=quad.units.begin();ui!=quad.units.end();++ui){
			if((*ui)->tempNum!=tempNum){
				(*ui)->tempNum=tempNum;
				units.push_back(*ui);
			}
		}
	}

	return units;
}

vector<CUnit*> CQuadField::GetUnitsExact(const float3& pos,float radius)
{
	vector<CUnit*> units;
/*	if(pos.x<0 || pos.z<0 || pos.x>gs->mapx*SQUARE_SIZE || pos.z>gs->mapy*SQUARE_SIZE){
		logOutput.Print("Trying to get units outside map %.0f %.0f",pos.x,pos.z);
		return units;
	}*/

	int* endQuad=tempQuads;
	GetQuads(pos,radius,endQuad);

	int tempNum=gs->tempNum++;

	for(int* a=tempQuads;a!=endQuad;++a){
		Quad& quad = baseQuads[*a];
		for(list<CUnit*>::iterator ui=quad.units.begin();ui!=quad.units.end();++ui){
			float totRad=radius+(*ui)->radius;
			if((*ui)->tempNum!=tempNum && (pos-(*ui)->midPos).SqLength()<totRad*totRad){
				(*ui)->tempNum=tempNum;
				units.push_back(*ui);
			}
		}
	}

	return units;
}

vector<CUnit*> CQuadField::GetUnitsExact(const float3& mins, const float3& maxs)
{
	vector<CUnit*> units;

	vector<int> quads = GetQuadsRectangle(mins, maxs);

	int tempNum = gs->tempNum++;

	vector<int>::iterator qi;
	for (qi = quads.begin(); qi != quads.end(); ++qi) {
		list<CUnit*>& quadUnits = baseQuads[*qi].units;
		list<CUnit*>::iterator ui;
		for (ui = quadUnits.begin(); ui != quadUnits.end(); ++ui) {
			CUnit* unit = *ui;
			const float3& pos = unit->midPos;
			if ((unit->tempNum != tempNum) &&
			    (pos.x > mins.x) && (pos.x < maxs.x) &&
			    (pos.z > mins.z) && (pos.z < maxs.z)) {
				unit->tempNum = tempNum;
				units.push_back(unit);
			}
		}
	}

	return units;
}

vector<int> CQuadField::GetQuadsOnRay(const float3& start, float3 dir, float length)
{

	int* end = tempQuads;
	GetQuadsOnRay(start,dir,length,end);

	return vector<int>(tempQuads,end);
}

void CQuadField::GetQuadsOnRay(float3 start, float3 dir,float length, int*& dst)
{
	if(start.x<1){
		if(dir.x==0)
			dir.x=0.00001f;
		start=start+dir*((1-start.x)/dir.x);
	}
	if(start.x>gs->mapx*SQUARE_SIZE-1){
		if(dir.x==0)
			dir.x=0.00001f;
		start=start+dir*((gs->mapx*SQUARE_SIZE-1-start.x)/dir.x);
	}
	if(start.z<1){
		if(dir.z==0)
			dir.z=0.00001f;
		start=start+dir*((1-start.z)/dir.z);
	}
	if(start.z>gs->mapy*SQUARE_SIZE-1){
		if(dir.z==0)
			dir.z=0.00001f;
		start=start+dir*((gs->mapy*SQUARE_SIZE-1-start.z)/dir.z);
	}

	if(start.x<1){
		start.x=1;
	}
	if(start.x>gs->mapx*SQUARE_SIZE-1){
		start.x=gs->mapx*SQUARE_SIZE-1;
	}
	if(start.z<1){
		start.z=1;
	}
	if(start.z>gs->mapy*SQUARE_SIZE-1){
		start.z=gs->mapy*SQUARE_SIZE-1;
	}

	float3 to=start+dir*length;

	if(to.x<1){
		to=to-dir*((to.x-1)/dir.x);
	}
	if(to.x>gs->mapx*SQUARE_SIZE-1){
		to=to-dir*((to.x-gs->mapx*SQUARE_SIZE+1)/dir.x);
	}
	if(to.z<1){
		to=to-dir*((to.z-1)/dir.z);
	}
	if(to.z>gs->mapy*SQUARE_SIZE-1){
		to=to-dir*((to.z-gs->mapy*SQUARE_SIZE+1)/dir.z);
	}
	//these 4 shouldnt be needed but sometimes we seem to get strange enough values that rounding errors throw us outide the map
	if(to.x<1){
		to.x=1;
	}
	if(to.x>gs->mapx*SQUARE_SIZE-1){
		to.x=gs->mapx*SQUARE_SIZE-1;
	}
	if(to.z<1){
		to.z=1;
	}
	if(to.z>gs->mapy*SQUARE_SIZE-1){
		to.z=gs->mapy*SQUARE_SIZE-1;
	}
//	if(to.x<0){
///		logOutput.Print("error %f %f %f %f %f %f %f %f",start.x,start.z,to.x,to.z,dir.x,dir.z,dir.y,length);
//	}

	float dx=to.x-start.x;
	float dz=to.z-start.z;
	float xp=start.x;
	float zp=start.z;
	float xn,zn;
	float invQuadSize=1.0f/QUAD_SIZE;

	if((floor(start.x*invQuadSize)==floor(to.x*invQuadSize)) && (floor(start.z*invQuadSize)==floor(to.z*invQuadSize))){
		*dst=((int(start.x*invQuadSize))+(int(start.z*invQuadSize))*numQuadsX);
		++dst;
	} else if(floor(start.x*invQuadSize)==floor(to.x*invQuadSize)){
		int first=(int(start.x*invQuadSize))+(int(start.z*invQuadSize))*numQuadsX;
		int last=(int(to.x*invQuadSize))+(int(to.z*invQuadSize))*numQuadsX;
		if(dz>0)
			for(int a=first;a<=last;a+=numQuadsX){
				*dst=(a);
				++dst;
			}
		else
			for(int a=first;a>=last;a-=numQuadsX){
				*dst=(a);
				++dst;
			}
	} else if(floor(start.z*invQuadSize)==floor(to.z*invQuadSize)){
		int first=(int(start.x*invQuadSize))+(int(start.z*invQuadSize))*numQuadsX;
		int last=(int(to.x*invQuadSize))+(int(to.z*invQuadSize))*numQuadsX;
		if(dx>0)
			for(int a=first;a<=last;a++){
				*dst=(a);
				++dst;
			}
		else
			for(int a=first;a>=last;a--){
				*dst=(a);
				++dst;
			}
	} else {
		bool keepgoing=true;
		for(int i = 0; i < 1000 && keepgoing; i++){
			*dst=((int(zp*invQuadSize))*numQuadsX+(int(xp*invQuadSize)));
			++dst;

			if(dx>0){
				xn=(floor(xp*invQuadSize)*QUAD_SIZE+QUAD_SIZE-xp)/dx;
			} else {
				xn=(floor(xp*invQuadSize)*QUAD_SIZE-xp)/dx;
			}
			if(dz>0){
				zn=(floor(zp*invQuadSize)*QUAD_SIZE+QUAD_SIZE-zp)/dz;
			} else {
				zn=(floor(zp*invQuadSize)*QUAD_SIZE-zp)/dz;
			}

			if(xn<zn){
				xp+=(xn+0.0001f)*dx;
				zp+=(xn+0.0001f)*dz;
			} else {
				xp+=(zn+0.0001f)*dx;
				zp+=(zn+0.0001f)*dz;
			}
			keepgoing=fabs(xp-start.x)<fabs(to.x-start.x) && fabs(zp-start.z)<fabs(to.z-start.z);
		}
	}
}

void CQuadField::RemoveUnit(CUnit* unit)
{
	std::vector<int>::iterator qi;
	for(qi=unit->quads.begin();qi!=unit->quads.end();++qi){
		list<CUnit*>::iterator ui;
		for(ui=baseQuads[*qi].units.begin();ui!=baseQuads[*qi].units.end();++ui){
			if(*ui==unit){
				baseQuads[*qi].units.erase(ui);
				break;
			}
		}
		for(ui=baseQuads[*qi].teamUnits[unit->allyteam].begin();ui!=baseQuads[*qi].teamUnits[unit->allyteam].end();++ui){
			if(*ui==unit){
				baseQuads[*qi].teamUnits[unit->allyteam].erase(ui);
				break;
			}
		}
	}
}

void CQuadField::AddFeature(CFeature* feature)
{
	vector<int> newQuads=GetQuads(feature->pos,feature->radius);

	vector<int>::iterator qi;
	for(qi=newQuads.begin();qi!=newQuads.end();++qi){
		baseQuads[*qi].features.push_front(feature);
	}
}

void CQuadField::RemoveFeature(CFeature* feature)
{
	vector<int> quads=GetQuads(feature->pos,feature->radius);

	std::vector<int>::iterator qi;
	for(qi=quads.begin();qi!=quads.end();++qi){
		baseQuads[*qi].features.remove(feature);
	}
}

vector<CFeature*> CQuadField::GetFeaturesExact(const float3& pos,float radius)
{
	vector<CFeature*> features;
/*	if(pos.x<0 || pos.z<0 || pos.x>gs->mapx*SQUARE_SIZE || pos.z>gs->mapy*SQUARE_SIZE){
		logOutput.Print("Trying to get units outside map %.0f %.0f",pos.x,pos.z);
		return units;
	}*/

	vector<int> quads=GetQuads(pos,radius);

	int tempNum=gs->tempNum++;

	vector<int>::iterator qi;
	for(qi=quads.begin();qi!=quads.end();++qi){
		list<CFeature*>::iterator fi;
		for(fi=baseQuads[*qi].features.begin();fi!=baseQuads[*qi].features.end();++fi){
			float totRad=radius+(*fi)->radius;
			if((*fi)->tempNum!=tempNum && (pos-(*fi)->midPos).SqLength()<totRad*totRad){
				(*fi)->tempNum=tempNum;
				features.push_back(*fi);
			}
		}
	}

	return features;
}

vector<CFeature*> CQuadField::GetFeaturesExact(const float3& mins,
                                               const float3& maxs)
{
	vector<CFeature*> features;

	vector<int> quads = GetQuadsRectangle(mins, maxs);

	int tempNum = gs->tempNum++;

	vector<int>::iterator qi;
	for(qi = quads.begin(); qi != quads.end(); ++qi) {
		list<CFeature*>& quadFeatures = baseQuads[*qi].features;
		list<CFeature*>::iterator fi;
		for (fi = quadFeatures.begin(); fi != quadFeatures.end(); ++fi) {
			CFeature* feature = *fi;
			const float3& pos = feature->midPos;
			if ((feature->tempNum != tempNum) &&
				  (pos.x > mins.x) && (pos.x < maxs.x) &&
					(pos.z > mins.z) && (pos.z < maxs.z)) {
				feature->tempNum = tempNum;
				features.push_back(feature);
			}
		}
	}

	return features;
}

vector<CSolidObject*> CQuadField::GetSolidsExact(const float3& pos,float radius)
{
	vector<CSolidObject*> solids;
/*	if(pos.x<0 || pos.z<0 || pos.x>gs->mapx*SQUARE_SIZE || pos.z>gs->mapy*SQUARE_SIZE){
		logOutput.Print("Trying to get units outside map %.0f %.0f",pos.x,pos.z);
		return units;
	}*/

	vector<int> quads=GetQuads(pos,radius);

	int tempNum=gs->tempNum++;

	vector<int>::iterator qi;
	for(qi=quads.begin();qi!=quads.end();++qi){
		list<CUnit*>::iterator ui;
		for(ui=baseQuads[*qi].units.begin();ui!=baseQuads[*qi].units.end();++ui){
			if (!(*ui)->blocking)
				continue;

			float totRad=radius+(*ui)->radius;
			if((*ui)->tempNum!=tempNum && (pos-(*ui)->midPos).SqLength()<totRad*totRad){
				(*ui)->tempNum=tempNum;
				solids.push_back(*ui);
			}
		}

		list<CFeature*>::iterator fi;
		for(fi=baseQuads[*qi].features.begin();fi!=baseQuads[*qi].features.end();++fi){
			if (!(*fi)->blocking)
				continue;

			float totRad=radius+(*fi)->radius;
			if((*fi)->tempNum!=tempNum && (pos-(*fi)->midPos).SqLength()<totRad*totRad){
				(*fi)->tempNum=tempNum;
				solids.push_back(*fi);
			}
		}
	}

	return solids;
}

vector<int> CQuadField::GetQuadsRectangle(const float3& pos,const float3& pos2)
{
	vector<int> ret;

	int maxx=max(0,min(((int)(pos2.x))/QUAD_SIZE+1,numQuadsX-1));
	int maxy=max(0,min(((int)(pos2.z))/QUAD_SIZE+1,numQuadsZ-1));

	int minx=max(0,min(((int)(pos.x))/QUAD_SIZE,numQuadsX-1));
	int miny=max(0,min(((int)(pos.z))/QUAD_SIZE,numQuadsZ-1));

	if(maxy<miny || maxx<minx)
		return ret;

	ret.reserve((maxy-miny)*(maxx-minx));
	for(int y=miny;y<=maxy;++y)
		for(int x=minx;x<=maxx;++x)
			ret.push_back(y*numQuadsX+x);

	return ret;

}

// optimization specifically for projectile collisions
void CQuadField::GetUnitsAndFeaturesExact(const float3& pos, float radius, CUnit**& dstUnit, CFeature**& dstFeature)
{
	int tempNum=gs->tempNum++;

	int* endQuad = tempQuads;
	GetQuads(pos, radius, endQuad);

	for(int* a=tempQuads;a!=endQuad;++a){
		Quad& quad = baseQuads[*a];
		for(list<CUnit*>::iterator ui=quad.units.begin();ui!=quad.units.end();++ui){
			if((*ui)->tempNum!=tempNum){
				(*ui)->tempNum=tempNum;
				*dstUnit=(*ui);
				++dstUnit;
			}
		}

		for(list<CFeature*>::iterator fi=quad.features.begin();fi!=quad.features.end();++fi){
			float totRad=radius+(*fi)->radius;
			if((*fi)->tempNum!=tempNum && (pos-(*fi)->midPos).SqLength()<totRad*totRad){
				(*fi)->tempNum=tempNum;
				*dstFeature=(*fi);
				++dstFeature;
			}
		}
	}
}

⌨️ 快捷键说明

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