In a game I wrote some years ago we handled simple rectangular collisions. Given the points:
We did:
// returning 0 means collision
int collision(int ax, int ay, int bx, int by, int cx, int cy, int dx, int dy){
return ((ax > dx)||(bx < cx)||(ay > dy)||(by < cy));
}
I'll show here a little demo about how implement simple rectangular collisions on JavaFX.
First I created a movable rectangle using the same idea of draggable nodes I already had posted before.
import javafx.input.MouseEvent;
import javafx.scene.geometry.Rectangle;
public class MovableRectangle extends Rectangle {
private attribute startX = 0.0;
private attribute startY = 0.0;
public attribute onMove = function(e:MouseEvent):Void {}
override attribute onMousePressed = function(e:MouseEvent):Void {
startX = e.getDragX()-translateX;
startY = e.getDragY()-translateY;
onMove(e);
}
override attribute onMouseDragged = function(e:MouseEvent):Void {
translateX = e.getDragX()-startX;
translateY = e.getDragY()-startY;
onMove(e);
}
}
In the main code I some important things:
- colide, a color that represents the collision effect. White means no collision and gray means collision.
- rec1 and rec2, the two rectangles that can collide.
- checkcollision() the function that checks and handles a possible collision.
Here is the main code:
import javafx.application.Frame;
import javafx.application.Stage;
import javafx.scene.geometry.Rectangle;
import javafx.scene.paint.Color;
import javafx.input.MouseEvent;
var colide = Color.WHITE;
function checkcollision():Void {
if (
(rec1.getBoundsX() > rec2.getBoundsX() + rec2.getWidth()) or
(rec1.getBoundsX() + rec1.getWidth() < rec2.getBoundsX()) or
(rec1.getBoundsY() > rec2.getBoundsY() + rec2.getHeight()) or
(rec1.getBoundsY() + rec1.getHeight() < rec2.getBoundsY())
) {
colide = Color.WHITE
} else {
colide = Color.LIGHTGRAY
}
}
var rec1: MovableRectangle = MovableRectangle {
x: 10, y: 10, width: 50, height: 60, fill: Color.RED
onMove: function(e:MouseEvent):Void {
checkcollision()
}
}
var rec2: MovableRectangle = MovableRectangle {
x: 100, y: 100, width: 70, height: 30, fill: Color.BLUE
onMove: function(MouseEvent):Void {
checkcollision()
}
}
Frame {
title: "Rectangular Collisions", width: 300, height: 300
closeAction: function() {
java.lang.System.exit( 0 );
}
visible: true
stage: Stage {
fill: bind colide
content: [rec1, rec2]
}
}
Try it via Java Web Start:
Some considerations:
- You can use rectangular collisions to create bounding boxes to handle collisions in more complex shapes or sprites. Is a common approach in 2d games to avoid more expensive calculations.
- There are space for optimizations.
- In this case I'm using only two objects. Some problems raises when I have N objects to handle.
More generally, we can code:
function collission(ax, ay, bx, by, cx, cy, dx, dy): Boolean {
return not ((ax > dx)or(bx < cx)or(ay > dy)or(by < cy));
}
function hitnode(a: Node, b:Node): Boolean{
return (collission(
a.getBoundsX(), a.getBoundsY(),
a.getBoundsX() + a.getWidth(), a.getBoundsY() + a.getHeight(),
b.getX(), b.getY(),
b.getX() + b.getWidth(), b.getY() + b.getHeight()
));
}
This way we can pass just two bounding boxes to hitnode and easily check collision of a node against a list of bounding boxes nodes.
Using the same approach I also wrote this function to test if a Node is inside another Node:
function inside (ax, ay, bx, by, cx, cy, dx, dy):Boolean{
return ((ax > cx) and (bx < dx) and (ay > cy) and (by < dy));
}
function insidenode(a:Node,b:Node):Boolean{
return (inside(
a.getBoundsX(), a.getBoundsY(),
a.getBoundsX() + a.getWidth(), a.getBoundsY() + a.getHeight(),
b.getBoundsX(), b.getBoundsY(),
b.getBoundsX() + b.getWidth(), b.getBoundsY() + b.getHeight()
));
}
Soon I'll post game examples showing how to use this method and others collission detection methods.
Downloads:
- The original video, javafx_rectangular_collision_detection.ogg
- NetBeans 6.1 Project with sources, javafx_rec_col.tar.gz. Needs JavaFX module installed.