HTML5 + JS: Collision Detection For Rotatable Character
Asked Answered
M

2

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!

Mcnulty answered 24/1, 2013 at 20:30 Comment(3)
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.Brodsky
The sprite is a rect, and so is the test prop ... for nowMcnulty
This is a possible duplicate then: #641719Brodsky
D
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.

Diplo answered 29/1, 2013 at 17:19 Comment(4)
function colliding(obj1,obj2){ var x = obj1.x - obj2.x, y = obj1.y - obj2.y; return Math.sqrt(xx + yy) < obj1.size + obj2.size; }Mesh
just a comment here: Stijn de witt optimization works because abs is useless if you are going to get the power of 2Forehead
That's true - The code is deliberately expanded for clarity. I agree though the optimisations mentioned are valid. @Forehead - I have now removed the abs calls. They were for debugging and I had left them in. Thanks :)Diplo
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.Forehead
C
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.

Comose answered 28/1, 2013 at 0:46 Comment(2)
Thats a good idea - okay, thanks @Kolink. How would one go about doing that? Does it have a particular term? Circular Character Collisions?Mcnulty
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).Robbery
D
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.

Diplo answered 29/1, 2013 at 17:19 Comment(4)
function colliding(obj1,obj2){ var x = obj1.x - obj2.x, y = obj1.y - obj2.y; return Math.sqrt(xx + yy) < obj1.size + obj2.size; }Mesh
just a comment here: Stijn de witt optimization works because abs is useless if you are going to get the power of 2Forehead
That's true - The code is deliberately expanded for clarity. I agree though the optimisations mentioned are valid. @Forehead - I have now removed the abs calls. They were for debugging and I had left them in. Thanks :)Diplo
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.Forehead

© 2022 - 2024 — McMap. All rights reserved.