Я работаю над HTML5-холстом, где карта случайным образом генерируется 10px на 10px плитки, которые игрок может затем выкопать и использовать. Плитки хранятся в массиве объектов, а небольшая карта содержит около 23000 плиток. Моя функция обнаружения столкновений проверяет позицию игроков против всех неэфирных плит, которые выполняются каждый раз (с использованием requestAnimationFrame()
), и она отлично работает, но я чувствую, что это интенсивность процессора. Функция коллизий следующим образом (код пришел из онлайн учебника):Выполнение обнаружения столкновений более эффективно
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 плиток вы можете получить индексы из плиток, которые имеют положение x между 170 и 220 в 2 * 14 операций = 28. Таким образом, вы только проверяете плитки, которые можно пересечь. То же можно сделать и в отношении y – juvian
Одна вещь, которую вы можете сделать, на самом деле похожа на популярную игру * Minecraft *. В принципе, группа плиток принадлежит к целому * «куску» *. Затем вы можете получить расстояние для каждого куска, и от этого определите, нужно ли вам обнаруживать столкновение предметов внутри. Таким образом, предметы далеко не будут иметь обнаружение столкновения и близкие. Но это зависит от того, как настроена система плитки. Конечно, в расчете расстояния есть накладные расходы, но (в зависимости от того, как он настроен) будет сохраняться эффективность обнаружения столкновений. –
@juvian, проверив столкновение только с близлежащими плитами, как вы сказали, количество времени, затрачиваемого на столкновение, снизилось на 40-60% и заметно повысило производительность на больших картах. –