I am working on a Pong-like game, and have implemented the code that moves the paddle (via user input) and the ball. I am currently working on the code for the collision between the ball and the paddle.
Everything seems to be working fine, except when I move the paddle directly onto the ball. This means that the ball collides with the bottom part or top part of the paddle, instead of the side of the paddle, which results in the ball getting stuck inside the paddle and stuttering rapidly.
I know that the motion is caused by the ball changing velocity every frame. I am still having trouble figuring out how to solve it.
I have tried implement a boolean variable to determine whether or not the ball already collided with the paddle during a frame. However, I am having some trouble going about implementing this logic into my code. In my main class, you will see some comments pointing out this boolean variable and what I intended to do with it.
Below are some of the major code snippets pertaining to my problem.
MainApp:
// ...
new AnimationTimer() {
#Override
public void handle(long currentTime) {
ballInfo.setText("Ball (" + ball.getX() + ", " + ball.getY() + ")");
leftPaddleInfo.setText("Left Paddle (" + leftPaddle.getX() + ", " + leftPaddle.getY() + ")");
rightPaddleInfo.setText("Right Paddle (" + rightPaddle.getX() + ", " + rightPaddle.getY() + ")");
// Give point and reset ball.
if (ball.didCollideWithLeftWall(canvas)) {
givePoint(rightPaddle);
rightPaddleScore = rightPaddle.getPoints();
rightPaddleScoreLabel.setText("Player 2 Score: " + rightPaddleScore);
reset();
}
if (ball.didCollideWithRightWall(canvas)) {
givePoint(leftPaddle);
leftPaddleScore = leftPaddle.getPoints();
leftPaddleScoreLabel.setText("Player 1 Score: " + leftPaddleScore);
reset();
}
// Handle bouncing off of top and bottom walls
ball.didCollideWithWalls(canvas);
// Keep paddle in screen bounds
if (leftPaddle.getY() <= canvasBounds.getMinY() + 5)
leftPaddle.setY(canvasBounds.getMinY() + 5);
if (leftPaddle.getY() >= canvasBounds.getMaxY() - 105)
leftPaddle.setY(canvasBounds.getMaxY() - 105);
if (rightPaddle.getY() <= canvasBounds.getMinY() + 5)
rightPaddle.setY(canvasBounds.getMinY() + 5);
if (rightPaddle.getY() >= canvasBounds.getMaxY() - 105)
rightPaddle.setY(canvasBounds.getMaxY() - 105);
if (leftPaddle.didCollideWith(ball)) {
ball.setvX(-ball.getvX());
ball.setX(ball.getX() + ball.getvX());
}
if (rightPaddle.didCollideWith(ball)) {
ball.setvX(-ball.getvX());
ball.setX(ball.getX() + ball.getvX());
}
// Update and render
ball.update(ELAPSED_TIME_SPEED);
leftPaddle.update(ELAPSED_TIME_SPEED);
rightPaddle.update(ELAPSED_TIME_SPEED);
gc.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
gc.setFill(BALL_COLOR);
ball.render(gc);
gc.setFill(LEFT_PADDLE_COLOR);
leftPaddle.render(gc);
gc.setFill(RIGHT_PADDLE_COLOR);
rightPaddle.render(gc);
}
}.start();
Paddle:
#Override
public boolean didCollideWith(Sprite other) {
Ball ball = (Ball) other;
double ballCenterX = ball.getCenterX();
double ballRadius = ball.getRadius();
double ballCenterY = ball.getCenterY();
double halfWidth = this.getHalfWidth();
double halfHeight = this.getHalfHeight();
double centerX = this.getCenterX();
double centerY = this.getCenterY();
if (getName().toLowerCase().equals("left")) {
boolean hitXBounds = ballCenterX - ballRadius <= centerX + halfWidth
&& ballCenterX - ballRadius >= centerX - halfWidth;
boolean hitTopPartOfBall = ballCenterY - ballRadius <= centerY + halfHeight
&& ballCenterY - ballRadius >= centerY - halfHeight;
boolean hitBotPartOfBall = ballCenterY + ballRadius <= centerY + halfHeight
&& ballCenterY + ballRadius >= centerY - halfHeight;
return hitXBounds && (hitTopPartOfBall || hitBotPartOfBall);
}
if (getName().toLowerCase().equals("right")) {
boolean hitXBounds = ballCenterX + ballRadius >= centerX - halfWidth
&& ballCenterX + ballRadius <= centerX + halfWidth;
boolean hitTopPartOfBall = ballCenterY - ballRadius <= centerY + halfHeight
&& ballCenterY - ballRadius >= centerY - halfHeight;
boolean hitBotPartOfBall = ballCenterY + ballRadius <= centerY + halfHeight
&& ballCenterY + ballRadius >= centerY - halfHeight;
return hitXBounds && (hitTopPartOfBall || hitBotPartOfBall);
}
return false;
}
Thank you!
EDIT
I have somewhat fixed the collision code in the Paddle class, so that now it is much more difficult to perform the mentioned bug. However, I am still getting the stuttering bug if the, for instance, the leftmost point of the ball comes right into contact with the rightmost point of the left paddle. If I were to time it just right, I can still get the ball stuck inside the paddle the same way as I could before (by moving it directly on top of/ bottom of it), but it will only create this bug IF the ball is still in front of the paddle.
I have changed the code above as well.
Related
I will keep this quick.
Just making a processing program where the ball bounces off the rectangle.
At the moment I can only figure out how to do the top,left,right and bottom sides but when the ball goes into the corners of the rectangle, it doesn't bounce off but instead goes into the rectangle and after 1 or 2 bounces gets realeased.
I just really want to know how I should go about making the ball deflect off the corners of the rectangle so it doens't glitch
Here is my code :
float x = 100, y = 100, radius = 50;
float vx = 3, vy = 3;
float MX = 0;
float MY = 0;
void setup() {
size(500, 700);
}
void draw() {
background(0);
fill(255);
x += vx;
y += vy;
if (x + radius > width) {
vx = vx * -1;
}
//makes the ball bounce off the right
if (x - radius < 0) {
vx = vx * -1;
}
//makes the ball bounce off the left
if (y + radius > height) {
vy = vy * -1;
y = height - radius;
}
//make the ball bounce off the top
if (y - radius < 0) {
vy = vy * -1;
y = radius;
}
//makes the ball bounce off the top
if (y + radius > MY && x + radius > MX + 50 && x + radius < MX + 150 &&
y + radius < MY + 20) {
vy *= -1;
y = MY - 3 - radius;
} //Top Side
if (x - radius < MX + 100 && y > MY - 10 && y < MY + 10 && x - radius > MX) {
vx *= -1;
} // Right Side
if (y - radius < MY + 20 && x + radius > MX + 50 && x + radius < MX + 150 &&
y - radius > MY) {
vy *= -1;
y = MY + 20 + radius;
} //Bottom Side
if (x + radius > MX && y > MY - 10 && y < MY + 10 && x + radius < MX + 100) {
vx *= -1;
} // Left Side
ellipse(x, y, radius * 2, radius * 2);
rect(MX, MY, 100, 20);
}
void mouseMoved() {
MX = mouseX - 50;
MY = mouseY - 10;
if (MX < 0) {
MX = 0;
}
if (MX > 400) {
MX = 400;
}
if (MY < 0) {
MY = 0;
}
if (MY > 680) {
MY = 680;
}
Sorry I do know know how to insert the code very well, I am new to this site, please have mercy haha :)
Cheers
The problem is not that you need to detect corner collision. You've got two other problems:
Problem 1: When you detect a collision, you need to move the ball so it's not colliding with the rectangle anymore.
If you don't, then when the ball intersects the top of the box, you multiply the vy variable by -1. That causes the circle to start moving up. But the next frame, the circle is still colliding with the rectangle, because it hasn't moved up enough yet. So your code detects that collision, multiples vy by -1 again, and the ball moves back down. Next frame the same thing happens, until the ball eventually stop colliding with the rectangle.
Slow the framerate down to see what I'm talking about:
To fix this, you need to "pop" the ball back to a location that's no longer intersecting with the rectangle. That way you know it won't still be colliding in the next frame.
Problem 2: You shouldn't do collision on each side separately. Instead, do collisions between the entire circle and the entire rectangle, and then check one axis of movement at a time.
Checking against one side at a time will lead to plenty of headaches, including the problem where multiple sides are hit at one time. I would also bet that your code isn't doing what you think it is: try adding println() statements to all of your if statements to make sure they're executing when you think they are.
To fix this problem, I would create a collides() function that takes parameters for the next position of the ball, and returns whether the ball will be colliding with any side of the rectangle. Then pass in the next X and Y positions and flip their speeds. It'll look something like this:
if (collides(circleX + vx, circleY)) {
vx*=-1;
}
else {
circleX += vx;
}
if (collides(circleX, circleY + vy)) {
vy*=-1;
}
else {
circleY += vy;
}
You'd also want to add the logic for "popping" the ball so it's no longer colliding.
PS: Did you try searching for your problem on google or the Stack Overflow search? This question is almost an exact duplicate of your question, to the point where I'm pretty sure you're in the same class!
A quick dirty way i have previously achieved this is by first adding bounding boxes to each side and positioning them in a way that if the ball collides with for example on the top right corner i would then have a condition:
If ball intercepts bounds top and bounds right: do this;
I hope this helps!
I am trying to create a class in Java which will add a simple box shadow to any given UI element. Normally, it displays correctly, however when it is applied to a button, the shadow gets darker each time the mouse enters or exits the button.
The paint function is as follows:
public void paint(Graphics g)
{
Rectangle bounds = g.getClipBounds();
g.setClip(bounds.x + (SHADOW_OFFSET + shadowOffsetMod) - (SHADOW_SIZE + shadowSizeMod), bounds.y + (SHADOW_OFFSET + shadowOffsetMod) - (SHADOW_SIZE + shadowSizeMod),
bounds.width + 2 * (SHADOW_SIZE + shadowSizeMod), bounds.height + 2 * (SHADOW_SIZE + shadowSizeMod));
int red = UIConstants.SHADOW_COLOR.getRed();
int green = UIConstants.SHADOW_COLOR.getGreen();
int blue = UIConstants.SHADOW_COLOR.getBlue();
int alpha = UIConstants.SHADOW_COLOR.getAlpha();
for (int x = (SHADOW_OFFSET + shadowOffsetMod) - (SHADOW_SIZE + shadowSizeMod); x < bounds.width + (SHADOW_OFFSET + shadowOffsetMod) + (SHADOW_SIZE + shadowSizeMod); x++)
{
for (int y = (SHADOW_OFFSET + shadowOffsetMod) - (SHADOW_SIZE + shadowSizeMod); y < bounds.width + (SHADOW_OFFSET + shadowOffsetMod) + (SHADOW_SIZE + shadowSizeMod); y++)
{
int dx = Math.abs(x - Math.max(Math.min(x, bounds.width + (SHADOW_OFFSET + shadowOffsetMod)), (SHADOW_OFFSET + shadowOffsetMod)));
int dy = Math.abs(y - Math.max(Math.min(y, bounds.height + (SHADOW_OFFSET + shadowOffsetMod)), (SHADOW_OFFSET + shadowOffsetMod)));
float dist = (float) Math.sqrt(dx * dx + dy * dy);
dist /= (SHADOW_SIZE + shadowSizeMod);
if (dist > 1)
dist = 1;
dist = 1 - dist;
g.setColor(new Color(red, green, blue, ((float)alpha * dist) / 255));
g.fillRect(x, y, 1, 1);
}
}
g.setClip(bounds);
super.paint(g);
}
the shadow gets darker each time the mouse enters or exits the button.
Not sure exactly how your code is used. But (assuming you are usign Swing) this is a problem resulting from using a background color with transparency.
Swing components are either
opaque, in which case they guarantee to paint the background
non-opaque, in which case the parent component is used to paint the background.
In your case it sounds like the component is opaque, but the background is transparent so you break rule and you have painting issues.
Check out Backgrouds With Transparency fore more information and a couple of solutions:
make the component non-opaque and paint the background yourself
use a custom component as a wrapper to paint the background for you.
I made a simple breakout game for Android, and I have some problems when the ball reaches the bar (paddle). ball, bar are bitmaps. x,y are the positions of the ball, bx and by are the positions of the bar (paddle). speedX and speedY are the speed of the ball. this isn't a very nice solution. Where can I change the code?
if (y + ball.getHeight() >= c.getHeight()
- (10 + bar.getHeight())
&& (x + ball.getWidth() / 2) >= bx - bar.getWidth() / 2
&& (x + ball.getWidth() / 2) <= bx + bar.getWidth() / 2) {
mp.start();
xdirection = (((x + ball.getWidth()) / 2) - ((bx + bar
.getWidth())) / 2) / (bar.getWidth() / 2);
speedY = -speedY;
speedX = (speedX) * Math.abs(xdirection);
I jumped into Processing (the language) today. I've been trying to implement a line without the line() function. In other words, I'm trying to replicate the line() function with my own code. I'm almost there, but not. (There's a screen, and you can click around, and this function connects those clicks with lines.)
There are four different line slopes I'm dealing with (m>1, 0
If you could just glance at the following code, and tell me where I've gone wrong, I'd be grateful.
int xStart = -1; // Starting x and y are negative.
int yStart = -1; // No lines are drawn when mouseReleased() and x/y are negative.
boolean isReset = false; // Turns true when 'r' is pressed to reset polygon chain.
int clickCounter = 0; // Changes background color every 10 clicks (after c is pressed).
color backgroundColor = 0; // Starting background color. Changed occasionally.
color lineColor = 255;
int weight = 1;
void setup() {
size(800, 800); // Initial size is 800x800
background(backgroundColor); // ...background is black.
smooth();
stroke(lineColor); //... lines/points are white.
strokeWeight(weight);
}
void draw() {
}
void mousePressed(){
clickCounter++;
}
void mouseReleased(){ // mouseReleased used instead of mousePressed to avoid dragged clicks.
point(mouseX, mouseY); // Draws white point at clicked coordinates.
if((xStart < 0 && yStart < 0) || isReset){ // If x/y negative or if r was pressed, set start points and return. No line drawn.
xStart = mouseX;
yStart = mouseY;
isReset = false; // Reset isReset to false.
return;
}
// Sends starting and ending points to createLine function.
createLine(xStart, yStart, mouseX, mouseY); // createLine(...) - Creates line from start point to end point.
xStart = mouseX; // Start point = last click location. End point = Current click location.
yStart = mouseY; // Sets starting coordinates for next click at current click point.
}
void keyPressed(){
if(key == 'x') // EXTRA CREDIT ADDITION: If x is pressed -> Exit program.
exit();
else if(key == 'c'){ // EXTRA CREDIT ADDITTION: If c pressed -> Set background black to clear all lines/points on screen.
if(clickCounter > 10){
backgroundColor = color(random(255), random(255), random(255)); // EXTRA CREDIT ADDITION: If cleared and clickCounter is greater
clickCounter = 0; // ...than 10, background changes to random color.
}
background(backgroundColor);
xStart = -1; // Must set points negative so line is not drawn after next new point is made (since there will only be one point on the screen).
yStart = -1;
}
else if(key == 'r'){ // If r pressed -> Reset: Next click will create new point that isn't connected with line to current points.
isReset = true;
lineColor = color(random(255), random(255), random(255)); // EXTRA CREDIT ADDITION: When dot chain is "reset", line changes color.
weight = (int)random(10);
strokeWeight(weight); // EXTRA CREDIT ADDITION: ...and line/dot thickness changes.
stroke(lineColor);
}
else
return;
}
// createLine(): Function which draws line from (x0,y0) to (x1,y1).
void createLine(int x0, int y0, int x1, int y1){
// 1) Line function draws from left to right. (Does not work right to left.) Check and swap points if ending point is left of starting point.
if(x1 < x0){
print("LEFT TO RIGHT SWITCH. \n");
createLine(x1, y1, x0, y0); // Drawing the line left to right cuts the number of line types we have to deal with to 4 regions.
return; // Regions: slope > 1; 0 < slope < 1; -1 < slope < 0; slope < -1.
}
// Declare/Initialize data needed to draw line with midpoint algorithm.
int dx = x1 - x0;
int dy = y1 - y0; //dy = Negative when y0 is lower on screen than y2, because origin is top left.
print(y0 + " " + x0 + " " +y1 + " " + x1+ " x y \n");
print(dy + " " + dx + " dx dy\n");
// Handle vertical & horizontal lines...
if(dx == 0 || dy == 0){ // If slope is vertical or horizontal, create line with simple function.
while(y1 != y0){ // If vertical -> Paint by incrementing/decrementing y until points connect.
if(y1 > y0){ // If new point is above -> Draw upwards.
y0 = y0 + 1;
point(x0, y0);
}
else{ // It new point below -> Draw downwards.
y0 = y0 - 1;
point(x0, y0);
}
}
while(x1 != x0){ // If horizontal -> Paint by incrementing x until points connect (will be left to right line always).
x0 = x0 + 1;
point(x0, y0);
}
return;
}
// Handle slanted lines...
double tempDX = x1 - x0;
double tempDY = y1 - y0; // Had to create dx and dy as doubles because typecasting dy/dx to a double data type wasn't working.
double m = (-tempDY / tempDX); // m = line slope. (Note - The dy value is negative because positive y is downwards on the screen.)
print("SLOPE CALCULATED: " + m + "\n");
int deltaN = (2 * -dx); // deltaX is the amount to increment d after choosing the next pixel on the line.
int deltaNE = (2 * (-dy - dx)); // ...where X is the direction moved for that next pixel.
int deltaE = (2 * -dy); // deltaX variables are used below to plot line.
int deltaSE = (2 * (dy + dx));
int deltaS = (2 * dx);
int x = x0;
int y = y0;
int d = 0; // d = Amount d-value changes from pixel to pixel. Depends on slope.
int region = 0; // region = Variable to store slope region. Different regions require different formulas.
if(m > 1){ // if-statement: Initializes d, depending on the slope of the line.
d = -dy - (2 * dx); // If slope is 1-Infiniti. -> Use NE/N initialization for d.
region = 1;
}
else if(m == 1)
region = 2;
else if(m > 0 && m < 1){
d = (2 * -dy) - dx; // If slope is 0-1 -> Use NE/E initialization for d.
region = 3;
}
else if(m < 0 && m > -1){
d = (2 * dy) + dx; // If slope is 0-(-1) -> Use E/SE initliazation for d.
region = 4;
}
else if(m == -1)
region = 5;
else if(m < -1){
d = dy + (2 * dx); // If slope is (-1)-(-Infiniti) -> Use SE/S initialization for d.
region = 6;
}
while(x < x1){ // Until points are connected...
if(region == 1){ // If in region one...
if(d <= 0){ // and d<=0...
d += deltaNE; // Add deltaNE to d, and increment x and y.
x = x + 1;
y = y - 1;
}
else{
d += deltaN; // If d > 0 -> Add deltaN, and increment y.
y = y - 1;
}
}
else if(region == 2){
x = x + 1;
y = y - 1;
}
else if(region == 3){
if(d <= 0){
d += deltaE;
x = x + 1;
}
else{
d += deltaNE;
x = x + 1;
y = y - 1;
}
}
else if(region == 4){
if(d <= 0){
d += deltaSE;
x = x + 1;
y = y + 1;
}
else{
d += deltaE;
x = x + 1;
}
}
else if(region == 5){
x = x + 1;
y = y + 1;
}
else if(region == 6){
if(d <= 0){
d += deltaSE;
x = x + 1;
y = y + 1;
}
else{
d += deltaS;
y = y + 1;
}
}
point(x, y);
}
return;
}
When programs pause, look for while() loops that don't resolve properly. I inserted the following println statements into your while loop to print out what was happening. Then I recreated the problematic condition and quit the program, and checked the console for signs of what was going wrong.
println("top of the while loop to ya...");
println("x: " + x + ", x1: " + x1);
println("region: " + region + ", d: " + d);
It looks like region 6 is causing the pausing problem. If d > 0, it is never decreased and x is never increased, so there is no way to satisfy the while condition.
With the same set of statements you can troubleshoot the inaccurate line issue. It occurs in region 4, but I'll leave the details as an exercise.
So I'm trying to implement a test where a oval can connect with a circle, but it's not working.
edist = (float) Math.sqrt(
Math.pow((px + ((pwidth/2) )) - (bx + (bsize/2)), 2 ) +
Math.pow(-((py + ((pwidth/2)) ) - (bx + (bsize/2))), 2 )
);
and here is the full code (requires Slick2D):
import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
public class ColTest extends BasicGame{
float px = 50;
float py = 50;
float pheight = 50;
float pwidth = 50;
float bx = 200;
float by = 200;
float bsize = 200;
float edist;
float pspeed = 3;
Input input;
public ColTest()
{
super("ColTest");
}
#Override
public void init(GameContainer gc)
throws SlickException {
}
#Override
public void update(GameContainer gc, int delta)
throws SlickException
{
input = gc.getInput();
try{
if(input.isKeyDown(Input.KEY_UP))
py-=pspeed;
if(input.isKeyDown(Input.KEY_DOWN))
py+=pspeed;
if(input.isKeyDown(Input.KEY_LEFT))
px-=pspeed;
if(input.isKeyDown(Input.KEY_RIGHT))
px+=pspeed;
}
catch(Exception e){}
}
public void render(GameContainer gc, Graphics g)
throws SlickException
{
g.setColor(new Color(255,255,255));
g.drawString("col: " + col(), 10, 10);
g.drawString("edist: " + edist + " dist: " + dist, 10, 100);
g.fillRect(px, py, pwidth, pheight);
g.setColor(new Color(255,0,255));
g.fillOval(px, py, pwidth, pheight);
g.setColor(new Color(255,255,255));
g.fillOval(200, 200, 200, 200);
}
public boolean col(){
edist = (float) Math.sqrt(Math.pow((px + ((pwidth/2) )) - (bx + (bsize/2)), 2) + Math.pow(-((py + ((pwidth/2)) ) - (bx + (bsize/2))), 2));
if(edist <= (bsize/2) + (px + (pwidth/2)))
return true;
else
return false;
}
public float rotate(float x, float y, float ox, float oy, float a, boolean b)
{
float dst = (float) Math.sqrt(Math.pow(x-ox,2.0)+ Math.pow(y-oy,2.0));
float oa = (float) Math.atan2(y-oy,x-ox);
if(b)
return (float) Math.cos(oa + Math.toRadians(a))*dst+ox;
else
return (float) Math.sin(oa + Math.toRadians(a))*dst+oy;
}
public static void main(String[] args)
throws SlickException
{
AppGameContainer app =
new AppGameContainer( new ColTest() );
app.setShowFPS(false);
app.setAlwaysRender(true);
app.setTargetFrameRate(60);
app.setDisplayMode(800, 600, false);
app.start();
}
}
Is using ovals an absolute requirement? You can approximate collisions between fancier shapes by representing them with multiple circles. That way you can use very a simple collision detection between circles and still achieve a high level of accuracy for the viewer.
collision(c1, c2) {
dx = c1.x - c2.x;
dy = c1.y - c2.y;
dist = c1.radius + c2.radius;
return (dx * dx + dy * dy <= dist * dist)
}
(source: strd6.com)
Finding the intersection is harder than you think. Your col() method is a bit off, but that approach will at best be able to tell you if a single point is within the circle. It won't be able to really detect intersections.
I Googled up some code for computing the actual intersections. I found one in JavaScript that's really interesting and really complicated. Take a look at the source.
If you wanted something a bit simpler (but less accurate), you could check a few points around the ellipse to see if they're within the circle.
private boolean isInCircle(float x, float y) {
float r = bsize / 2;
float center_x = bx + r;
float center_y = by + r;
float dist = (float) Math.sqrt(Math.pow(x - center_x, 2) + Math.pow(y - center_y, 2));
return dist < r;
}
public boolean col() {
return
isInCircle(px + pwidth / 2, py ) || // top
isInCircle(px + pwidth , py + pheight / 2) || // right
isInCircle(px + pwidth / 2, py + pheight ) || // bottom
isInCircle(px , py + pheight / 2); // left
}
If you plan on implementing more shapes and/or need the minimum distance between your shapes, you could start using GJK : you would only need to implement the support functions for each new shape. If computation time is also critical, GJK is definitely something you should look at, but it would surely require some more programming on your side.
If you can find your foci you can check for collision with the pseudo code below.
WARNING this only works for two ellipse collisions (ellipse and circle collisions work also).
r = length of semi major axis
a_x = x coordinate of foci 1 of the first ellipse
a_y = y coordinate of foci 1 of the first ellipse
b_x = x coordinate of foci 2 of the first ellipse
b_y = y coordinate of foci 2 of the first ellipse
c_x = x coordinate of foci 1 of the second ellipse
c_y = y coordinate of foci 1 of the second ellipse
d_x = x coordinate of foci 2 of the second ellipse
d_y = y coordinate of foci 2 of the second ellipse
p_x = (a_x+b_x+c_x+d_x)/4 // i.e. the average of the foci x values
p_y = (a_y+b_y+c_y+d_y)/4 // i.e. the average of the foci y values
if r >= ( sqrt( (p_x + a_x)^2+(p_y + a_y)^2 ) + sqrt( (p_x + a_x)^2+(p_y + a_y)^2 ) )
then collision
If you really want the derivation of this let me know and I'll provide it. But it uses the idea that the sum of the distances between the foci of an ellipse and any point on the edge of an ellipse are a set distance apart (the semi major axis). And solves for a point that is on the edge of both ellipsoids and if one exist then their is a collision.