MemeFrug
MemeFrug

Reputation: 15

JavaScript - How to have collision with character and an object?

Im testing on a simple game and i was starting to get into collision between the character and any object. I first went about this by getting the characters last position and changing the characters coordinates to it. I was wondering if there would be anyother way of doing it? Right now i have the "detection" part out of the way.

//Class Function
    iscolliding(object) {
        if (this.x < object.x + object.width &&
            this.x + this.width > object.x &&
            this.y < object.y + object.height &&
            this.height + this.y > object.y) {
            return true;
        } else {
            return false;
        }
    }

//------------------------------------------------------------------
//Is colliding function (returns bool)

    if (character.iscolliding(/*Object*/)) {
        console.log('working');
    }

Where there is console.log('working') i was wondering what i would do next? How would i stop the character from going through the object? I would prefer not to use Jquery, just plain javascript>

Thanks (:
If you need any more info i would gladly answer any comments below! (:

Upvotes: 0

Views: 1880

Answers (2)

guzmonne
guzmonne

Reputation: 2540

There are many algorithms that you can use to check for collisions. The one you are using works fine when you can simplify the objects that are colliding as rectangles.

An overlap will always occur when two boxes collide. How much will depend on the speed at which they were moving. After a collision is detected, you need to decide what to do with the elements. You probably want to move both elements so that they don't overlap. You could:

  1. Reset the position to the one before the collision occurred.
  2. Calculate the position they should be in when they collide and adjust them.

The first solution is easier, but it can't fail if the objects were moving too fast. The second solution is better but harder to implement. Especially if you later decide to use other geometries to check for collisions.

You can see an example of the first solution on this project:

https://stackblitz.com/edit/js-o8orw3?file=index.js

I've implemented an elementary Vector class that handles how the boxes move. Inside the animation frame, I move both boxes and check for a collision. If one happens, I move both boxes back to the position they were before colliding. You can update the SPEED constant to see how different they end up with this solution.

You could then adjust for the behavior your game requires. For a game, this solution should be enough.

Please refer to the following links for more information:

https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection

This one is from Unity, and touches some other ways to handle collisions. Everything except the sections about the editor itself can be applied.

https://learn.unity.com/tutorial/physics-best-practices#5c7f8528edbc2a002053b5b4

The same goes for this link:

https://learnopengl.com/In-Practice/2D-Game/Collisions/Collision-detection

Upvotes: 1

Justin
Justin

Reputation: 2958

You will want call another function if your current one determines that they are colliding. Then you will set the player's x and/or y value. So if you collide from the player's left side to the object right side you would set player.x to the object.x + object.w and set the player's velocity.x to 0.

Here's a function that works. You can see it in action on here where I recently answered another question. Just go down to the answer and run the snippet.

2d Square to rectangle collision detection and action(physics)

The collisionDetection() below is different from your in that if any value is true then there cannot be a collision and it just return. Otherwise there is one and it calls the narrowPhase().

function collisionDetection(obj) {
    if (player.x + player.w < obj.x ||
        player.x > obj.x + obj.w ||
        player.y + player.h < obj.y ||
        player.y > obj.y + obj.h) {
            return
        }
        narrowPhase(obj);
}

function narrowPhase(obj) {
    let playerTop_ObjBottom = Math.abs(player.y - (obj.y + obj.h));
    let playerRight_ObjLeft = Math.abs((player.x + player.w) - obj.x);
    let playerLeft_ObjRight = Math.abs(player.x - (obj.x + obj.w));
    let playerBottom_ObjTop = Math.abs((player.y + player.h) - obj.y);

    if ((player.y <= obj.y + obj.h && player.y + player.h > obj.y + obj.h) && (playerTop_ObjBottom < playerRight_ObjLeft && playerTop_ObjBottom < playerLeft_ObjRight)) {
        player.y = obj.y + obj.h;
        player.vy = 0;
    }
    if ((player.y + player.h >= obj.y && player.y < obj.y) && (playerBottom_ObjTop < playerRight_ObjLeft && playerBottom_ObjTop < playerLeft_ObjRight)) {
        player.y = obj.y - player.h; 
        player.jumping = false;
        player.vy = 0;
    }
    if ((player.x + player.w >= obj.x && player.x < obj.x) && (playerRight_ObjLeft < playerTop_ObjBottom && playerRight_ObjLeft < playerBottom_ObjTop)) {
        player.x = obj.x - player.w;
        player.vx = 0; 
    }
    if ((player.x <= obj.x + obj.w && player.x + player.w > obj.x + obj.w) && (playerLeft_ObjRight < playerTop_ObjBottom && playerLeft_ObjRight < playerBottom_ObjTop)) {
        player.x = obj.x + obj.w;
        player.vx = 0; 
    }
}

Upvotes: 2

Related Questions