Side Collisions

76 views Asked by At

I'm making a tilemap game and I've got the simple collisions down. However to make the game work I have to know which side of the rectangle hit the wall/brick. Just putting a simple collision code inside of the main collision:

if(spriteX < brickX + brickwidth) {}

doesn't work. The main collision code at the moment is:

for(int counter = 0; counter < 31; counter++) {

    if(spriteX + 40 >= collisionX[counter] && collisionX[counter] + 100 >= spriteX 
    && spriteY + 40 >= collisionY[counter] && collisionY[counter] + 100 >= spriteY) {

        velX = 0;
        velY = 0;

        collisions = counter;

    } else {

        if(counter == collisions && jumping == false) {

            fall();                 
        }               
    }           
}

If you want the entire class:

package Main;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;

import javax.swing.JPanel;

public class Panel extends JPanel implements Runnable, KeyListener {

// dimensions

public static final int width = 800;
public static final int height = 800;
public static final int scale = 1;

// main loop

private Thread thread;
private boolean running = false;
private int FPS = 60;
private int targetTime = 1000 / FPS;

// drawing

private Graphics2D g;
private BufferedImage image;

int x;
int y;

boolean makeCollision = false;

// sprite

int spriteX = 210;
int spriteY = 200;
int velX = 0;
int velY = 10;

public boolean notOnGround = true;

int counter;
int collisionsCounter;
int jumps = 0;

public int row;
public int column;

public boolean collision;
public boolean jumping = false;

public String side = null;

// tilemap

int[][] map = {

        {1, 1, 1, 1, 1, 1, 1, 1},
        {1, 0, 0, 1, 0, 0, 1, 1},
        {1, 0, 0, 0, 0, 1, 1, 1},
        {1, 0, 0, 0, 1, 1, 0, 1},
        {1, 0, 0, 1, 1, 0, 0, 1},
        {1, 0, 0, 1, 0, 0, 0, 1},
        {1, 0, 0, 0, 0, 0, 0, 1},
        {1, 1, 1, 1, 1, 1, 1, 1}

};

int[] collisionX = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
                    };
int[] collisionY = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
                    };
int[] jump =       {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
                    };
int collisions;

public Panel() {

    setPreferredSize(new Dimension(width * scale, height * scale));
    setFocusable(true);
    requestFocus();

}

public void addNotify() {
    super.addNotify();

    if(thread == null) {

        running = true;
        addKeyListener(this);
        thread = new Thread(this);
        thread.start();

    }

}

public void init() {

    image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    g = (Graphics2D) image.getGraphics();

}

public void update() {

    if(spriteY < jump[0]) {

        System.out.println(jump[0]);

        jumping = false;

        fall();

    }

}

public void draw() {

    g.clearRect(0, 0, WIDTH, HEIGHT);

    x = 0;
    y = 0;

    for(column = 0; column <= 7; column++) {

        x = 0;

        for(row = 0; row <= 7; row++) {

            changeColor(row, column, g);

            g.fillRect(x, y, 100, 100);

            x = x + 100;

        }

        y = y + 100;

    }

    g.setColor(Color.YELLOW);
    g.fillRect(spriteX, spriteY, 40, 40);

    spriteX += velX;
    spriteY += velY;

    for(int counter = 0; counter < 31; counter++) {

        if(spriteX + 40 >= collisionX[counter] && collisionX[counter] + 100 >= spriteX 
        && spriteY + 40 >= collisionY[counter] && collisionY[counter] + 100 >= spriteY){

            velX = 0;
            velY = 0;

            collisions = counter;

        } else {

            if(counter == collisions && jumping == false) {

                fall();

            }

        }

    }

}

public void changeColor(int rowGive, int columnGive, Graphics g) {

    if(map[rowGive][columnGive] == 1) {

        g.setColor(Color.BLACK);

        if(counter < 30) {

            collisionX[counter] = x;
            collisionY[counter] = y;

        }

        counter++;

    } else {

        g.setColor(Color.WHITE);

    }

}

public void fall() {

    velY = 5;

}

public void drawToScreen() {

    Graphics g2 = getGraphics();
    g2.drawImage(image, 0, 0, width * scale, height * scale, null);
    g2.dispose();

}

public void run() {

    init();

    long wait;
    long elapsed;
    long start;

    while(running) {

        start = System.nanoTime();
        update();
        draw();
        drawToScreen();

        elapsed = System.nanoTime() - start;

        wait = targetTime - elapsed / 1000000;

        if(wait < 0) wait = 5;

        try {

            thread.sleep(wait);

        } catch(Exception e) {

            e.printStackTrace();

        }

    }

}

public void keyPressed(KeyEvent e) {

    int code = e.getKeyCode();

    if(code == KeyEvent.VK_RIGHT) {

        velX = 5;

    }
    if(code == KeyEvent.VK_LEFT) {
        velX = -5;

    }
    if(code == KeyEvent.VK_SPACE && jumping == false) {

        jumping = true;

        velY = -5;
        jump[0] = spriteY - 100;

    }

}
public void keyReleased(KeyEvent e) {



}
public void keyTyped(KeyEvent e) {


}}
2

There are 2 answers

1
Pierre On

Let's try to divide the problem a little bit. You don't need to find out when a rectange hit a wall: you need to find when the left side of the rectangle hit the right side of the wall and when the right side of the rectangle hit the left side of the wall.

To be more precise: don't test objects. Divide your object in collision surfaces (left and right sides in your case), find a way to modelize them (usually x and x+width are the left and right side of your rectangle, if x is the x coordinate of your topleft corner). And test both at the same time with an "or" condition.

if(spriteX < brickX + brickwidth || spriteX + spritewidth > brickX) {}

edit Reading your complete class a little more closely, it looks like you do something similar but you use "&&" condition, meaning you can never be true since both side collisions cannot happen at the same time. But I may be wrong, can you tell me ?

0
candied_orange On

While not strictly about your collision problem I've noticed a "bug" in draw() that is causing your map array to be displayed flipped around the -45 angle.

You should be incrementing y when row is incremented and x when column is incremented. Do this and your display will look the same as your map initialization code.

In other words this:

public void draw() {

    g.clearRect(0, 0, WIDTH, HEIGHT);

    x = 0;
    y = 0;

    for(column = 0; column <= 7; column++) {

        y = 0;

        for(row = 0; row <= 7; row++) {

            changeColor(row, column, g);

            g.fillRect(x, y, 100, 100);

            y = y + 100;

        }

        x = x + 100;

    }
...

will make this

int[][] map = {

        {1, 1, 1, 1, 1, 1, 1, 1},
        {1, 0, 0, 1, 0, 0, 1, 1},
        {1, 0, 0, 0, 0, 1, 1, 1},
        {1, 0, 0, 0, 1, 1, 0, 1},
        {1, 0, 0, 1, 1, 0, 0, 1},
        {1, 0, 0, 1, 0, 0, 0, 1},
        {1, 0, 0, 0, 0, 0, 0, 1},
        {1, 1, 1, 1, 1, 1, 1, 1}

};

look like this

enter image description here

instead of this

enter image description here