Обнаружение столкновений холста Javascript - PullRequest
7 голосов
/ 05 ноября 2011

Я создаю игру в Javascript, используя canvas, который требует обнаружения столкновений, в этом случае, если спрайт игрока попадает в поле, игрок не должен быть пропущен через поле.

У меня есть глобальный массив с именем blockList, в котором хранятся все поля, отображаемые на холсте. Это выглядит так:

var blockList = [[50, 400, 100, 100]];

И они рисуются на холсте так:

c.fillRect(blockList[0][0], blockList[0][1], blockList[0][2], blockList[0][3]);

У меня также есть объект player, у которого есть метод update и метод draw. Обновление устанавливает положение игрока на основе ввода с клавиатуры и т. Д., А рисование используется основным игровым циклом для рисования игрока на холсте. Игрок рисуется так:

this.draw = function(timestamp) {
        if(this.state == "idle") {
            c.drawImage(this.idleSprite, this.idleSprite.frameWidth * this.idleSprite.frameCount, 0, this.idleSprite.frameWidth, this.idleSprite.frameHeight, this.xpos, this.ypos, this.idleSprite.frameWidth, this.idleSprite.frameHeight);
            if(timestamp - this.lastDraw > this.idleSprite.updateInterval) {
                this.lastDraw = timestamp;
                if(this.idleSprite.frameCount < this.idleSprite.frames - 1) { this.idleSprite.frameCount++; } else { this.idleSprite.frameCount = 0; }
            }
        } else if(this.state == "running") {
            var height = 0;
            if(this.facing == "left") { height = 37; }
            c.drawImage(this.runningSprite, this.runningSprite.frameWidth * this.runningSprite.frameCount, height, this.runningSprite.frameWidth, this.runningSprite.frameHeight, this.xpos, this.ypos, this.runningSprite.frameWidth, this.runningSprite.frameHeight);
            if(timestamp - this.lastDraw > this.runningSprite.updateInterval) {
                this.lastDraw = timestamp;
                if(this.runningSprite.frameCount < this.runningSprite.frames - 1) { this.runningSprite.frameCount++; } else { this.runningSprite.frameCount = 0; }
            }
        }
    }

Теперь у игрока есть определенные свойства: player.xpos, player.ypos, player.width, player.height. Те же свойства существуют для блоков. Таким образом, у меня есть все, что мне нужно для обнаружения столкновений, я просто не знаю, как это сделать. Я пытался делать такие вещи, как:

if(player.x > blockList[0][0] && player.y > blockList[0][1])

но это далеко от идеального или играбельного.

Кто-нибудь знает простой метод или функцию, позволяющую возвращать истину или ложь в зависимости от столкновения двух объектов?

Ответы [ 3 ]

8 голосов
/ 05 ноября 2011

Я использую следующую функцию для обнаружения столкновений между двумя прямоугольниками:

rect_collision = function(x1, y1, size1, x2, y2, size2) {
  var bottom1, bottom2, left1, left2, right1, right2, top1, top2;
  left1 = x1 - size1;
  right1 = x1 + size1;
  top1 = y1 - size1;
  bottom1 = y1 + size1;
  left2 = x2 - size2;
  right2 = x2 + size2;
  top2 = y2 - size2;
  bottom2 = y2 + size2;
  return !(left1 > right2 || left2 > right1 || top1 > bottom2 || top2 > bottom1);
};

Это определяет, будут ли два квадрата, центрированные в (x1, y1) и (x2, y2), с длинами сторон 2*size1 и 2*size2соответственно пересекаются.Должно быть достаточно легко изменить определения left1, right1 и т. Д., Чтобы иметь дело с общими прямоугольниками, а не только с квадратами, и использовать другой формат данных.

В частности, left1 - этолевая сторона первого квадрата, right1 правая сторона и т. д. Обратите внимание, что в моей системе координат ось Y инвертирована (top1 <<code>bottom1).

2 голосов
/ 05 ноября 2011

Вы просто хотите знать, перекрываются ли два прямоугольника?

Вот пуленепробиваемая функция для вас:

// returns true if there is any overlap
// params: x,y,w,h of two rectangles
function intersects(x1, y1, w1, h1, x2, y2, w2, h2) {
  if (w2 !== Infinity && w1 !== Infinity) {
    w2 += x2;
    w1 += x1;
    if (isNaN(w1) || isNaN(w2) || x2 > w1 || x1 > w2) return false;
  }
  if (y2 !== Infinity && h1 !== Infinity) {
    h2 += y2;
    h1 += y1;
    if (isNaN(h1) || isNaN(y2) || y2 > h1 || y1 > h2) return false;
  }
  return true;
}

Если ваша программа может быть уверена, что числа всегда будут конечными для васможет использовать более простую версию:

// returns true if there is any overlap
// params: x,y,w,h of two rectangles
function intersects(x1, y1, w1, h1, x2, y2, w2, h2) {
    w2 += x2;
    w1 += x1;
    if (x2 > w1 || x1 > w2) return false;
    h2 += y2;
    h1 += y1;
    if (y2 > h1 || y1 > h2) return false;
  return true;
}

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

Если любой прямоугольник начинается после того, как другой закончился, то столкновения нет.В противном случае должно произойти столкновение.

0 голосов
/ 07 марта 2016

По-моему, я не фанат функций, которые требуют много параметров.

Вот как я бы это сделал:

function collisionCheckRectRect(rectOne, rectTwo){

    var x1=rectOne.x, y1 = rectOne.y, height1 = rectOne.height, width1 = rectOne.width;
    var x2=rectTwo.x, y2 = rectTwo.y, height2 = rectTwo.height, width2 = rectTwo.width; 

    return x1 < x2+width2 && x2 < x1+width1 && y1 < y2+height2 && y2 < y1+height1;
}
...