Collision Detection With Complex Shapes

Collision detection with complex shapes

..there will be complex corners and not everything will be rectangle.

This could be achieved by drawing and dealing with Shape and Area instances. E.G.

  • Yellow is a little animated 'player'.
  • The bounds of the image represent walls that contain the path of the player (it bounces off them).
  • Obstacles are painted green when not in collision, red otherwise.

ShapeCollision

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import javax.swing.*;

class ShapeCollision {

private BufferedImage img;
private Area[] obstacles = new Area[4];
private Area walls;

int x;
int y;
int xDelta = 3;
int yDelta = 2;

/** A method to determine if two instances of Area intersect */
public boolean doAreasCollide(Area area1, Area area2) {
boolean collide = false;

Area collide1 = new Area(area1);
collide1.subtract(area2);
if (!collide1.equals(area1)) {
collide = true;
}

Area collide2 = new Area(area2);
collide2.subtract(area1);
if (!collide2.equals(area2)) {
collide = true;
}

return collide;
}

ShapeCollision() {
int w = 400;
int h = 200;
img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
final JLabel imageLabel = new JLabel(new ImageIcon(img));
x = w/2;
y = h/2;

//circle
obstacles[0] = new Area(new Ellipse2D.Double(40, 40, 30, 30));

int[] xTriangle = {330,360,345};
int[] yTriangle = {60,60,40};
//triangle
obstacles[1] = new Area(new Polygon(xTriangle, yTriangle, 3));

int[] xDiamond = {60,80,60,40};
int[] yDiamond = {120,140,160,140};
//diamond
obstacles[2] = new Area(new Polygon(xDiamond, yDiamond, 4));

int[] xOther = {360,340,360,340};
int[] yOther = {130,110,170,150};
// other
obstacles[3] = new Area(new Polygon(xOther, yOther, 4));

walls = new Area(new Rectangle(0,0,w,h));

ActionListener animate = new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
animate();
imageLabel.repaint();
}
};
Timer timer = new Timer(50, animate);

timer.start();
JOptionPane.showMessageDialog(null, imageLabel);
timer.stop();
}

public void animate() {
Graphics2D g = img.createGraphics();
g.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);

g.setColor(Color.BLUE);
g.fillRect(0, 0, img.getWidth(), img.getHeight());
x+=xDelta;
y+=yDelta;
int s = 15;
Area player = new Area(new Ellipse2D.Double(x, y, s, s));

// Acid test of edge collision;
if (doAreasCollide(player,walls)) {
if ( x+s>img.getWidth() || x<0 ) {
xDelta *= -1;
}
if(y+s>img.getHeight() || y<0 ) {
yDelta *= -1;
}
}
g.setColor(Color.ORANGE);
for (Area obstacle : obstacles) {
if (doAreasCollide(obstacle, player)) {
g.setColor(Color.RED);
} else {
g.setColor(Color.GREEN);
}
g.fill(obstacle);
}

g.setColor(Color.YELLOW);
g.fill(player);


g.dispose();
}

public static void main(String[] args) {
Runnable r = new Runnable() {

@Override
public void run() {
new ShapeCollision();
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
SwingUtilities.invokeLater(r);
}
}

Edit

make it detect all the red color and set that as the collision bounds

At start-up, use the source seen in the Smoothing a jagged path question to get an outline of the red pixels (see the getOutline(Color target, BufferedImage bi) method). Store that Area as the single obstacle on start-up.

How do detect collision for a complex shape like a game character?

Your questions isn't really a javascript or html question directly but..

1) There are multiple options how to detect if two objects are colliding. One (and simple) solution is called AABB Collision Detection (good video tutorial)

2) There is a good Answer already on stackoverflow: Collision detection with complex shapes

3) There are plenty of good game frameworks (take a look at this list) doing collision detection for you. Are you sure you want to do it by your own?

Collision detection of irregular shapes

This is not a simple stuff. If you are satisfied that a function can tell if two polygons are colliding (and you can roll back them), then the solution is not so hard. You just need to check if any two of the polygon's sides are crossing each other or not. This can be done by some math, and with big shapes or lot polygons it can eat away the performance. To solve this, you may use space partitioning and bounding volumes.

UPDATE:
You can calculate the intersection of lines based on this. Then you need to check if this point is in both segment or not. To do this, you can use the endpoints of the segments, and the ua and ub variables will be between 0-1 if the segment actually contains the point.

Alternative solution to my collision detection with complex shapes?

I ended up going with a manual solution. My solution requires the user to define the points. More points = smooth. Less points = more polygon like.

Hittest for two object shapes

Here is a snippet of code I found in ActionScript 3 (https://snipplr.com/view/90435/pixel-perfect-collision-detection-as3/) that looks like it should work in OpenFL.

A Haxe version of the code might look like this:

public function objectsHit (mc1:DisplayObject, mc2:DisplayObject):Bool {

var mc1bounds = mc1.getBounds (this);
var mc2bounds = mc2.getBounds (this);
var allintersections = (mc2bounds.intersection(mc1bounds));

for (xval in allintersections.x...(allintersections.x + allintersections.width)) {
for (yval in allintersections.y...(allintersections.y + allintersections.height)) {
if (mc2.hitTestPoint (xval, yval, true) && mc1.hitTestPoint (xval, yval, true)) {
return true;
}
}
}

return false;
}

It might also be possible to use the hitTestObject method first, then to use the hitTestPoint method second. The general idea is to perform bounding box hit detection first, then to perform point-based collision (which is more expensive) if you need something more exact.

Collision with image (irregular shape)

You need to implement colliders. They are ready to use in game-engines such Unity, but if you want to implement this yourself consider the following:

  1. Create colliders components for your bird and walls. Collidiers are simplified shapes to make collision detection algorithms easier and faster regarding to CPU speed. For example, for bird it can be circle around it and rectangles for your walls.
  2. During your Update frame event check whether your bounding circle of bird intersects with wall rectangles. It is simple mathematics, you can find formulas for "circle rectangle intersection" in google.
  3. If collision is detected - your bird should crash down )

That's it!



Related Topics



Leave a reply



Submit