Skip to content

Instantly share code, notes, and snippets.

@MarcinKonowalczyk
Created January 18, 2021 02:49
Show Gist options
  • Save MarcinKonowalczyk/a89b82a7712bf49dbd7efa599374c70b to your computer and use it in GitHub Desktop.
Save MarcinKonowalczyk/a89b82a7712bf49dbd7efa599374c70b to your computer and use it in GitHub Desktop.
[Processing] Fast collision detection between axis-aligned rectangle and a circle
Circle c;
Rectangle r;
void setup() {
size(500,500);
frameRate(600);
rectMode(CORNERS);
c = new Circle(width/2, height/2, 80);
r = new Rectangle(width/2, height/2, 160, 80);
}
void draw() {
// Background
fill(#c1c1c1); noStroke();
rect(0,0,width,height);
// Draw rectangle
r.show();
// Update circle position
c.move(mouseX,mouseY);
// Collide calc + draw shadows
boolean result = collide(c,r);
c.state = result;
// Draw circle
c.show();
// Draw info text
draw_info_text(result);
}
void keyPressed() {
if (keyCode == UP) {
; //r.move(r.center.add;
} else if (keyCode == DOWN) {
; // delta_time = max(delta_time-0.1,0.5);
} else if (keyCode == LEFT) {
; // neighbour_radius = max(neighbour_radius-5,10);
} else if (keyCode == RIGHT) {
; // neighbour_radius = min(neighbour_radius+5,100);
}
}
//////////////
// COLLIDER //
//////////////
boolean collide(Circle circ, Rectangle rect) {
boolean result = false;
float cx = circ.center.x;
float cy = circ.center.y;
float r = circ.radius;
float r2 = circ.radius_squared;
float[] edges = rect.edges();
float vl = edges[0]; float vr = edges[1];
float ht = edges[2]; float hb = edges[3];
// I - top left of the top corner
// II - top, between top left and top right corners
// III - top right of the top right corner
// IV - left, between top left and bottom left corners
// V - center (trivial case)
// VI - right, between top right and top bottom right corner
// VII - bottom left of the bottom left corner
// VIII - bottom, between bottom left and bottom right corner
// IX - bottom right of the bottom right corner
fill(#111111,30);
if (cx<vl) { // I, IV or VII
if (cy<ht) { // I
result = sq(vl-cx)+sq(ht-cy) < r2;
rect(0,0,vl,ht); arc(vl, ht, 2*r, 2*r, PI, PI+HALF_PI);
} else if (cy<hb) { // IV
result = cx>(vl-r);
rect(0,ht,vl,hb); rect(vl-r,ht,vl,hb);
} else { // VII
result = sq(vl-cx)+sq(hb-cy) < r2;
rect(0,hb,vl,height); arc(vl, hb, 2*r, 2*r, HALF_PI, PI);
}
} else if (cx<vr) { // II, V or VII
if (cy<ht) { // II
result = cy>(ht-r);
rect(vl,0,vr,ht); rect(vl,ht-r,vr,ht);
} else if (cy<hb) { // V
result = true;
rect(vl,ht,vr,hb);
} else { // VIII
result = cy<(hb+r);
rect(vl,hb,vr,height); rect(vl,hb,vr,hb+r);
}
} else { // III, VI or IX
if (cy<ht) { // III
result = sq(vr-cx)+sq(ht-cy) < r2;
rect(vr,0,width,ht); arc(vr, ht, 2*r, 2*r, PI+HALF_PI, TWO_PI);
} else if (cy<hb) { // VI
result = cx<(vr+r);
rect(vr,ht,width,hb); rect(vr,ht,vr+r,hb);
} else { // IX
result = sq(vr-cx)+sq(hb-cy) < r2;
rect(vr,hb,width,height); arc(vr, hb, 2*r, 2*r, 0, HALF_PI);
}
}
return result;
}
////////////
// SHAPES //
////////////
class Point {
float x,y;
Point(float x, float y) {
this.x = x;
this.y = y;
}
}
class Circle {
Point center;
float radius, radius_squared;
boolean state = false;
Circle(float cx, float cy, float r) {
center = new Point(cx,cy);
radius = r;
radius_squared = r*r;
}
void move(float x, float y) {
center.x = x; center.y = y;
}
void show() {
push();
stroke(#121212); strokeWeight(1.5);
color c;
if (state) {c = color(#c2452c,150);}
else {c = color(#45acc2,150);}
fill(c);
ellipse(center.x,center.y,2*radius,2*radius);
strokeWeight(2.5);
point(center.x,center.y);
pop();
}
}
class Rectangle {
Point center = new Point(0,0); // Needs to be initialised here
float width, height;
float vl, vr, ht, hb; // Edges (no need to recalculate these)
Rectangle(float cx, float cy, float w, float h) {
width = w;
height = h;
move(cx,cy);
}
void move(float x, float y) {
center.x = x; center.y = y;
recalculate_edges();
}
void recalculate_edges() {
vl = center.x - width/2;
vr = center.x + width/2;
ht = center.y - height/2;
hb = center.y + height/2;
}
void show() {
push();
stroke(#121212); strokeWeight(1.5);
fill(#acc245,150);
rectMode(CORNER);
rect(center.x-width/2,center.x-height/2,width,height);
strokeWeight(2.5);
point(center.x,center.y);
pop();
}
float[] edges() {
// Bounding edges
// Vertical left, V. right, Horizontal top, H. bottom
return new float[] {vl,vr,ht,hb};
}
Point[] corners() {
// Rectangle corners
// Top left, Top right, Bottom right, Bottom left
float[] e = edges();
return new Point[] {
new Point(e[0],e[2]), // top-left
new Point(e[1],e[2]), // top-right
new Point(e[1],e[3]), // bottom-right
new Point(e[0],e[3]) // bottom-left
};
}
}
/////////////
// HELPERS //
/////////////
void draw_info_text(boolean result) {
push();
fill(128);
strokeWeight(2.5);
textSize(12);
textAlign(RIGHT, TOP);
String t = "fps: " + nf(frameRate,3,-1) + "\n";
if (result) {t += "Collision";}
else {t += "No collision";}
text(t, width-5, 0+5);
pop();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment