2D平铺地图碰撞检测 - 玩家自动向下移动

时间:2017-09-27 01:41:08

标签: javascript html collision-detection

我有一个简单的2d瓷砖地图游戏,但我试图让碰撞检测工作。当玩家碰到地板或天花板时看起来很好但是当玩家碰到墙壁时,它们会非常快地缩小,我不知道为什么。这是代码的jsfiddle - https://jsfiddle.net/o6dn1z6u/3/

我已经做到这一点,以便游戏检查玩家所在的每个牌(最多4个)。如果jsfiddle太乱了,这是代码

声明平铺贴图。 0是透明的,其他一切都是墙/地板等:

    var levelOne = {
    background: 'lightblue',
    collisions: [
        [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,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,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,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,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,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,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,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,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,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,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,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,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,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,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,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,2,2,2,1],
        [1,2,2,2,2,2,2,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,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,2,2,2,2,2,2,2,1],
        [1,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1],
    ],
    player: {spawnX: 1, spawnY: 18}
}

标准游戏变量:

    var canvas = document.getElementById('game-canvas');
var context = canvas.getContext('2d');

var tile = 40;
var FPS = 30;
var currentLevel = levelOne;

var playerLeft = false;
var playerRight = false;
var playerUp = false;
var playerDown = false;
var speed = 6;
var xSpeed = 0;
var ySpeed = 0;

var playerX = currentLevel.player.spawnX * tile; 
var playerY = currentLevel.player.spawnY * tile; 

function draw()
{
    updateMap(currentLevel);
    updatePlayer(currentLevel.player);
}

setInterval(draw, 1000/ FPS);

更新地图只是将图块绘制到画布上,所以我会跳过它。当更新玩家时,它会获得玩家想要做的移动,如果新移动会与墙碰撞,它会将它们放在墙旁边,所以如果他们的玩家位于X:2并且他们向下移动5个空格,那么将它们定位在x:0而不是将它们放在x:2

    function updatePlayer (player)
{
    var newX = playerX;
    var newY = playerY; 

    if (playerLeft)
    {
        newX -= speed;
    }

    if (playerRight)
    {
        newX += speed;
    }

    if (playerUp)
    {
        newY -= speed;
    }

    if (playerDown)
    {
        newY += speed;
    }
    if (!verticleCollision(newX, newY))
    {
        playerY = newY;
    }
    else
    {
        newY = playerY;
    }

    if (!horizontalCollision(newX, newY))
    {
        playerX = newX;
    }

    context.fillStyle = 'blue';
    context.fillRect(playerX, playerY, tile, tile);
}

以下是碰撞功能。我想为水平和垂直制作2,这样你就可以有效地在地板或墙壁上滑动。在小提琴上,我在玩家所在的4个方框中着色,所以我可以看到碰撞。

    function verticleCollision(x, y)
{
    var topLeftX = Math.floor(x/tile);
    var topLeftY = Math.floor(y/tile);

    var bottomLeftX = Math.floor(x/tile)
    var bottomLeftY = Math.ceil(y/tile);

    var topRightX = Math.ceil(x/tile);
    var topRightY = Math.floor(y/tile);

    var bottomRightX = Math.ceil(x/tile);
    var bottomRightY = Math.ceil(y/tile);

    if ((currentLevel.collisions[topLeftY][topLeftX] != 0) || (currentLevel.collisions[topRightY][topRightX] != 0))
    {
        playerY = topLeftY * tile + tile;
        return true;
    }
    else if ((currentLevel.collisions[bottomLeftY][bottomLeftX] != 0) || (currentLevel.collisions[bottomRightY][bottomRightX] != 0))
    {
        playerY = bottomLeftY * tile - tile;
        return true;
    }
    else
    {
        return false;
    }
}

function horizontalCollision(x, y)
{
    var topLeftX = Math.floor(x/tile);
    var topLeftY = Math.floor(y/tile);

    var bottomLeftX = Math.floor(x/tile)
    var bottomLeftY = Math.ceil(y/tile);

    var topRightX = Math.ceil(x/tile);
    var topRightY = Math.floor(y/tile);

    var bottomRightX = Math.ceil(x/tile);
    var bottomRightY = Math.ceil(y/tile);

    if ((currentLevel.collisions[topLeftY][topLeftX] != 0) || (currentLevel.collisions[bottomLeftY][bottomLeftX] != 0))
    {
        playerX = topLeftX * tile + tile;
        return true;
    }
    else if ((currentLevel.collisions[bottomRightY][bottomRightX] != 0) || (currentLevel.collisions[bottomLeftY][bottomLeftX] != 0))
    {
        playerX = bottomRightX * tile - tile;
        return true;
    }
    else
    {
        return false;
    }
}

有很多代码,这就是为什么我包含jsfiddle,但任何帮助表示赞赏:)

1 个答案:

答案 0 :(得分:0)

我使用了JSFiddle并发现了一些有趣的东西。它不仅使玩家失望,也使他们失望。这取决于玩家是靠近顶部还是底部。然后,我通过更改代码的一个字符来解决向下传送的问题。

function verticleCollision(x, y)
{
    var topLeftX = Math.floor(x/tile);
    var topLeftY = Math.floor(y/tile);

    var bottomLeftX = Math.floor(x/tile)
    var bottomLeftY = Math.ceil(y/tile);

    var topRightX = Math.ceil(x/tile);
    var topRightY = Math.floor(y/tile);

    var bottomRightX = Math.ceil(x/tile);
    var bottomRightY = Math.ceil(y/tile);

    context.fillStyle = 'brown';
    context.fillRect(topLeftX * tile, topLeftY * tile, tile, tile);

    context.fillStyle = 'red';
    context.fillRect(topRightX * tile, topRightY * tile, tile, tile);

    context.fillStyle = 'green';
    context.fillRect(bottomLeftX * tile, bottomLeftY * tile, tile, tile);

    context.fillStyle = 'gold';
    context.fillRect(bottomRightX * tile, bottomRightY * tile, tile, tile);

    if ((currentLevel.collisions[topLeftY][topLeftX] != 0) || (currentLevel.collisions[topRightY][topRightX] != 0))
    {
        //I changed this from plus to minus
        playerY = topLeftY * tile - tile;
        return true;
    }
    else if ((currentLevel.collisions[bottomLeftY][bottomLeftX] != 0) || (currentLevel.collisions[bottomRightY][bottomRightX] != 0))
    {
        playerY = bottomLeftY * tile - tile;
        return true;
    }
    else
    {
        return false;
    }
}

我将第一个playerY编辑更改为“-”,而不是“ +”。这样可以防止播放器向下传送,但是我不知道您是否也希望播放器向上传送。所以我决定尝试修复另一个。

嗯,原来垂直碰撞破裂了,所以要刮一下。将其切换回“ +”。这次我们尝试保持水平碰撞。

大约5分钟后,我发现播放器可能先进入黑色方块,然后再向后撞,从而导致垂直碰撞首先起作用。就像我说的那样,由于JS不是我的技能,因此您可能必须找到一种方法来获取水平,然后再进行垂直检查。尝试将两者切换!

编辑:

如果将它们切换,结果将很奇怪。我不会详细介绍。 我只是没有很多结果。