【问题标题】:Canvas Collision detection not exact on an 2D Tilebased game画布碰撞检测在基于 2D Tile 的游戏上并不准确
【发布时间】:2023-03-17 23:35:01
【问题描述】:

我用 Javascript 和 Canvas 制作了一个小游戏。我有碰撞检测,但效果不太好。我不能穿墙。到目前为止一切都很好,但它只适用于左侧和顶部,没有重叠。

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

我的播放器是 32x32,我的瓷砖也是。

PosX 是来自可能玩家的 x 坐标 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 右侧触及阻挡瓷砖的左侧时,他必须停下来。

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

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

谢谢:)

【问题讨论】:

    标签: javascript canvas 2d collision-detection collision


    【解决方案1】:

    据我所知,我假设您的碰撞检测仅基于玩家精灵的一个点 - 很可能是中心点。 为了进行更精确的碰撞检测,我们需要考虑该对象周围的角点及其方向 搬到。此外,我们需要检查是否会在我们实际将其移动到该位置之前与墙壁等固体物体发生碰撞。 这样我们就可以将它与该对象并排放置。

    考虑这个例子:

    我们的玩家精灵是红色方块,它以每帧 4 像素的速度移动。 A 你可以看到精灵和蓝墙仅相距 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);

    【讨论】:

    • 非常感谢 :D 在我阅读了你的文章并意识到我必须使用我的播放器的所有四个站点并且必须检查我击中瓷砖的位置之后,它现在可以工作了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-30
    • 1970-01-01
    • 2019-02-20
    • 1970-01-01
    相关资源
    最近更新 更多