Kenton de Jong
Kenton de Jong

Reputation: 995

Collision Checking With JavaScript

I'm creating a game where the user wanders around a cemetery and collects stories from different graves. It's a classic top-down game. I'm building a script where if the user walks into a grave their movement stops, but I'm having trouble setting up collisions. I am using jQuery. Here is what I have so far:

var position = -1;
var $char = $('#char');
var keyCode = null;
var fired = false;
var $stones = $('.stones div');
var collision = null;

document.onkeydown = function(e) {

keyCode = e.which || e.keyCode;

if (!fired) {
    position = -1;
    fired = true; 
    switch (keyCode) {
        case 38: position = 0; break; //up
        case 40: position = 1; break; //down
        case 37: position = 2; break; //left
        case 39: position = 3; break; //right
    }

    walking();
    stepping = setInterval(walking,125);
}

};

document.onkeyup = function(e) {
  //standing
  clearInterval(stepping);
  stepping = 0;
  fired = false;
};


function walking() {

$stones.each(function() { //check all the stones...

    collision = collision($(this), $char, position); ...for collisions

    if (collision) { //if any, then break loop
        return false; 
    }

});

if (!collision) { //check if there was a collision
   //if no collision, keep walking x direction
}


function collision($el, $charEl, position) {

var $el = $el[0].getBoundingClientRect();
var $charEl = $charEl[0].getBoundingClientRect();

var elBottom = parseInt($el.bottom);
var elRight = parseInt($el.right);
var elLeft = parseInt($el.left);
var elTop = parseInt($el.top);

var charBottom = parseInt($charEl.bottom);
var charRight = parseInt($charEl.right);
var charLeft = parseInt($charEl.left);
var charTop = parseInt($charEl.top);

//this is where I'm stuck

}
}

I've tried various different codes, but nothing seems to work. I keep having an issue where if I'm going forward and then I bump into a headstone and I turn around, I'm stuck. Here's an example code of what I mean:

if (position == 0 && 
    !(elTop > charBottom ||
    elBottom < charTop ||
    elRight < charLeft + 1 ||
    elLeft > charRight - 1)
   ) {
    return true; 
}


if (position == 1 && 
    !(elTop > charBottom ||
    elBottom < charTop ||
    elRight < charLeft + 1 ||
    elLeft > charRight - 1)
   ) {
    return true; 
}

return false;

enter image description here

I have looked this question and this question and this question and so far I'm not having any luck. Can somebody help me with the logic or supply an example code of what I need to do?

Thank you.

Upvotes: 3

Views: 267

Answers (2)

Kenton de Jong
Kenton de Jong

Reputation: 995

I managed to find the following solution, thanks to stwitz' about idea, as well as this script: https://magently.com/blog/detecting-a-jquery-collision-part-iv/

var position = -1;
var $char = $('#char');
var keyCode = null;
var fired = false;
var stepSize = 32;
var $stones = $('.stones div');

//new
var cancelTop = cancelRight = cancelLeft = cancelBottom = false;

var charEl = $char[0].getBoundingClientRect();
var charLeft = parseInt(charEl.left);
var charRight = parseInt(charEl.right);
var charTop = parseInt(charEl.top);
var charBottom = parseInt(charEl.bottom);

function walking() {

if (position == 0 && !cancelTop) {
    //if moving up & is safe to move up
} else if (position == 1 && !cancelBottom) {
    //if moving down & is safe to move down
} else if (position == 2 && !cancelLeft) {
   //if moving left and is safe to move left
} else if (position == 3 && !cancelRight) {
   //if moving right and is safe to move right
}

cancelTop = cancelRight = cancelLeft = cancelBottom = false; //mark all as safe until we check

$stones.each(function() {

    collision($(this));

});

}

document.onkeydown = function(e) {

keyCode = e.which || e.keyCode;

if (!fired) {
    position = -1;
    fired = true; 
    switch (keyCode) {
        case 38: position = 0; break; //up
        case 40: position = 1; break; //down
        case 37: position = 2; break; //left
        case 39: position = 3; break; //right
    }

    walking();
    stepping = setInterval(walking,125);
}

};

document.onkeyup = function(e) {
  //standing
  clearInterval(stepping);
  stepping = 0;
  fired = false;
};


function collision($el) {

var el = $el[0].getBoundingClientRect();

var elBottom = parseInt(el.bottom);
var elRight = parseInt(el.right);
var elLeft = parseInt(el.left);
var elTop = parseInt(el.top);

if ( 
    (elRight == charLeft) &&
    (elBottom - stepSize >= charBottom && charBottom >= elTop + stepSize)
    ) { 
    cancelLeft = true;
    return true;  
}

if ( 
    (elLeft == charRight) &&
    (elBottom - stepSize >= charBottom && charBottom >= elTop + stepSize)
    ) { 
    cancelRight = true;
    return true;  
}

if ( 
    (elTop + stepSize > charBottom) && 
    (elTop <= charBottom) && 
    (elLeft < charRight) && 
    (elRight > charLeft) 
    ) 
{ 
    cancelBottom = true;
    return true; 
}

if ( 
    (elBottom - stepSize < charTop) && 
    (elBottom >= charTop) && 
    (elLeft < charRight) && 
    (elRight > charLeft) 
    ) 
{ 
    cancelTop = true;
    return true; 
}

return false;
}

Upvotes: 1

stwilz
stwilz

Reputation: 2397

Your game is looking good man!

I recently wrote some collision detection and had the exact same problem. The issue is that once your coordinates are true of the case of the collision then they will always be true on any other movement.

You need to store the previous position your character was in and revert back to it OR perform the check before you change your characters coordinates.

Upvotes: 2

Related Questions