8

I'm working on the Collision system for my game; which is a top down shooter, the character is always static - and everything else (Map/Level), moves around him.

The character also rotates so it's always facing the mouse position.

With that in mind, I can't seem to get my head around my collision system, which needs to take into account of the character rotation, right?

I basically just want to check if the given object is at all 'touching' my character/sprite. I'm not so sure if the maths I'm using is correct.

This is my collision detection (called every update):

function detectCollisions(){

    //Detect for game props
    if(collides(Map, TestProp)){
        console.debug("Touching...");
    }

}

function collides(a, b){

    //ctxMap.setTransform(1, 0, 0, 1, -Map.x + gameWidth/2, -Map.y + gameHeight/2);

    //var transX = -Map.x + gameWidth/2;
    //var transY = -Map.y + gameHeight/2;

    //need to take player rotation into account too!

    //console.debug(a.x + " " + b.x + " " + b.width + " " + Player.width); //A Width

    /*return  a.x < b.x + b.width && a.x + Player.width > b.x &&
            a.y < b.y + b.height && a.y + Player.height > b.y;*/

    var xOffset = Math.cos(Player.characterRotation); //+ Player.width;
    var yOffset = Math.sin(Player.characterRotation); //+ Player.height;

    return  Map.x + xOffset > b.x && Map.x + xOffset < b.x + b.width &&
            Map.y + yOffset > b.y && Map.y + yOffset < b.y + b.height;

}

Also, not sure if this is relevant, but this is the transform used to move my Map Canvas:

ctxMap.setTransform(1, 0, 0, 1, -Map.x + gameWidth/2, -Map.y + gameHeight/2);

Would much appreciate it if someone helped me out here :) Thanks!

Oliver Jones
  • 1,420
  • 7
  • 27
  • 43
  • Do you need to use rectangles? If not, you could just do a circle based collision detection by computing the distance between the two center points and comparing it to the radii. – WildCrustacean Jan 24 '13 at 20:35
  • The sprite is a rect, and so is the test prop ... for now – Oliver Jones Jan 24 '13 at 20:47
  • 1
    This is a possible duplicate then: http://stackoverflow.com/questions/641219/how-can-i-perform-collision-detection-on-rotated-rectangles – WildCrustacean Jan 25 '13 at 17:40

2 Answers2

4

Personally, I wouldn't worry so much about the character colliding. The reason I say that is simple.

Let's saw you're walking real close to a wall. Then you turn to follow the mouse, and the sprite then overlaps the wall. What do you do now? Either you stop the turning, which would screw up movements, or you let the sprite overlap and the player gets completely stuck until they turn free again.

My preference would be to use a collision circle. If the player is closer than R pixels from the wall, count it as a collision and stop the player from moving. This way, even if the player turns, the sprite will never cause the player to get stuck and he will always be able to move away from the wall.

Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
  • Thats a good idea - okay, thanks @Kolink. How would one go about doing that? Does it have a particular term? Circular Character Collisions? – Oliver Jones Jan 28 '13 at 14:25
  • It should be simple. Look at the center point of your sprite, and check the shortest distance between that and the wall is not less than the radius of your circle (else you have a collision). – CodePB Feb 01 '13 at 16:52
2

I entered ludum dare this time around and did a tutorial to explain my base code. The tutorials can be found here: http://www.philjeffes.co.uk/wordpress/?p=63

This demonstrates an example of circle based collision detection - please feel free to use any of the code. The following code is an adaptation of that code for general usage:

function CollisionCheck(obj1,obj2){
    // If the two objects are less the sum of their collision radii apart then they have collided
    // Note that one obj is obj (with a loc and a size) and the other is this.
    // Returns true if the objects are touching

    var dist = obj2.size + obj1.size; // The distance they must be apart to be not touching
    if(obj1.x-obj2.x>dist || obj1.x-obj2.x<-dist)
       return false; // Too far apart in x plane
    if(obj1.y-obj2.y>dist || obj1.y-obj2.y<-dist)
       return false; // Too far apart in y plane

    var xDist = obj1.x-obj2.x;
    var yDist = obj1.y-obj2.y;

   var hyp = Math.sqrt((xDist*xDist)+(yDist*yDist));

   if(hyp<dist)
    return true;

   return false;

}

EDIT

Removed the Math.abs calls as pointed out by vals in the comments.

PJeffes
  • 366
  • 2
  • 11
  • function colliding(obj1,obj2){ var x = obj1.x - obj2.x, y = obj1.y - obj2.y; return Math.sqrt(x*x + y*y) < obj1.size + obj2.size; } – Stijn de Witt Feb 02 '13 at 00:00
  • just a comment here: Stijn de witt optimization works because abs is useless if you are going to get the power of 2 – vals Feb 03 '13 at 11:46
  • That's true - The code is deliberately expanded for clarity. I agree though the optimisations mentioned are valid. @vals - I have now removed the abs calls. They were for debugging and I had left them in. Thanks :) – PJeffes Feb 04 '13 at 09:48
  • Another common optimization in this scenario would be to make the player a point with no dimension (size = 0). All the other objects need to have their size increased, and everything works the same. – vals Feb 04 '13 at 10:43