Из того, что я вижу, я предполагаю, что ваше обнаружение столкновений основано только на одной точке спрайта игрока - скорее всего, это центральная точка.Для более точного обнаружения столкновений нам необходимо учесть угловые точки, окружающие этот объект, и направление, в котором он движется.Кроме того, нам нужно проверить, не столкнемся ли мы с твердым объектом, таким как стена , до , мы фактически переместим его в эту позицию.Таким образом, мы можем поместить его рядом с этим объектом.
Рассмотрим пример:
![collisionA](https://i.stack.imgur.com/nSQA6.png)
Наш спрайт игрокакрасный квадрат и он движется со скоростью 4 пикселя на кадр.А вы можете видеть спрайт и синюю стену на расстоянии всего 2 пикселя!Если мы переместимся вправо на 4 пикселя, нижний правый удар по стене.![CollisionB](https://i.stack.imgur.com/JIv68.png)
Чтобы обойти эту проблему, нам нужно проверить верхний правый и нижний правый углы спрайта на возможное столкновение, если мы хотим двигаться вправо.
Если мы обнаружим столкновение - опять же, прежде чем мы на самом деле что-то передвинем на экран - вместо этого мы поместим красного героя рядом с блоком.
![collisionC](https://i.stack.imgur.com/Q4RRn.png)
Вот сложный пример.Сфокусируйте его щелчком мыши и используйте клавиши курсора для перемещения.
var whichKey = 0;
var tileWidth = 32;
var tileHeight = 32;
var player = {
tileX: 2,
tileY: 2,
xPos: 0,
yPos: 0,
speed: 3,
width: 24,
height: 24,
topLeft: 0,
topRight: 0,
bottomLeft: 0,
bottomRight: 0
};
player.xPos = player.tileX * tileWidth + tileWidth / 2 - player.width / 2;
player.yPos = player.tileY * tileHeight + tileHeight / 2 - player.height / 2;
var map = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 1, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 1, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
];
var canvas = document.createElement("canvas");
canvas.width = 400;
canvas.height = 300;
var context = canvas.getContext("2d");
document.body.appendChild(canvas);
function updateMap() {
context.clearRect(0, 0, canvas.width, canvas.height);
context.fillStyle = "black";
for (var a = 0; a < map.length; a++) {
for (var b = 0; b < map[0].length; b++) {
if (map[a][b] == 1) {
context.fillRect(b * tileWidth, a * tileHeight, tileWidth, tileHeight);
}
}
}
context.fillStyle = "red";
context.fillRect(player.xPos, player.yPos, player.width, player.height);
player.tileX = Math.floor(player.xPos / tileWidth);
player.tileY = Math.floor(player.yPos / tileHeight);
}
function getCorners(futureX, futureY) {
var bottom = Math.floor((futureY + player.height - 1) / tileHeight);
var top = Math.floor((futureY) / tileHeight);
var left = Math.floor((futureX) / tileWidth);
var right = Math.floor((futureX + player.width - 1) / tileWidth);
player.topLeft = map[top][left];
player.topRight = map[top][right];
player.bottomLeft = map[bottom][left];
player.bottomRight = map[bottom][right];
}
function move(directionX, directionY) {
getCorners(player.xPos + player.speed * directionX, player.yPos);
if (directionX == -1) {
if (player.topLeft == 0 && player.bottomLeft == 0) {
player.xPos += player.speed * directionX;
} else {
player.xPos = player.tileX * tileWidth;
}
}
if (directionX == 1) {
if (player.topRight == 0 && player.bottomRight == 0) {
player.xPos += player.speed * directionX;
} else {
player.xPos = (player.tileX + 1) * tileWidth - player.width;
}
}
getCorners(player.xPos, player.yPos + player.speed * directionY);
if (directionY == -1) {
if (player.topLeft == 0 && player.topRight == 0) {
player.yPos += player.speed * directionY;
} else {
player.yPos = player.tileY * tileHeight;
}
}
if (directionY == 1) {
if (player.bottomLeft == 0 && player.bottomRight == 0) {
player.yPos += player.speed * directionY;
} else {
player.yPos = (player.tileY + 1) * tileHeight - player.height;
}
}
}
window.addEventListener('keydown', function(e) {
whichKey = e.keyCode;
});
window.addEventListener('keyup', function(e) {
whichKey = 0;
});
function loop() {
if (whichKey == 37) {
move(-1, 0);
}
if (whichKey == 39) {
move(1, 0);
}
if (whichKey == 38) {
move(0, -1);
}
if (whichKey == 40) {
move(0, 1);
}
updateMap();
}
var interval = setInterval(loop, 20);