当前位置: 代码迷 >> JavaScript >> 在基于2D Tile的游戏中画布碰撞检测不完全
  详细解决方案

在基于2D Tile的游戏中画布碰撞检测不完全

热度:55   发布时间:2023-06-03 18:11:23.0

我用Javascript和Canvas做一个小游戏。 我有一个碰撞检测,但是效果不是很好。 我不能穿过墙壁。 到目前为止还算不错,但是它只能在左侧和顶部工作而不会重叠。

我的地图是基于0和1的数组。1是可步行的,0必须阻塞

我的播放器是32x32,我的磁贴也是。

PosX是xy可能来自玩家的坐标PosY是y可能来自玩家的坐标

这是我的检测代码:

var tileWidth = 32;                                                                                                                     // Fliesen breite festgelegt
var tileHeight = 32;                                                                                                                    // Fliesen h?he festgelegt

    var solidTiles = [0];                                                                                                               // var solidTiles beinhaltet die 0 aus dem array, sagt das die nicht durchdringbar sein sollen (Hol mir quasi die 0 ausem array raus

function isSolidTile(x, y) {                                                                                                            // Funktion zu festlegung das 0 Flie?en nicht durchgehbar sind,  x Pixel und y Pixel der fliese
    var tileX = Math.floor(x / tileWidth);                                                                                              // Flie?e in X   --> x koordinate / durch die halbe breite, damit wir den mittelpunkt der fliese als festen punkt feststellen
    var tileY = Math.floor(y / tileHeight);                                                                                             // Flie?e in Y   --> y koordinate / durch die halbe breite, damit wir den mittelpunkt der fliese als festen punkt feststellen
    var tile = mapKollision[ tileY ][tileX] ;                                                                                           // WICHTIG!: Bei Listen ist auch die Zeile und Spalte einzuhalten. Bei der Abfrage einer Kollision zu erst Y dann X
    if ( tile == 0 )    {                                                                                                               //
        return true;                                                                                                                    //
    } else {return false}                                                                                                               //
}


    var altPosX = PosX;                                                                                                                 // neue variable für die alte helden position 
    var altPosY = PosY; 

if ( isSolidTile( PosX, PosY) ){                                                                                                // if wenn isSolidTile getroffen wird
            PosX = altPosX;                                                                                                             // soll er DIESE PosX in die alte Pos X umwandeln
            PosY = altPosY;                                                                                                             // soll er DIESE PosY in die alte Pos Y umwandeln
    }   

我知道我必须说些类似的话

 if( PosX + 32 ) PosX = altPosX -32;

但是,当我使用它时,我的播放器从“阻隔砖块”的右侧反弹回来,而当我向左走时,我的播放器穿过了其播放器剩下的所有阻隔砖块。

但是我想要的是,当我的玩家用他的32x32的右侧触摸阻塞的Tile的左侧时,他必须停下来。

而且我不知道为什么它不起作用。

如果您需要更多代码,请告诉我。

谢谢 :)

根据我的观察,我认为您的碰撞检测仅基于玩家精灵的单个点-最有可能是它的中心点。 为了进行更精确的碰撞检测,我们需要考虑该对象周围的拐角点及其移动方向。 另外, 实际将其移动到该位置之前,我们需要检查是否会与诸如墙壁的实体碰撞。 这样,我们可以将其并排放置在该对象上。

考虑以下示例:

我们的播放器精灵是红色方块,它以每帧4像素的速度移动。 可以看到精灵和蓝色的墙壁相隔仅2个像素! 如果我们向右移动4个像素,则右下角会碰到墙。

为了解决这个问题,如果我们想向右移动,我们需要检查精灵的右上角和右下角是否有可能发生碰撞。

如果我们检测到碰撞-再次在实际在屏幕上移动东西之前-我们将红色英雄放到块旁边。

这是一个复杂的例子。 通过单击鼠标使其聚焦,然后使用光标键移动。

 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);