我是游戏开发的初学者,并且一直在努力在一系列瓷砖和一个播放器矩形之间完成碰撞。这个游戏具有跳跃和重力。首先碰撞工作,但非常笨重。有时候当玩家最终在一个瓷砖的顶部和一个小的边缘时,它会立即传送到右侧或左侧(取决于什么边缘/角落)和它的下降。当与瓷砖底部碰撞时也会发生这种情况;玩家将立即传送到侧面并进一步向上移动。根据我的理解,瓦片碰撞检测器将碰撞与一侧或另一侧混淆,因为当玩家碰到瓦片的边缘时,检测器将其读取为好像它与两者碰撞并决定将玩家置于其他基础上的最高坐标速度(又名speedX和speedY)。我通过设置speedY = 0每次碰到瓷砖的顶部来解决这个问题,这解决了问题,但另一个问题就出来了。现在,如果玩家位于牌块的顶部,然后跌落并且很快就会向后移动,那么它不会与牌块碰撞,但它会很快再次回到它的顶部。
我只需要一些关于如何解决这个问题的提示,因为我尝试的所有内容都会导致另一个问题。我听说这是开发基于2D磁贴的游戏中常见的错误。
这是一个包含操作代码的jsfiddle:https://jsfiddle.net/8121u356/
这是我整个代码的显示:
function startGame() { //Starts after all assets have finished loading into the browser
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]
];
function TileCollisionManager() {
let tileSize = 32;
let baseCol = Math.floor(actor.x / tileSize);
let baseRow = Math.floor(actor.y / tileSize);
let colOverlap = actor.x % tileSize;
let rowOverlap = actor.y % tileSize;
if (actor.speedX > 0) { //horizontal collision detection
if ((mapArray[baseRow][baseCol + 1] && !mapArray[baseRow][baseCol]) ||
(mapArray[baseRow + 1][baseCol + 1] && !mapArray[baseRow + 1][baseCol] && rowOverlap)) {
actor.x = baseCol * tileSize;
}
}
if (actor.speedX < 0) {
if ((!mapArray[baseRow][baseCol + 1] && mapArray[baseRow][baseCol]) ||
(!mapArray[baseRow + 1][baseCol + 1] && mapArray[baseRow + 1][baseCol] && rowOverlap)) {
actor.x = (baseCol + 1) * tileSize;
}
}
if (actor.speedY > 0) { //vertical collision detection
if ((mapArray[baseRow + 1][baseCol] && !mapArray[baseRow][baseCol]) || //Collision with the top of a tile
(mapArray[baseRow + 1][baseCol + 1] && !mapArray[baseRow][baseCol + 1] && colOverlap)) {
actor.y = ((baseRow) * tileSize);
actor.jumping = false;
actor.speedY = 0;
}
}
if (actor.speedY < 0) { //Collision with the bottom of a tile
if ((!mapArray[baseRow + 1][baseCol] && mapArray[baseRow][baseCol]) ||
(!mapArray[baseRow + 1][baseCol + 1] && mapArray[baseRow][baseCol + 1] && colOverlap)) {
actor.y = (baseRow + 1) * tileSize;
}
}
}
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 updateGameArea() { //loop function
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]) { //jump
if (!actor.jumping) {
actor.jumping = true;
actor.speedY = -actor.speed * 3;
}
}
TileCollisionManager();
if (!TileCollisionManager) {
actor.speedY += actor.gravity;
}
requestAnimationFrame(updateGameArea);
}
function player (width, height, color, x, y) { //player component
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;
};
}