2d游戏地图渲染图层顺序(2)

上一篇 2d游戏地图渲染图层顺序

讲了大概的思路,下面我们来看看具体的代码。

1.基础准备

1.1.提供一个结构体用于存放建筑物指针和建筑物的度edge

struct BUILDING_EDGE{
    CityNodes cityNode;
    int edge = 0;
};

1.2.提供一个结构体用于表达建筑物覆盖关系

struct NODE_FROM_TO {
    CityNodes fromNode;
    CityNodes toNode;
};

表示fromNode 覆盖 toNode

1.3.提供一个map用于存放建筑物ID和他的度edge

map<int, BUILDING_EDGE> buildingEdge;

1.4.提供一个list用于记录建筑物覆盖关系

list<NODE_FROM_TO> nodeList;

1.5提供一个queue用于存储需要输出的渲染的建筑物顺序

queue<CityNodes> drawQueue;

2.程序设计思路

2.1画建筑物原则

城市节点需要记录x,y坐标上节点是否可用

如果鼠标移动到x,y坐标上该节点为可用状态,并且我们需要画的建筑物A,假设A占地空间为2*2个格子,即当前(x,y) (x,y-1) (x+1,y) (x+1,y-1)格子均要可以使用才能安放建筑物

2.2 FindNodeEdge方法去找到每个建筑物的度edge

假设下图AB两个建筑物,经过大量的建筑物遮挡图片发现

建筑物主体高度不超过一个格,即B建筑物对A建筑物的遮盖可以看做是(x,y+1)位置是否存在建筑物。以及如下图黄色圈圈处都需判断是否存在建筑物。如果存在建筑物,那么这些建筑物就应该对本建筑物造成遮盖。即表达为fromNode=B;toNode=A把这对关系存入list<NODE_FROM_TO> nodeList;中。并且对建筑物A的edge进行+1操作buildingEdge[A].edge++;

于是上图经过FindNodeEdge后得到 nodeList中记录了一条 B遮盖A的记录。

2.3 InputDrawQueue()按拓扑排序方法去解这个排序问题

目的就是把度为0的节点拆出来,然后把跟他相关的遮盖节点的度减1。首先从buildingEdge中找到度edge为0的建筑A,把建筑物A加入到输出队列drawQueue中去。并且把建筑物A从buildingEdge中删除。然后在nodeList中去找那些记录的fromNode是A的记录,把他们的toNode对应建筑的edge减1。如此循环找度为0的节点一个个的输出到队列drawQueue中。

2.4 目前我的建筑物里面有投影占了2层格子

我的代码最终把x+1层和x+2层都计算到受影响范围中,这样就彻底把所有建筑物合理按序排放了。缺点就是虽然代码上思路简单了,但是循环的次数变多了

 

3.主要代码实现

外部入口函数DrawQueue,返回一个格子节点渲染队列

queue<CityNodes> DrawQueue::GetDrawQueue(array< array<CityNodes, NODE_NUMBER>, NODE_NUMBER> thisCityNode)
{
	BaseData * basedata = BaseData::GetInstance();
	City * thisCity = basedata->mapCity[basedata->selectedCityKey]->city;
	
	//访问地图上所有节点
	for (int y = 0; y < NODE_NUMBER - 1; y++)
	{
		for (int x = 0; x < NODE_NUMBER - 1; x++)
		{
			//找到一个有内容的节点
			if (thisCityNode[x][y].x != 0 && thisCityNode[x][y].CanUse == true && thisCityNode[x][y].BuildingKey != "")
			{
				//排除掉自己重复计算
				if (buildingEdge.find(thisCityNode[x][y].pBuilding->id) == buildingEdge.end())
				{
					int headx = thisCityNode[x][y].x;
					int heady = thisCityNode[x][y].y;
					
					BUILDING_EDGE building;
					building.cityNode = thisCityNode[x][y];
					buildingEdge[thisCityNode[x][y].pBuilding->id] = building;
				}
			}
		}
	}
	map<int, BUILDING_EDGE>::iterator iterBuildingEdge;
	for (iterBuildingEdge = buildingEdge.begin(); iterBuildingEdge != buildingEdge.end(); iterBuildingEdge++)
	{
		int headx = iterBuildingEdge->second.cityNode.x;
		int heady = iterBuildingEdge->second.cityNode.y;
		FindNodeEdge(thisCityNode, headx, heady);
	}
	
	InputDrawQueue();
	return drawQueue;
}

