Search code examples
javascriptjquerycollision-detectioncollisionboundary

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.


Solution

  • 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;
    }