Search code examples
javalwjglgame-engine

LWJGL - When my player collides with more than one wall object he starts to bounce back and forth


So me and my friends are deciding to make a game, so I decided to create an engine for the game. And all was going well, I implemented a collision type I call "Push Collision" which basically means: When the player is moving towards and object take the speed it is moving at the object with and subtract it to the position, so say I am pressing W or the up arrow and I am moving into a wall, the wall will take my Horizontal speed or ysp (Y Speed) and subtract it to my y position. And it started working until I added a second box, know it worked when I went to collide with the boxes one by one, but when I got in the middle of the two wall objects, and my player would start bouncing back and forth from the walls. Now I know whats going on, since it's colliding with one wall it is subtracting my speed to my y or x position, but since I am colliding with two it will subtract twice the speed I am moving at to my x or y, I was thinking that I could just increase the x or y speed of the object/player but then the objects will just subtract twice was I am moving, so I'm in a bit of a pickle. Here is the code that I made for the "Push Collision type" and the Game class along with the Player class and TestBox class or Wall class.

Collision Class:

package engine.test.core;

public class Collision {
    public static void PushCollision(BaseObject obj1, BaseObject obj2) {
        if (obj1.box.CollideWOB(obj2.box)) {

            if (obj1.MoveDir == 2) {
                obj1.Position.x -= obj1.xsp;
            } else if (obj1.MoveDir == 1) {
                obj1.Position.x += obj1.xsp;
            } else if (obj1.MoveDir == 3) {
                obj1.Position.y += obj1.ysp;
            } else if (obj1.MoveDir == 4) {
                obj1.Position.y -= obj1.ysp;
            }
        }
    }
}

Player Class:

package engine.test.game;

import org.lwjgl.input.Keyboard;

import engine.test.core.BaseObject;
import engine.test.core.Renderer;

public class Player extends BaseObject {

    public Player(int x, int y, int w, int h) {
        super(x, y, w, h);
    }

    @Override
    public void Init() {
        xsp = 5;
        ysp = 5;
    }

    @Override
    public void Update() {
        if (Keyboard.isKeyDown(Keyboard.KEY_D)) {
            MoveDir = 2;
        } else if (Keyboard.isKeyDown(Keyboard.KEY_A)) {
            MoveDir = 1;
        } else if (Keyboard.isKeyDown(Keyboard.KEY_S)) {
            MoveDir = 4;
        } else if (Keyboard.isKeyDown(Keyboard.KEY_W)) {
            MoveDir = 3;
        } else {
            MoveDir = 0;
        }

        if (MoveDir == 1) {
            Position.x -= xsp;
        } else if (MoveDir == 2) {
            Position.x += xsp;
        } else if (MoveDir == 3) {
            Position.y -= ysp;
        } else if (MoveDir == 4) {
            Position.y += ysp;
        }

        box.UpdateBox(Position, Size);
    }

    @Override
    public void Draw() {
        Renderer.Quad(Position, Size);
    }
}

TestBox Class:

package engine.test.game;

import engine.test.core.BaseObject;
import engine.test.core.Renderer;

public class TestBox extends BaseObject {

    public TestBox(int x, int y, int w, int h) {
        super(x, y, w, h);
    }

    @Override
    public void Init() {

    }

    @Override
    public void Update() {
        box.UpdateBox(Position, Size);
    }

    @Override
    public void Draw() {
        Renderer.Quad(Position, Size);
    }
}

Game Class:

package engine.test.game;

import java.util.ArrayList;
import java.util.List;

import engine.test.core.BaseGame;
import engine.test.core.Collision;

public class Game extends BaseGame {

    Player p;
    TestBox tb;
    TestBox tb2;

    List<TestBox> TestBoxes = new ArrayList<TestBox>();


    boolean Debug = false;

    @Override
    public void Init() {
        p = new Player(0, 0, 32, 32);

        p.Init();

        tb = new TestBox(100, 100, 32, 32);
        tb2 = new TestBox(132, 100, 32, 32);

        tb.Init();
        tb2.Init();

        TestBoxes.add(tb);
        TestBoxes.add(tb2);
    }

    @Override
    public void Update() {

        p.Update();

        for (TestBox box : TestBoxes) {
            Collision.PushCollision(p, box);
        }
    }

    @Override
    public void Draw() {
        p.Draw();

        for (TestBox box : TestBoxes) {
            box.Draw();
        }
    }
}

Solution

  • One approach you could take to solve this is:

    • When a collision is detected, add it to a queue of "detected collisions" which should hold the collision box data.
    • After all collisions have been detected and added to the queue, iterate through the queue and after each push, check to see if the object is still colliding with that object. If it is, calculate a new push and apply that. Otherwise, ignore the original collision.

    This is the first solution that comes to mind for me. Let me know if you have any questions about this! :)