Canvas Collision обнаружение не точно в 2D-игре на основе Tile - PullRequest
0 голосов
/ 21 февраля 2019

Я делаю небольшую игру с использованием Javascript и Canvas.У меня есть обнаружение столкновений, но оно работает не очень хорошо.Я не могу пройти сквозь стены.Пока все хорошо, но работает только слева и сверху без наложения.

Моя карта основана на массивах 0 и 1. 1 можно пройти, 0 должен блокировать

Мой игрок 32x32 и мои плитки тоже.

PosX равен x Координата изmay Player PosY is y Координата от may Player

Вот мой код обнаружения:

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 левой стороны блокирующей плитки, он должен остановиться.

И я не знаю, почему это не работает.

Если вам нужно больше кодаПожалуйста, дайте мне знать.

Спасибо:)

1 Ответ

0 голосов
/ 21 февраля 2019

Из того, что я вижу, я предполагаю, что ваше обнаружение столкновений основано только на одной точке спрайта игрока - скорее всего, это центральная точка.Для более точного обнаружения столкновений нам необходимо учесть угловые точки, окружающие этот объект, и направление, в котором он движется.Кроме того, нам нужно проверить, не столкнемся ли мы с твердым объектом, таким как стена , до , мы фактически переместим его в эту позицию.Таким образом, мы можем поместить его рядом с этим объектом.

Рассмотрим пример:

collisionA

Наш спрайт игрокакрасный квадрат и он движется со скоростью 4 пикселя на кадр.А вы можете видеть спрайт и синюю стену на расстоянии всего 2 пикселя!Если мы переместимся вправо на 4 пикселя, нижний правый удар по стене.CollisionB

Чтобы обойти эту проблему, нам нужно проверить верхний правый и нижний правый углы спрайта на возможное столкновение, если мы хотим двигаться вправо.

Если мы обнаружим столкновение - опять же, прежде чем мы на самом деле что-то передвинем на экран - вместо этого мы поместим красного героя рядом с блоком.

collisionC

Вот сложный пример.Сфокусируйте его щелчком мыши и используйте клавиши курсора для перемещения.

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