//所有建筑物的图
void DrawQueue::InsertEdge(CityNodes from, CityNodes to)
{
	NODE_FROM_TO node;
	node.fromNode = from;
	node.toNode = to;
	nodeList.push_back(node);
	buildingEdge[to.pBuilding->id].edge++;
}

//找到会覆盖自己的节点,并建立有像图
void DrawQueue::FindNodeEdge(array< array<CityNodes, NODE_NUMBER>, NODE_NUMBER> thisCityNode, int headx, int heady)
{
	map<int, CityNodes> tempNodeMap;
	//找x方向遮挡物
	for (int x = headx; x < thisCityNode[headx][heady].pBuilding->x_size + headx; x++)
	{
		if (thisCityNode[x][heady + 1].IsUsed)
		{
			//排出掉重复元素
			if (tempNodeMap.find(thisCityNode[x][heady + 1].pBuilding->id) == tempNodeMap.end())
			{
				tempNodeMap[thisCityNode[x][heady + 1].pBuilding->id] = thisCityNode[x][heady + 1];
				InsertEdge(thisCityNode[headx][heady], thisCityNode[x][heady + 1]);
			}
		}
		if (thisCityNode[x][heady + 2].IsUsed)
		{
			//排出掉重复元素
			if (tempNodeMap.find(thisCityNode[x][heady + 2].pBuilding->id) == tempNodeMap.end())
			{
				tempNodeMap[thisCityNode[x][heady + 2].pBuilding->id] = thisCityNode[x][heady + 2];
				InsertEdge(thisCityNode[headx][heady], thisCityNode[x][heady + 2]);
			}
		}
	}
	//找y方向遮挡物
	int findx = headx + thisCityNode[headx][heady].pBuilding->x_size;
	//y轴计算是把右下角建筑物斜对面一个单元格纳入计算范围
	for (int y = heady + 1; y > heady - thisCityNode[headx][heady].pBuilding->y_size; y--)
	{
		if (thisCityNode[findx][y].IsUsed)
		{
			if (tempNodeMap.find(thisCityNode[findx][y].pBuilding->id) == tempNodeMap.end())
			{
				tempNodeMap[thisCityNode[findx][y].pBuilding->id] = thisCityNode[findx][y];
				InsertEdge(thisCityNode[headx][heady], thisCityNode[findx][y]);
			}
		}
		if (thisCityNode[findx + 1][y].IsUsed)
		{
			if (tempNodeMap.find(thisCityNode[findx + 1][y].pBuilding->id) == tempNodeMap.end())
			{
				tempNodeMap[thisCityNode[findx + 1][y].pBuilding->id] = thisCityNode[findx + 1][y];
				InsertEdge(thisCityNode[headx][heady], thisCityNode[findx + 1][y]);
			}
		}
	}
}
//解图输出
void DrawQueue::InputDrawQueue()
{
	//不断的找度为零的节点输出即可
	map<int, BUILDING_EDGE>::iterator iterBuildingEdge;
	iterBuildingEdge = buildingEdge.begin();
	while (buildingEdge.size() != 0)
	{
		while (iterBuildingEdge->second.edge != 0)
		{
			iterBuildingEdge++;
		}
		if (iterBuildingEdge == buildingEdge.end())
			break;
		if (iterBuildingEdge->second.edge == 0)
		{
			drawQueue.push(iterBuildingEdge->second.cityNode);
			//删除与该节点有关的向量from to记录
			for (auto iter = nodeList.begin(); iter != nodeList.end();)
			{
				if (iterBuildingEdge->second.cityNode.pBuilding->id == iter->fromNode.pBuilding->id)
				{
					buildingEdge[iter->toNode.pBuilding->id].edge--;
					iter = nodeList.erase(iter);
				}
				else
				{
					iter++;
				}
			}
			buildingEdge.erase(iterBuildingEdge);
			iterBuildingEdge = buildingEdge.begin();
		}
	}
}

虽然上述代码解决了建筑物的问题,但是如果有小人在里面移动,那就还要考虑更多覆盖问题了。后面我做到这一步的时候会有详细介绍。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值