【发布时间】:2015-09-15 21:45:19
【问题描述】:
我正在开发一个 HTML5 画布游戏,其中地图是随机生成的 10 像素 x 10 像素的图块,玩家可以在这些图块上进行挖掘和构建。瓦片存储在对象数组中,一张小地图包含大约 23000 个瓦片。我的碰撞检测功能在每次运行时检查所有非空气瓷砖的玩家位置(使用requestAnimationFrame()),它运行良好,但我觉得它是 CPU 密集型的。碰撞函数如下(代码来源于在线教程):
function colCheck(shapeA, shapeB) {
var vX = (shapeA.x + (shapeA.width / 2)) - (shapeB.x + (shapeB.width / 2)),
vY = (shapeA.y + (shapeA.height / 2)) - (shapeB.y + (shapeB.height / 2)),
hWidths = (shapeA.width / 2) + (shapeB.width / 2),
hHeights = (shapeA.height / 2) + (shapeB.height / 2),
colDir = null;
// if the x and y vector are less than the half width or half height, they we must be inside the object, causing a collision
if (Math.abs(vX) < hWidths && Math.abs(vY) < hHeights) {
// figures out on which side we are colliding (top, bottom, left, or right)
var oX = hWidths - Math.abs(vX),
oY = hHeights - Math.abs(vY);
if (oX >= oY) {
if (vY > 0) {
colDir = "t";
shapeA.y += oY;
} else {
colDir = "b";
shapeA.y -= oY;
}
} else {
if (vX > 0) {
colDir = "l";
shapeA.x += oX;
} else {
colDir = "r";
shapeA.x -= oX;
}
}
}
return colDir;
};
然后在我的更新函数中,我以播放器和图块作为参数运行此函数:
for (var i = 0; i < tiles.length; i++) {
//the tiles tag attribute determines rendering colour and how the player can interact with it ie. dirt, rock, etc.
//anything except "none" is solid and therefore needs collision
if (tiles[i].tag !== "none") {
dir = colCheck(player, tiles[i]);
if (dir === "l"){
player.velX = 0;
player.jumping = false;
} else if (dir === "r") {
player.velX = 0;
player.jumping = false;
} else if (dir === "b") {
player.grounded = true;
player.jumping = false;
} else if (dir === "t") {
player.velY *= -0.3;
}
}
};
所以我想知道的是,如果我只使用Math.abs(tiles[i].x - player.x) < 100 和y 之类的条件检查距玩家一定距离内的瓷砖,这是否会使代码更高效,因为它将检查碰撞针对较少的图块,或者检查额外参数的效率是否较低?
如果不进行测试就很难说,我该如何确定我的代码运行情况如何?
【问题讨论】:
-
假设您有一个数组,其中的图块按 x 排序。您的角色宽度为 50,位置为 170。这意味着您只想检查 170 到 220 之间的图块。这可以通过 O(2 log2 n) 操作获得,这意味着对于 10000 个图块,您可以获得索引在 2*14 次操作中 x 位置在 170 和 220 之间的图块 = 28。因此,您只检查可能相交的图块。 y 也可以这样做
-
您可以做的一件事实际上类似于流行的游戏Minecraft。这基本上是有一组瓷砖属于整个“块”。然后你可以得到每个块的距离,并从中确定是否需要对里面的项目进行碰撞检测。因此,远处的物品不会有碰撞检测,而附近的物品可以。但这取决于瓷砖系统的设置方式。当然距离计算有开销,但是(取决于它的设置方式)会节省碰撞检测性能。
-
@juvian 通过只检查与附近瓷砖的碰撞,就像你说的那样检查碰撞所花费的时间减少了 40-60%,并在较大的地图上显着提高了性能。
-
@spencer 尽管性能有所提高,但使用约 180000 个图块仍然很慢,所以我可能会尝试采纳您的建议并将地图分成三份(表面、中部和深层)以获得更大的地图,然后检查图块在球员进入的三分之一内,我一定会调查的!
-
@TuckerFlynn 不确定您如何检查附近的瓷砖,但如果您使用答案的方法,您仍在迭代 180000 瓷砖并多次执行 math.abs,这可能很慢。使用我的方法,您只会遍历可能区域的图块,这取决于您的图块大小和玩家大小,但应该少得多。需要更多细节来举例说明
标签: javascript html5-canvas collision-detection tile