Javascript 基于画布平铺的游戏有一个困难的碰撞错误
我是一个游戏开发的初学者,一直在努力在一组瓷砖和一个玩家矩形之间完成碰撞。这个游戏的特点是跳跃和重力。首先,碰撞可以工作,但非常笨重。有时,当玩家最终到达一块瓷砖的顶部并稍微靠近边缘时,它会立即传送到右侧或左侧(取决于边缘/角落),然后掉落。当与瓷砖底部碰撞时也会发生这种情况;玩家将立即传送到侧面,并进一步向上移动。据我所知,磁贴碰撞检测器会将碰撞与一侧或另一侧混淆,因为当玩家撞击磁贴边缘时,检测器会将其视为与两侧碰撞,并根据最高坐标速度(也称为speedX和speedY)决定将玩家放置在其他位置。我通过设置speedY=0来解决这个问题,每次它碰到一块瓷砖的顶部,这就解决了这个问题,但是又出现了另一个问题。现在,如果玩家在一块瓷砖的上面,然后摔倒,很快又向后扫射,它不会与瓷砖的侧面碰撞,但会很快再次回到瓷砖的上面 我只是需要一些关于如何解决这个问题的建议,因为我尝试的每件事都会导致另一个问题。我听说这是开发基于2D瓷砖的游戏时的一个常见错误 下面是一个JSFIDLE,代码正在运行: 下面是我全部代码的显示:Javascript 基于画布平铺的游戏有一个困难的碰撞错误,javascript,css,html,canvas,tiles,Javascript,Css,Html,Canvas,Tiles,我是一个游戏开发的初学者,一直在努力在一组瓷砖和一个玩家矩形之间完成碰撞。这个游戏的特点是跳跃和重力。首先,碰撞可以工作,但非常笨重。有时,当玩家最终到达一块瓷砖的顶部并稍微靠近边缘时,它会立即传送到右侧或左侧(取决于边缘/角落),然后掉落。当与瓷砖底部碰撞时也会发生这种情况;玩家将立即传送到侧面,并进一步向上移动。据我所知,磁贴碰撞检测器会将碰撞与一侧或另一侧混淆,因为当玩家撞击磁贴边缘时,检测器会将其视为与两侧碰撞,并根据最高坐标速度(也称为speedX和speedY)决定将玩家放置在其他位
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;
};
}
函数startGame(){//在所有资源都加载到浏览器后启动
gameArea.start();
演员=新玩家(32,32,“绿色”,32,32);
}
变量映射数组=[
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,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]
];
函数TileCollisionManager(){
让tileSize=32;
让baseCol=Math.floor(actor.x/tileSize);
让baseRow=Math.floor(actor.y/tileSize);
让colOverlap=actor.x%tileSize;
让rowOverlap=actor.y%tileSize;
如果(actor.speedX>0){//水平碰撞检测
if((mapArray[baseRow][baseCol+1]&&!mapArray[baseRow][baseCol])||
(mapArray[baseRow+1][baseCol+1]&&!mapArray[baseRow+1][baseCol]&&rowOverlap)){
actor.x=baseCol*tileSize;
}
}
如果(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;
}
}
如果(actor.speedY>0){//垂直碰撞检测
如果((mapArray[baseRow+1][baseCol]&&!mapArray[baseRow][baseCol])||//与平铺顶部碰撞
(mapArray[baseRow+1][baseCol+1]&&!mapArray[baseRow][baseCol+1]&&colOverlap)){
actor.y=((基线)*tileSize);
actor.jumping=false;
actor.speedY=0;
}
}
如果(actor.speedY<0){//与平铺底部碰撞
if((!mapArray[baseRow+1][baseCol]&&mapArray[baseRow][baseCol])||
(!mapArray[baseRow+1][baseCol+1]&&mapArray[baseRow][baseCol+1]&&colOverlap)){
actor.y=(基线+1)*tileSize;
}
}
}
var levelRows=20;
var levelCols=20;
var游戏区={
canvas:document.getElementById('canvas'),
开始:函数(){
this.context=this.canvas.getContext(“2d”);
document.body.insertBefore(this.canvas,document.body.childNodes[0]);
requestAnimationFrame(updateGameArea);
window.addEventListener('keydown',函数(e){
gameArea.keys=(gameArea.keys | | |[]);
gameArea.keys[e.keyCode]=true;
});
window.addEventListener('keyup',函数(e){
gameArea.keys=(gameArea.keys | | |[]);
gameArea.keys[e.keyCode]=false;
})
},
清除:函数(){
this.context.clearRect(0,0,this.canvas.width,this.canvas.height);
},
render:function(){
context=this.canvas.getContext(“2d”);
var tileSize=32;
对于(i=0;我建议尝试Unity3d游戏引擎。与用JS构建游戏相比,学习如何使用它所需的时间更少。我知道unity更适合制作。但是,我对这个游戏的目的是从从头开始编程中学习。也许我可以阅读unity代码的工作原理,并从中汲取一些想法。我建议尝试Unity3d游戏引擎。学习如何使用它所需的时间比在JS中构建游戏所需的时间要少。我知道unity更适合制作。但是,我对这个游戏的目的是从从头开始编程中学习。也许我可以阅读unity代码的工作原理,并从中汲取一些想法。