2D Collision detection

Started by royger, April 07, 2007, 13:47:38

Previous topic - Next topic

royger

Hello,

I'm developing a 2D game (Metal Slug clone) with lwjgl and I would like to know if there is any collision detection method, I was thinking about using a 2D brute force mode with the java Rectangle class (like in the space invaders tutorial from the site), but I'm open to suggestions.

I use OpenGL for rendering and also have the textures loaded, so I was thinking if there was a better way to detect collision (like a pixel-to-pixel comparation).

Thanks and regards, Roger.

bobjob

Very cool cant wait 2 c it!

as for collision techniques, more you play with it  you'll find which one seems to flow for you.

In my personal opinion. i like point(position) to line collisions, therefore depding on your x-position, you can just run a check on the line located under you (or on the two lines if you have multiple platforms). works well for ramps in order to climb up the gradient of the line. also if you ever deside to go 3d it will be a smooth transition.

but if you want something easy 2 program with very little physics, prob use ur point against other rectangles.

not familiar with any other techniques myself, hopefully other people have some good ideas

princec

For a Breakout game I wrote recently I had rect-rect, rect-circle, and circle-circle collisions, depending on what shape fit best. Had to do some other clever stuff with per-pixel movements to get collisions to work properly when the ball was moving faster than 1 pixel/frame. Was all brute force too.

Cas :)

elias4444

I would recommend getting some books that cover this subject (e.g., Real Time Collision Detection). They're great to have for reference, and this is a subject that you'll always be dealing with in games.

Pixel to pixel collision detection can be VERY expensive, so I wouldn't recommend it unless it's really needed.
Spherical/Circular/Cylindrical detection is a pretty optimal method for odd shapes (create X number of collision zones per object in order to match it as close as possible). If your objects/sprites are more boxy, create a number of collision boxes and then just check if the other object's zones collide with any (a loop that does a bunch of greater-than/less-than checks). And if you feel like getting it to be as exact as possible, mix and match the different shape methods.

I'm still in the middle of moving across a couple of states, but if you need more help when I'm finished, I can post a few code snippets for you.
=-=-=-=-=-======-=-=-=-=-=-
http://www.tommytwisters.com

royger

Hi, thanks for the interest.

I've been working on this recently and I've eventually coded a simple collision detection method using rectangles. I have a few problems though, and would like to know how to draw a java Rectangle class object on a lwjgl OpenGL Display. Later on, when the method is ended I can post it here, for other 2D game developers interested.

Thanks, Roger

royger

I've been trying to do this, but with no luck, here is my non-working code, I hope someone can give me some advice, thanks:

public void drawR(Rectangle rect) {
		int x1,y1,width,height;
                // store the current model matrix
		GL11.glPushMatrix();
		
                x1 = (int) rect.getX();
                y1 = (int) rect.getY();
                width = (int) rect.getWidth();
                height = (int) rect.getHeight();
			
                GL11.glTranslatef(x1, y1, 0);
                
		GL11.glColor3f(1, 0, 0); 

                GL11.glBegin(GL11.GL_POLYGON);
                {
                    GL11.glVertex2f(0, 0);
                    GL11.glVertex2f(0, height);
                    GL11.glVertex2f(width,height);
                    GL11.glVertex2f(width,0);
                    
                }
                GL11.glEnd();
		
		GL11.glPopMatrix();
}


I've also tryed to implement it with glRect* functions, but with no luck.

Thanks and regards, Roger.

bobjob

Is this a collision question? i personally do not use openGL for any collision checks

if it is a display problem try using Quad instead of polygon as you are working with rectangles
GL11.glBegin(GL11.GL_QUADS);			// Draw A Quad
   GL11.glVertex3f(0, height, 0.0f);		   // Top Left
   GL11.glVertex3f(width, height, 0.0f);	 // Top Right
   GL11.glVertex3f(width, 0, 0.0f);	          // Bottom Right
   GL11.glVertex3f(0 ,0, 0.0f);			    // Bottom Left
GL11.glEnd();						// Done Drawing The Quad



Kavi

Hey. Just tried your code and it works fine. (both using GL_QUADS and GL_POLYGON) Must be some initializing you've got wrong...

As for collision detection i personally prefer bounding circles (mixing with lines for checks against walls).. but as has been said it depends a lot on the shapes of objects you need to check for, and I haven't worked a lot with other approaches. I'll give a code example for bounding circles if you want otherwise i won't bother :)

good luck

royger

Hi,

