二维地图中的游戏图块移动
在 2D 方形网格系统中进行移动的最佳方法是什么?我有这个有效的东西,但它看起来错误/丑陋(见下文)。
x x x x x x x
x x x x x x x
x x x O x x x
x x x U x x x
x x x x x x x
x x x x x x x
x x x x x x x
例如,U是我要移动的单位,O是不可通行的物体,例如另一个单位或一座山。如果你可以移动 3 个方块,我希望可移动区域 (M) 看起来像这样。
x x x x x x x
x x M x M x x
x M M O M M x
M M M U M M M
x x M M M M x
x x M M M x x
x x x M x x x
这是我的代码:
public function possibleMoves(range:uint, cords:Array):void {
var X:uint = cords[0];
var Y:uint = cords[1];
if (range > 0) {
try {
theGrid[X + 1][Y].moveable = true;
if (theGrid[X + 1][Y].getOccupied == false) {
possibleMoves(range - 1, [X + 1, Y], flag, mtype);
}
} catch (err:Error) { }
try {
theGrid[X - 1][Y].moveable = true;
if (theGrid[X - 1][Y].getOccupied == false) {
possibleMoves(range - 1, [X - 1, Y], flag, mtype);
}
} catch (err:Error) { }
try {
theGrid[X][Y + 1].moveable = true;
if (theGrid[X][Y + 1].getOccupied == false) {
possibleMoves(range - 1, [X, Y + 1], flag, mtype);
}
} catch (err:Error) { }
try {
theGrid[X][Y - 1].moveable = true;
if (theGrid[X][Y - 1].getOccupied == false) {
possibleMoves(range - 1, [X, Y - 1], flag, mtype);
}
} catch (err:Error) { }
}
What's the best way to do movement in a 2D square grid system? I have this something that works but it seems wrong/ugly (see below).
x x x x x x x
x x x x x x x
x x x O x x x
x x x U x x x
x x x x x x x
x x x x x x x
x x x x x x x
For example, U is the unit I want to move, and O is an impassable object like another unit or a mountain. If U can move 3 tiles, I want the moveable area (M) to look like this.
x x x x x x x
x x M x M x x
x M M O M M x
M M M U M M M
x x M M M M x
x x M M M x x
x x x M x x x
Here's my code:
public function possibleMoves(range:uint, cords:Array):void {
var X:uint = cords[0];
var Y:uint = cords[1];
if (range > 0) {
try {
theGrid[X + 1][Y].moveable = true;
if (theGrid[X + 1][Y].getOccupied == false) {
possibleMoves(range - 1, [X + 1, Y], flag, mtype);
}
} catch (err:Error) { }
try {
theGrid[X - 1][Y].moveable = true;
if (theGrid[X - 1][Y].getOccupied == false) {
possibleMoves(range - 1, [X - 1, Y], flag, mtype);
}
} catch (err:Error) { }
try {
theGrid[X][Y + 1].moveable = true;
if (theGrid[X][Y + 1].getOccupied == false) {
possibleMoves(range - 1, [X, Y + 1], flag, mtype);
}
} catch (err:Error) { }
try {
theGrid[X][Y - 1].moveable = true;
if (theGrid[X][Y - 1].getOccupied == false) {
possibleMoves(range - 1, [X, Y - 1], flag, mtype);
}
} catch (err:Error) { }
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
你的tileset的数据结构似乎与一个做太多事情的“Tile”类紧密耦合; theGrid[X][Y].moveable、theGrid[X][Y].getOccupied...+可能还有一些其他方法。
也许tileset数据结构应该只存储布尔值(可步行?真/假),并有一个单一的方法来判断一个图块是否可步行。在这种情况下,布尔值向量就足够了。测试 4 个(或 8 个对角线)naerby 值非常快,并且可以通过递归循环将测试扩展到新找到的值。
如果您有不同类型的图块(墙壁、物体、角色等),您可以使用矢量。整数>而不是布尔值; 0 是可行走的区域,其他任何区域都是禁止区域。
这允许布尔检查:0 = false,任何其他值 = true。
我在这里做了一个示例 http://wonderfl.net/c/bRV8 ;可能比贴代码更清楚。移动鼠标,您应该会看到一个小指形状,它为您提供了有效的单元格。
,无论起点如何,都会执行递归。有时它会以意想不到的方式溢出。
如果你需要给出特定的移动量,这还不够,你必须设置某种探路者。
编辑:
看来提供的代码可以工作,但包含一个递归终止错误,尝试通过以下行来避免该错误。这仅在某些情况下有效,并且如果您将角色放在地图边缘或给他 5 以外的移动次数,则行为会非常奇怪:
我检查了不同的递归深度,并且该错误很快就变得明显。此示例缺乏网格和复杂的地图设计掩盖了该错误,但下面是一个屏幕截图 - 请注意,如果鼠标位于如图所示的角落,则该字段向上延伸 6 个方格,向左延伸 7 个方格,而它应该只延伸5.
the data structure of your tileset seems strongly coupled to a "Tile" class that does too many things ; theGrid[X][Y].moveable, theGrid[X][Y].getOccupied... + probably some other methods.
maybe the tileset data structure should only store Boolean values (walkable?true/false) and have a single method to tell wether a tile is walkable or not. in this case, a Vector of Boolean values is enough. testing the 4 ( or 8 with diagonals ) naerby values is pretty fast and spreading the test to the newly found values can be done with a recursive loop.
if you have different types of tiles (walls, objects, characters etc.), you could use a Vector.< int > rather than Booleans ; 0 would be a walkable tile and anything else would be forbidden areas.
this allows a Boolean check : as 0 = false and any other value = true.
I've done a sample here http://wonderfl.net/c/bRV8 ; it might be clearer than pasting the code. move the mouse around, you should see a pinky shape the gives you the valid cells.
as such, the recursion is performed regardless of the starting point. it will spill in a sometimes unexpected way.
if you need to give a specific amount of moves this won't be enough, you'll have to set up some kind of pathfinder.
Edit:
It appears that the code provided works, but contains a recursion termination bug that is attempted to be avoided by the following line. This works only in some cases and behaves really weird if you put your character at the edge of the map or give him number of moves other than 5:
I checked with different recursion depth, and the bug quickly becomes apparent. Lack of grid and complex map design of this example obscures the bug, but here's a screenshot below - note that if mouse is positioned in the corner like shown, the field extends 6 squares up and 7 squares left, while it should've only been 5.
您的代码可以工作,但远非优雅。很多瓷砖会被多次计算。您可以通过缓存每个 gridTile 的结果来解决此问题。
查看记忆化技术。
Your code will work, but is far from elegant. A lot of tiles will be calculated multiple times. You could fix this by caching the results for each gridTile.
Have a look at the Memoization technique.
这是 Objective-c 中二维瓦片地图问题的递归避障的正确解决方案。我花了 4.5 个小时将动作脚本翻译为 Objective-C 并进行调试...现在差不多凌晨 3 点了:) 要使用这个,只需创建一个 X × Y 方块的地图,将您的模型放在地图上并调用
生成的数组将给出您的角色通过给定的移动次数可以到达的位置。然后,您可以使用
A* 寻路算法
制作从当前位置到任一突出显示图块的移动动画。我试图在我的名称和描述中变得非常详细,因为如果没有它,很难通过所有这些方法调用来跟踪这些点。
MapOfTiles.m
Here's the correct solution to the recursion to the avoiding obstacles on a 2D tile map problem in objective-c. Took me good 4.5 hours translate action script to objective-c and debug it... almost 3AM now :) To use this, just create a map of X by Y squares, put your model on the map and call
The resulting array will give you locations that your character can reach with the given number of moves. You can then use
A* pathfinding algorithm
to animate movement from the current position to any one of highlighted tiles.I have attempted to be super-verbose in my names and descriptions, as it was quite difficult to trace these points through all these method calls without it.
MapOfTiles.m