gpt4 book ai didi

c++ - 映射分支瓦片路径

转载 作者:搜寻专家 更新时间:2023-10-31 00:23:55 30 4
gpt4 key购买 nike

我正在开发一款游戏(并且已经问了几个关于它的问题),现在我有另一个问题要问你们。

此游戏中的关卡格式设置为 Uint16 的瓦片图(我使用的是 SDL),它们是瓦片数据结构数组的索引。 tilemapData 结构的位之一是 isConductive 位/ bool 值。

该位的用途基本上是创建将各种对象连接在一起形成单个“powerNet”的路径。我在下面有一些关于当前方法的代码(有效,但我会在之后解释为什么我真的很讨厌它)

void findSetPoweredObjects(unsigned long x, unsigned long y, powerNetInfo * powerNet) {
//Look for poweredObjs on this tile and set their powerNet to the given powernet
for (int i = 0; i < level->numChunks[CHUNKTYPE_POWEREDDEF]; i++)
if (level->poweredObjects[i]->position[0] == x && level->poweredObjects[i]->position[1] == y)
level->poweredObjects[i]->powerNet = powerNet, powerNet->objectsInNet++;
}

void recursiveCheckTile(bool * isWalked, powerNetInfo * powerNet, unsigned long x, unsigned long y, tilemapData * levelMap) {
//If out of bounds, return
if (x < 0 || y < 0 || x >= level->mapDimensions[0] || y >= level->mapDimensions[1]) return;
//If tile already walked, return
if (isWalked[x + (y * level->mapDimensions[0])]) return;
//If tile is nonconductive, return
if (!(level->tiles[levelMap->map[x + (y * level->mapDimensions[0])]]->flags & TILETYPE_CONDUCTIVE)) return;

//Valid tile to check, see if there's a poweredobj on the tile (link it to the net if it is) and check the adjacent tiles.
isWalked[x + (y * level->mapDimensions[0])] = true;

findSetPoweredObjects(x,y,powerNet);

recursiveCheckTile(isWalked, powerNet, x - 1, y, levelMap);
recursiveCheckTile(isWalked, powerNet, x + 1, y, levelMap);
recursiveCheckTile(isWalked, powerNet, x, y - 1, levelMap);
recursiveCheckTile(isWalked, powerNet, x, y + 1, levelMap);
}

bool buildPowerNets(void) {
//Build the powernets used by the powered objects
//TODO: Rewrite buildPowerNets() & recursiveCheckTile() to avoid stack overflows and make it easier to backtrace powernets in-game
bool * isWalked;
isWalked = new bool[(level->mapDimensions[0] * level->mapDimensions[1])];
unsigned long x, y;
tilemapData * levelMap = level->layers[level->activeMap];
for (y = 0; y < level->mapDimensions[1]; y++) {
for (x = 0; x < level->mapDimensions[0]; x++) {
if (isWalked[x + (y * level->mapDimensions[0])]) continue;
isWalked[x + (y * level->mapDimensions[0])] = true;
if (level->tiles[levelMap->map[x + (y * level->mapDimensions[0])]]->flags & TILETYPE_CONDUCTIVE) {
//it's conductive, find out what it's connected to.

//But first, create a new powernet
powerNetInfo * powerNet = new powerNetInfo;
powerNet->objectsInNet = 0;
powerNet->producerId = -1;
powerNet->supplyType = POWER_OFF;
powerNet->prevSupplyType = POWER_OFF;
powerNet->powerFor = 0;

//Find adjacent tiles to this one, add them to it's powernet, and then mark them walked. Then repeat until the net is done.
recursiveCheckTile(isWalked, powerNet, x, y, levelMap);
}
}
}
delete isWalked;
for (int i = 0; i < level->numChunks[CHUNKTYPE_POWEREDDEF]; i++)
if (level->poweredObjects[i]->powerNet == NULL) return false;
return true;
}

请注意,返回 false 意味着函数失败(在这种情况下,它没有正确链接所有对象)。

我担心的是,由于堆栈溢出,在更复杂的 map 上行走导电砖的功能会完全失败。关于如何通过这些功能降低这种风险有哪些想法?如果需要,我可以提供有关所用结构的更多信息。

我考虑过修改代码,使 recursiveCheckTile 仅在到达交界处时进行递归调用,并且只是交互地遵循它所在的导电路径,但这似乎仍然只是一个部分解决方案,因为我无法提前知道路径可能有多扭曲或分支。

如果它有所不同,速度在这里完全不重要,因为这个函数只在 map 使用前处理时运行一次,所以多花点时间也没什么坏处。

最佳答案

洪水填充

看起来你基本上是在做 flood fill你的网格。您可以通过使用需要检查的队列或一堆方 block 来消除递归。查看"alternate implementations" section伪代码的维基百科文章。

自己维护队列/堆栈的优点是,当您访问它们时,您将从列表中删除方 block ,而在递归解决方案中,即使在您访问它们之后,方 block 仍保留在堆栈中。

这是维基百科文章中适合您的问题的“简单”替代实现:

1. Set Q to the empty queue.
2. Add node to the end of Q.
3. While Q is not empty:
4. Set n equal to the first element of Q
5. Remove first element from Q
6. If n has already been visited:
7. Go back to step 3.
8. Mark n as visited.
9. Add the node to the west to the end of Q.
10. Add the node to the east to the end of Q.
11. Add the node to the north to the end of Q.
12. Add the node to the south to the end of Q.
13. Return.

请注意,您可以为此使用堆栈或队列,两者都可以。这里有一些很酷且令人着迷的动画,从视觉上展示了差异:

基于队列的泛洪填充

Flood fill with queue

基于堆栈的洪水填充

Flood fill with stack

连通分量标记

您还可以找到 connected component labeling如果您最终在同一个网格上拥有多个电网,这个页面很有趣。它基本上可以帮助您确定是否有多个断开的电源网络,当您这样做时,它会告诉您每个方格属于哪一个。

Connected-component labeling example

关于c++ - 映射分支瓦片路径,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1175600/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com