Still no luck trying to draw rectangles, thanks for the advice. I would like to draw them to check my collision method, because it has a bug and detects a collision while jumping when there are no other objects (at least I think so, that's why I would like to check it by drawing a rectangle arround each entity).

Here are my initialization methods, copied them from the spaceinvaders 2D tutorial:

                       
setDisplayMode();
                        //Display.setFullscreen(true);
			Display.create();
                        
			
			// grab the mouse, dont want that hideous cursor when we're playing!
			//Mouse.setGrabbed(true);
			// enable textures since we're going to use these for our sprites
			GL11.glEnable(GL11.GL_TEXTURE_2D);
			
			// disable the OpenGL depth test since we're rendering 2D graphics
			GL11.glDisable(GL11.GL_DEPTH_TEST);
			
			GL11.glMatrixMode(GL11.GL_PROJECTION);
			GL11.glLoadIdentity();
			
			GL11.glOrtho(0, width, height, 0, -1, 1);
			
			textureLoader = new TextureLoader();
			
			if(callback != null) {
				callback.initialise();
			}


I think I miss some kind of GL11.glEnable(); argument, but not sure wich one. Thanks another time.

Kavi: I would really like to see some examples, so please send me or post your code, as you prefer.

bobjob

run this tutorial on your computer
http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=03
the lwjgl source is at the bottom of the page.

if you cant run the source its because, lwjgl isnt setup correctly on your computer

Kavi

Hmm.. still works for me  ???

Only removed TextureLoader and callback init as I don't have those classes.. don't think it should make a difference anyways.

Here is how i used your code:
import java.awt.Rectangle;

import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;


public class Controller {

	private boolean gamerunning = false;

	private int width = 800;
	private int height = 600;

	public Controller() throws LWJGLException
	{
		init();
	}

	private void init() throws LWJGLException
	{
		if (setDisplayMode())
		{
			Display.create();
			GL11.glEnable(GL11.GL_TEXTURE_2D);
			GL11.glDisable(GL11.GL_DEPTH_TEST);
			GL11.glMatrixMode(GL11.GL_PROJECTION);
			GL11.glLoadIdentity();
			GL11.glOrtho(0, width, height, 0, -1, 1);
			GL11.glClearColor(0f, 0f, 0f, 0f);
			
			gamerunning = true;
		}
		else
			System.out.println("Couldn't find desired display-mode");
	}

	private boolean setDisplayMode() throws LWJGLException
	{
			DisplayMode[] modes = Display.getAvailableDisplayModes();
			DisplayMode displaymode = null;

			for (int i = 0; i < modes.length;i++)
			{
				if (modes[i].getWidth() == width && modes[i].getHeight() == height 
						&& modes[i].getBitsPerPixel() == 32)
				{
					displaymode = modes[i];
				}
			}

			if (displaymode == null)
			{
				return false;
			}
			else
			{
				Display.setDisplayMode(displaymode);
				return true;
			}	
	}

	public void run()
	{
		while(gamerunning)
		{
			if (Keyboard.isKeyDown(Keyboard.KEY_ESCAPE) || Display.isCloseRequested())
			{
				gamerunning = false;
			}
			GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);

			drawR(new Rectangle(100,100,200,200));

			Display.update();
		}
	}

	public void drawR(Rectangle rect) {
		int x1,y1,width,height;
		// store the current model matrix
		GL11.glPushMatrix();

		x1 = (int) rect.getX();
		y1 = (int) rect.getY();
		width = (int) rect.getWidth();
		height = (int) rect.getHeight();

		GL11.glTranslatef(x1, y1, 0);

		GL11.glColor3f(1, 0, 0); 

		GL11.glBegin(GL11.GL_POLYGON);
		{
			GL11.glVertex2f(0, 0);
			GL11.glVertex2f(0, height);
			GL11.glVertex2f(width,height);
			GL11.glVertex2f(width,0);

		}
		GL11.glEnd();

		GL11.glPopMatrix();
	}
}


(Decided to post the entire class - then you can see where my code differs from yours and see why it doesn't work :)
Just need to make a main-method which creates a Controller and calls run() on it afterwards...

Hope it helps :)

I'll post some examples later (monday most likely). I'm moving this weekend so will have to pack my computer as well for 1-2 days  :'(

royger

Sorry for the delay in the reply, I've had some exams this week and were unable to do any work.

Can you please post some examples of collision detection? I've heard something about checking collisions with lines, which seems quite interesting.

Thanks, Roger.

bobjob

good choice ;)

do you understand the equation y = mx + c, its quite basic but if you dont understand that would make it a little hard to explain.

once you understand it (if you dont message me ill give a overvue of it) you set two points. which make a line
then do a test on the character using the equation such as:

// check if the xPosition of the character is between the line points: assuming Line.X1 is always less the Line.X2
if (character.xPos > Line.X1 && characater.xPos < Line.X2) {
        if (character.yPos <= (Line.M * character.xPos) + Line.C) {
                  //then collided
                  character.yPos = (Line.M * character.xPos) + Line.C;
        }
}


i hope u understand how to get M and C. also the importand thing to understand with a basic line collision that i have used, you cannot have X1 and X2 with the same value. as the line would have and infinite gradient. also this simple equation only allows for one platform at a time with any angle.

so the level may look something like
       ________
___/              \
                      \______


but not:
             _______
__    ___/      ____
    \________/       \
as it has multiple platforms ocupying the Y space

its an easy fix but hopefully you understand the basics for now