views:

4378

answers:

6

I have two characters displayed in a game I am writing, the player and the enemy. defined as such:

public void player(Graphics g) {
    g.drawImage(plimg, x, y, this);
}

public void enemy(Graphics g) {
    g.drawImage(enemy, 200, 200, this);
}

Then called with:

player(g);
enemy(g);

I am able to move player() around with the keyboard, but I am at a loss when trying to detect a collision between the two. A lot of people have said to use Rectangles, but being a beginner I cannot see how I would link this into my existing code. Can anyone offer some advice for me?

A: 

Use a rectangle to surround each player and enemy, the height and width of the rectangles should correspond to the object you're surrounding, imagine it being in a box only big enough to fit it.

Now, you move these rectangles the same as you do the objects, so they have a 'bounding box'

I'm not sure if Java has this, but it might have a method on the rectangle object called .intersects() so you'd do if(rectangle1.intersectS(rectangle2) to check to see if an object has collided with another.

Otherwise you can get the x and y co-ordinates of the boxes and using the height/width of them detect whether they've intersected yourself.

Anyway, you can use that to either do an event on intersection (make one explode, or whatever) or prevent the movement from being drawn. (revert to previous co-ordinates)

edit: here we go

boolean

intersects(Rectangle r) Determines whether or not this Rectangle and the specified Rectangle intersect.

So I would do (and don't paste this code, it most likely won't work, not done java for a long time and I didn't do graphics when I did use it.)

Rectangle rect1 = new Rectangle(player.x, player.y, player.width, player.height);

Rectangle rect1 = new Rectangle(enemy.x, enemy.y, enemy.width, enemy.height);


if(rect1.intersects(rect2))
{

System.out.println("game over, g");
}

obviously you'd need to fit that in somewhere.

Shahin
This is what I was getting at. Java does have intersect, but I am struggling to apply it to the code I already have. Would I have to define the rectangle inside player() and enemy()?
EnderMB
No.. I've not used the painting stuff in java before, but you should definately have an object like "Creature", and then create instances of Creature i.e. player/enemy or make them subclasses which you create instances of. Create object should contain all that's needed for an Update/Draw NoCharsLeft
Shahin
+1  A: 

You don't want to have the collision check code inside the painting code. The painting needs to be fast. Collision can go in the game loop. Therefore you need an internal representation of the objects independent of their sprites.

Karl
A: 

Since Java doesn't have an intersect function (really!?) you can do collision detection by simply comparying the X and Y, Width and Height values of the bounding boxes (rectangle) for each of the objects that could potentially collide.

So... in the base object of each colliding object... i.e. if your player and enemy have a common base you can put a simple Rectangle object called something like BoundingBox. If the common base is a built in Java class then you'll need to create a class that extends the build in class and have the player and enemy objects extend your new class or are instances of that class.

At creation (and each tick or update) you'll need to set the BoundingBox paremeters for both your player and enemy. I don't have the Rectangle class infront of me but its most likely something like X, Y, Width and finally Height. X and Y are that objects location in your game world. The width and height are self explanatory I think. They'll most likely come out from the right of the players location though so, if the X and Y were bothe at 0 and your Width and Height were both at 256 you wouldn't see anything because the character would be at the top left outside of the screen.

Anyways... to detect a collision, you'll want to compare the attributes of the player and enemy BoundingBoxes. So something like this...

 if( Player.BoundingBox.X = Enemy.BoundingBox.X && If( Player.BoundingBox.Y = Enemy.BoundingBox.Y )
 {
      //Oh noes!  The enemy and player are on top of eachother.
 }

The logic can get sort of complicated but you'll need to compare the distances between each BoundingBox and compare locations.

Dalin Seivewright
Java does have an intersect method: http://java.sun.com/javase/6/docs/api/java/awt/Rectangle.html#intersects(java.awt.Rectangle) .
Michael Myers
Argh, can't get the last ) to be included in the link. Sorry.
Michael Myers
A: 

Here's a useful of an open source game that uses a lot of collisions: http://robocode.sourceforge.net/

You may take a look at the code and complement with the answers written here.

OscarRyz
+3  A: 

I think your problem is that you are not using good OO design for your player and enemies. Create two classes:

public class Player
{
    int X;
    int Y;
    int Width;
    int Height;

    // Getters and Setters
}

public class Enemy
{
    int X;
    int Y;
    int Width;
    int Height;

    // Getters and Setters
}

Your Player should have X,Y,Width,and Height variables.

Your enemies should as well.

In your game loop, do something like this (C#):

foreach (Enemy e in EnemyCollection)
{
    Rectangle r = new Rectangle(e.X,e.Y,e.Width,e.Height);
    Rectangle p = new Rectangle(player.X,player.Y,player.Width,player.Height);

    // Assuming there is an intersect method, otherwise just handcompare the values
    if (r.Intersects(p))
    {
       // A Collision!
       // we know which enemy (e), so we can call e.DoCollision();
       e.DoCollision();
    }
}

To speed things up, don't bother checking if the enemies coords are offscreen.

FlySwat
Correct. My OO skills are dreadful, and the majority of my game exists in one file. Your method works, but I've got a lot of work in trying to separate this one file into its respective classes.
EnderMB
+1  A: 

First, use the bounding boxes as described by Jonathan Holland to find if you may have a collision.

From the (multi-color) sprites, create black and white versions. You probably already have these if your sprites are transparent (i.e. there are places which are inside the bounding box but you can still see the background). These are "masks".

Use Image.getRGB() on the mask to get at the pixels. For each pixel which isn't transparent, set a bit in an integer array (playerArray and enemyArray below). The size of the array is height if width <= 32 pixels, (width+31)/32*height otherwise. The code below is for width <= 32.

If you have a collision of the bounding boxes, do this:

// Find the first line where the two sprites might overlap
int linePlayer, lineEnemy;
if (player.y <= enemy.y) {
    linePlayer = enemy.y - player.y;
    lineEnemy = 0;
} else {
    linePlayer = 0;
    lineEnemy = player.y - enemy.y;
}
int line = Math.max(linePlayer, lineEnemy);

// Get the shift between the two
x = player.x - enemy.x;
int maxLines = Math.max(player.height, enemy.height);
for ( line < maxLines; line ++) {
    // if width > 32, then you need a second loop here
    long playerMask = playerArray[linePlayer];
    long enemyMask = enemyArray[lineEnemy];
    // Reproduce the shift between the two sprites
    if (x < 0) playerMask << (-x);
    else enemyMask << x;
    // If the two masks have common bits, binary AND will return != 0
    if ((playerMask & enemyMask) != 0) {
        // Contact!
    }

}

Links: JGame, Framework for Small Java Games

Aaron Digulla