【发布时间】:2017-10-24 12:30:43
【问题描述】:
我是游戏开发的初学者,一直在努力在一组图块和一个玩家矩形之间完成碰撞。该游戏具有跳跃和重力。首先碰撞有效,但非常笨重。有时,当玩家最终到达瓷砖顶部并稍微靠近边缘时,它会立即传送到右侧或左侧(取决于哪个边缘/角落)并掉落。与瓷砖底部碰撞时也会发生这种情况;玩家会立即传送到一边并走得更远。据我了解,瓷砖碰撞检测器会混淆与一侧或另一侧的碰撞,因为当玩家撞到瓷砖的边缘时,检测器会读取它,就好像它与两者发生碰撞一样,并决定将玩家放置在其他位置基于最高坐标速度(又名 speedX 和 speedY)。我通过将 speedY = 0 设置为每次碰到瓷砖的顶部来解决这个问题,这解决了这个问题,但又出现了另一个问题。现在,如果玩家在瓷砖顶部,然后跌落并很快向后扫射,它不会与瓷砖的侧面发生碰撞,而是很快又回到顶部。
我只需要一些关于如何解决此问题的提示,因为我尝试的一切都会导致另一个问题。我听说这是开发基于 2D 瓷砖的游戏中的常见错误。
这是一个运行代码的 jsfiddle:https://jsfiddle.net/8121u356/
这是我的整个代码的显示:
function startGame() {
gameArea.start();
actor = new player(32, 32, "green", 32, 32);
}
var mapArray = [
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,0,0,0],
[0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
];
var levelRows = 20;
var levelCols = 20;
var gameArea = {
canvas : document.getElementById('canvas'),
start : function() {
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
requestAnimationFrame(updateGameArea);
window.addEventListener('keydown', function (e) {
gameArea.keys = (gameArea.keys || []);
gameArea.keys[e.keyCode] = true;
});
window.addEventListener('keyup', function (e) {
gameArea.keys = (gameArea.keys || []);
gameArea.keys[e.keyCode] = false;
})
},
clear : function(){
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
},
render : function() {
context = this.canvas.getContext("2d");
var tileSize = 32;
for(i=0;i<levelRows;i++){
for(j=0;j<levelCols;j++){
if(mapArray[i][j]==1){
context.fillStyle = "gray";
context.fillRect(j*tileSize,i*tileSize,tileSize,tileSize);
}
}
}
}
};
function TileCollisionManager(object) {
let tileSize = 32;
let baseCol = Math.floor(object.x / tileSize);
let baseRow = Math.floor(object.y / tileSize);
let colOverlap = object.x % tileSize;
let rowOverlap = Math.floor(object.y % tileSize);
if (object.speedX > 0) {
if ((mapArray[baseRow][baseCol + 1] && !mapArray[baseRow][baseCol]) ||
(mapArray[baseRow + 1][baseCol + 1] && !mapArray[baseRow + 1][baseCol] && rowOverlap)) {
object.x = baseCol * tileSize;
}
}
if (object.speedX < 0) {
if ((!mapArray[baseRow][baseCol + 1] && mapArray[baseRow][baseCol]) ||
(!mapArray[baseRow + 1][baseCol + 1] && mapArray[baseRow + 1][baseCol] && rowOverlap)) {
object.x = (baseCol + 1) * tileSize;
}
}
if (object.speedY > 0) {
if ((mapArray[baseRow + 1][baseCol] && !mapArray[baseRow][baseCol]) ||
(mapArray[baseRow + 1][baseCol + 1] && !mapArray[baseRow][baseCol + 1] && colOverlap)) {
object.y = ((baseRow) * tileSize);
object.jumping = false;
object.speedY = 0;
}
}
if (object.speedY < 0) {
if ((!mapArray[baseRow + 1][baseCol] && mapArray[baseRow][baseCol]) ||
(!mapArray[baseRow + 1][baseCol + 1] && mapArray[baseRow][baseCol + 1] && colOverlap)) {
object.y = (baseRow + 1) * tileSize;
object.speedY = 5;
}
}
}
function updateGameArea() {
gameArea.clear();
gameArea.render();
actor.update();
actor.newPos();
actor.speedX = 0;
actor.speedY += actor.gravity;
if (gameArea.keys && gameArea.keys[39]) {
actor.speedX = 4;
}
if (gameArea.keys && gameArea.keys[37]) {
actor.speedX = -4;
}
if (gameArea.keys && gameArea.keys[32]) {
if (!actor.jumping) {
actor.jumping = true;
actor.speedY = -actor.speed * 3;
}
}
TileCollisionManager(actor);
requestAnimationFrame(updateGameArea);
}
function player (width, height, color, x, y) {
this.width = width;
this.height = height;
this.x = x;
this.y = y;
this.speedX=0;
this.speedY=0;
this.gravity=0.3;
this.speed=3;
this.jumping=false;
this.color = color;
this.update = function () {
ctx = gameArea.context;
ctx.fillStyle = this.color;
ctx.fillRect(
this.x,
this.y,
this.width, this.height);
};
this.newPos = function () {
this.x += this.speedX;
this.y += this.speedY;
};
【问题讨论】:
-
您的代码有一个问题,即当它撞到底部时,您没有将 speedY 设置为零“与瓷砖底部碰撞”,这反过来会在运动下降时触发向上碰撞检测或者根本不动。导致奇怪的行为。
-
另一个潜在的错误是你让用户在跌倒时跳一次。这可能会导致在工作时感觉碰撞内容中存在错误。
标签: javascript html canvas collision-detection tiles