I'm trying to write a program that checks if a circle contains another circle, if a certain point is inside a circle, or the one I'm having trouble with, if a circle overlaps with another circle.
import javafx.scene.shape.Circle;
public class Problem10_11 {
public static void main(String[] args) {
//Create circle with certain parameters.
Circle2D c1 = new Circle2D(2, 2, 5.5);
//Create output which will be tested by all our methods.
System.out.println("The area for circle 1 is " +c1.getArea()+
" and its perimeter is " + c1.getPerimeter());
System.out.println("Is (3,3) contained within circle 1? "
+ c1.contains(3, 3));
System.out.println("Does circle 1 contain circle 2? "
+ c1.contains(new Circle2D(4,5,10.5)));
System.out.println("Does circle 1 overlap with circle 3? "
+ c1.overlaps(new Circle2D(3, 5, 2.3)));
}
}
class Circle2D {
double x; //first parameter
double y; //second parameter
double radius; //third parameter
Circle2D() {
}
public Circle2D(double x, double y, double radius) {
this.x = x;
this.y = y;
this.radius = radius;
}
public void setX(double x) {
this.x = x; //set x
}
public double getX() {
return x; //grab x
}
public void setY(double y) {
this.y = y; //set y
}
public double getY() {
return y; //grab y
}
public void setRadius(double radius) {
this.radius = radius; //set radius
}
public double getRadius() {
return radius; //grab radius
}
public double getArea() {
double area = Math.PI*radius*radius; //formula for area
return area;
}
public double getPerimeter() {
double perimeter = 2*Math.PI*radius; //formula for perimeter
return perimeter;
}
public boolean contains(double x, double y) {
//Use distance formula to check if a specific point is within our circle.
double distance = Math.sqrt(Math.pow(this.x - x, 2) + (Math.pow(this.y - y, 2)));
if (distance <= radius * 2)
return true;
else {
return false;
}
}
public boolean contains(Circle2D circle) {
//Use distance formula to check if a circle is contained within another circle.
double distance = Math.sqrt(Math.pow(circle.getX() - x, 2) + (Math.pow(circle.getY() - y, 2)));
if (distance <= (this.radius - circle.radius)) {
return true;
} else {
return false;
}
}
public boolean overlaps(Circle2D circle) {
//Use distance formula to check if a circle overlaps with another circle.
double distance = Math.sqrt(Math.pow(circle.getX() - x, 2) + (Math.pow(circle.getY() - y, 2)));
}
}
So my overlap method is all the way at the bottom but I don't really have anything inside because I'm not sure exactly what to do. I tried this :
if (distance <= radius) return true;
else return false;
but that didnt work. So I'm not sure what else to try. FYI, I'm trying to check if c1 overlaps with a circle with parameters (3, 5, 2.3). I appreciate any suggestions/advice.
You can refer to Relative position of two circles.
public boolean overlaps(Circle2D circle) {
//Use distance formula to check if a circle overlaps with another circle.
double distance = Math.sqrt(Math.pow(circle.getX() - x, 2) + (Math.pow(circle.getY() - y, 2)));
return distance <= (this.radius + circle.radius) and distance >= Math.abs(this.radius - circle.radius)
}
if the distance between the centres of the circles is less than the sum of the radius of the two circles then they are overlapping.
double minDistance = Math.max(circle.getRadius(),this.radius) - Math.min(circle.getRadius(),this.radius);
if (distance <= (this.radius + circle.getRadius()) && distance>= minDistance) return true;
else return false;
1.- you have to to place both circles in space, give them some cordinates
2.- you have to get the vectors from 2 circles.
3.- you have to normailze those vectors and get the correct distance in units,
im gonna use pixels.
4.- finally you have to check if the distance between those 2 vectors are less that the radious of both circles, if so, then they are overlaped.
here you have a link that is better explained:
https://gamedevelopment.tutsplus.com/tutorials/when-worlds-collide-simulating-circle-circle-collisions--gamedev-769, actually this is something very common we use in game development when we want to check circle collisions ( for 2D games )
Most answers here are wrong.
There are three cases to consider:
Circles overlap and the center of the smaller circle is inside the bigger circle
Circles overlap and the center of the smaller circle is outside the bigger circle
3.
The two circles touch at their borders
The algorithm is this (in Java):
Calculate the distance between centers:
double centersDistance = Math.sqrt((x2 - x1)^2 + (y2 - y1)^2)
Check if one circle contains another:
boolean blueContainsRed = blue.radius > centersDistance + red.radius;
boolean redContainsBlue = red.radius > centersDistance + blue.radius;
Check if they overlap:
boolean circlesOverlap = centersDistance <= blue.radius + red.radius;
the <= would make sure that true is returned for case 3 (when borders only touch). If you don't want that, use < .
So the final formula would be:
return !blueContainsRed && !redContainsBlue && circlesOverlap;
This table might also prove useful (from https://planetcalc.com/8098/):
Related
I have an assigment in my beginners class in coding, in java. This is the assignment (translated from swedish to english by me, therefor I'm sorry in advance);
The class CircleList keeps track of a number of circles. Implement the class.
Guidance
This task should, not only give practice in using ArrayList, but also give practice in breaking down a problem in several methods. Therefor you should use the method overlapsinside of the method add.
And for the method overlaps to be easier to write, you should, in overlaps use the private method circleOverlaps.
Two circles overlaps if the distance between their origos are less than the sum of their radiuses.
The class Circle looks like this;
class Circle {
private double radius;
private double x;
private double y;
/** Constructs a circle with the radie radius and the
center in x, y. */
public Circle(double x, double y, double radius) {
this.x = x;
this.y = y;
this.radius = radius;
}
/** Returns the x coordinate of the center. */
public double getX() {
return x;
}
/** Returns the y coordinate of the center. */
public double getY() {
return y;
}
/** Returns the radius. */
public double radius() {
return radius;
}
/** Returns the area. */
public double area() {
return Math.PI * radius * radius;
}
}
And this is what I've come up with so far, (the methods were already declared but not implemented);
public class CircleList {
private ArrayList<Circle> circles;
/** Constructs an empty list for circles. */
public CircleList() {
circles = new ArrayList<Circle>();
}
/** Adds the circle c to the list if it not ovelaps
with any circle in the list. Return true if
circle has been added. */
public boolean add(Circle c) {
circles.add(c);
}
/** Returns true if the circle c ovelaps with any
one circle in this list. */
public boolean overlaps(Circle c) {
}
private boolean circlesOverlaps(Circle c1, Circle c2) {
double r1 = Circle.radius(c1); //radius, x- & y-value of circle 1 (c1)
double x1 = Circle.getX(c1);
double y1 = Circle.getY(c1);
double r2 = Circle.radius(c2); //radius, x- & y-value för circle 2 (c2)
double x2 = Circle.getX(c2);
double y2 = Circle.getY(c2);
double distance = Math.pow((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2), 0.5);
if (r2 >= r1 && distance <= (r2 - r1)){ //c1 is inside c2
}
else if (r1 >= r2 && distance <= (r1 - r2) ) { //c2 is inside c1
}
else if (distance > (r1 + r2)){ //c2 doesn't overlap c1
}
else { //c2 overlaps c1
}
}
}
I don't really know where to start. And I don't really have anyone to ask at the moment. I understand if this is too much to even start with. But thank you anyways.
Take care.
Basically you have to iterate over all circles and check if the given circle overlaps with any like
public boolean overlaps(Circle c) {
return circles.stream()
.anyMatch(circle -> circlesOverlaps(c, circle));
}
and you have to return true or false from your if conditions in circlesOverlaps method, depending on whether you consider one circle inside another as an overlap or not for your problem.
One other place you need to correct is
public boolean add(Circle c) {
return circles.add(c);
}
basically adding return as you need to return a boolean based on your return type.
In celebration of Pi Day, I decided to implement the Monte Carlo method to approximate the value of π, but my algorithm doesn’t seem to be working.
I've tried running with different parameters, but I always get approx 3.66
I've tried debugging but I can't figure it out.
public class ApproximatePi {
private int iterations; // how many points to test
private double r; // width of the square / radius of circle (quarter circle)
private int inCount = 0; // number of points that are inside the circle
private int outCount = 0; // number of points outside of the circle
private Random getNum = new Random(System.currentTimeMillis());
ApproximatePi(int iterations, double r) {
this.iterations = iterations;
this.r = r;
// getNum = new Random(System.currentTimeMillis());
}
public double getApproximation() {
for (int i = 0; i < iterations; i++) {
double x = (r) * getNum.nextDouble();
double y = (r) * getNum.nextDouble();
if (inside(x, y)) {
inCount++;
} else
outCount++;
}
double answer = (double) inCount / (double) outCount;
return answer;
}
private boolean inside(double x, double y) {
// if the hypotenuse is greater than the radius, the point is outside the circle
if (getHypot(x, y) >= r) {
return false;
} else
return true;
}
private double getHypot(double x, double y) {
double s1 = Math.pow(x, 2);
double s2 = Math.pow(y, 2);
return Math.sqrt(s1 + s2);
}
}
So, lets assume that radius is 1, so in this case what actually you're doing:
Generate bunch of x,y coordinates within square with coordinates (0,0) - (1,1)
Then you test which of them are within circle with center at (0,0)
By counting in/out counters you're getting how many points within circle's segment and how many outside
inCount / (inCount+outCount) represents ratio between in points to total surface
r² is total surface
Thus, you can get approximate area of 1/4th of circle via formula inCount / (inCount+outCount) * r² == pi * r² / 4
Now, you can say that 4 * inCount / (inCount+outCount) == pi
I have a program to draw 20 circles w/ random rad x and y. After, I need to test which circles are overlapping and if they are, set them cyan, if not set them black. heres what I have so far, the problem, is it always sets it to cyan overlapping or not.
public class AppletP5 extends JApplet{
MyCircle[] circle = new MyCircle[20];
public AppletP5(){
for(int i = 0; i<20; i++){
int x0= (int) (Math.random()*500);
int y0= (int) (Math.random()*500);
int rad0= (int) (30 + Math.random()*70);
circle[i] = new MyCircle(x0,y0,rad0);
}
}
public void paint(Graphics g){
for(int i = 0; i<20; i++){
if(circle[i].isOverlapping(circle) == true){
g.setColor(Color.CYAN);
g.drawOval(circle[i].x,circle[i].y,circle[i].rad*2,circle[i].rad*2);
} else if(circle[i].isOverlapping(circle) == false){
g.setColor(Color.BLACK);
g.drawOval(circle[i].x,circle[i].y,circle[i].rad*2,circle[i].rad*2);
}
}
}
}
public class MyCircle {
protected int x, y, rad;
public MyCircle(int x, int y, int rad){
this.x = x;
this.y = y;
this.rad = rad;
}
public boolean isOverlapping(MyCircle[] circles){
for(MyCircle c : circles){
if(Math.pow(c.rad - rad , 2) >= Math.sqrt(Math.pow(x - c.x, 2) + Math.pow(y - c.y , 2))){
return true;
}
}
return false;
}
}
You need to exclude the current Circle from the comparison, since a circle trivially overlaps itself.
You could go with an easy check as long as you just have one instance of each Circle:
for (MyCirlce c : circles) {
if (c != this && ...)
In addition you are checking if the difference of radii between two circles squared by two is greater than the distance of the two centres? Shouldn't you check for the sum of the radii, eg:
r1 + r2 <= distance(c1, c2)
isOverLapping is incorrect implemented.
Two circles intersect, if the distance between their centers is smaller than the sum of their radii. So:
int radSum = c.rad + rad;
int radDif = c.rad - rad;
int distX = c.x - x + radDif;
int distY = c.y - y + radDif;
if(radSum * radSum < distX * distX + distY * distY)
return true;
Apart from that you'll have to ensure you don't compare a circle with itself. And finally: Math.pow is rather costly, so replace it with the simpler version, if you only want the square of a number.
This question already has answers here:
Java check if two rectangles overlap at any point
(9 answers)
Closed 7 years ago.
My assignment is to check if two points are inside a rectangle, check if a rectangle is inside another rectangle, and also check if a rectangle overlaps another rectangle
I completed the first two steps but I can't solve the overlapping method.
This what I've done.
public class MyRectangle2D {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
MyRectangle2D rect = new MyRectangle2D();
//returns area of default rectangle
System.out.println(rect.getArea());
//returns perimeter of default rectangle
System.out.println(rect.getPerimeter());
//returns true if default (0,0) is inside rectangle
System.out.println(rect.contains(0,0));
//returns false if point is not in triangle
System.out.println(rect.contains(10,10));
MyRectangle2D r1 = new MyRectangle2D(10,2,6,4);
System.out.println("The area of your rectangle is " + r1.getArea() +
" \nthe perimeter of your rectangle is " + r1.getPerimeter());
System.out.println("Testing Rectangle 2 with points (1,8)...");
//following lines test the contain(x,y) method
System.out.println(r1.contains(1,8) ? "Point (1,8) is on Rectangle" : "Point(1,8) is not on Rectangle");
System.out.println("Testing Rectangle 2 with points (10,1)...");
System.out.println(r1.contains(10,1) ? "Point (10,1) is on Rectangle" : "Point(10,1) is not on Rectangle");
//following lines test contains(rect) method
System.out.println(r1.contains(new MyRectangle2D(9,1,1,1)) ? "Rectangle is inside" : "Not inside");
System.out.println(r1.contains(new MyRectangle2D(9,1,10,2)) ? "Rectangle is inside" : "Rectangle is not inside");
//following lines test if rectangles overlap
System.out.println(r1.overlaps(new MyRectangle2D(4,2,8,4)));
}
double x;
double y;
double width;
double height;
private MyRectangle2D(){
x = 0;
y = 0;
width = 1;
height = 1;
}
private MyRectangle2D(double newX, double newY,
double newWidth, double newHeight){
setX(newX);
setY(newY);
setHeight(newHeight);
setWidth(newWidth);
}
double getX(){
return x;
}
double getY(){
return y;
}
void setX(double newA){
x = newA;
}
void setY(double newA){
y = newA;
}
double getWidth(){
return width;
}
double getHeight(){
return height;
}
void setWidth(double newA){
width = newA;
}
void setHeight(double newA){
height = newA;
}
double getArea(){
double area = width * height;
return area;
}
double getPerimeter(){
double perimeter = (2 * width) + (2 * height);
return perimeter;
}
boolean contains(double x, double y){
boolean inside = false;
if(x<(getWidth()/2 + getX()) && x>getX()-(getWidth()/2)){
if(y<(getY() + getHeight()/2) && y>getY()-(getHeight()/2))
inside = true;
}
return inside;
}
boolean contains(MyRectangle2D r){
boolean inside = false;
if(r.getX()<(getWidth()/2 + getX()) && r.getX()>getX()-(getWidth()/2)){
if(r.getY()<(getY() + getHeight()/2) && r.getY()>getY()-(getHeight()/2)){
if(r.getWidth()<=getWidth() && r.getHeight()<=getHeight())
inside = true;
}
}
return inside;
}
boolean overlaps(MyRectangle2D r){
boolean inside = false;
if(contains(r.getX()+r.getWidth(),r.getY()+r.getHeight()))
inside = true;
if(contains(r.getX()-r.getWidth(),r.getY()-r.getHeight()))
inside = true;
return inside;
}
}
This will find if the rectangle is overlapping another rectangle, don't forget to mark this as the answer and vote up when you can.
public boolean overlaps (MyRectangle2D r) {
return x < r.x + r.width && x + width > r.x && y < r.y + r.height && y + height > r.y;
}
I am making a 2d rpg game in java and I have run into a problem. I can make the player move around the stage and I have rocks, trees, walls, etc. on the stage as well. I don't know how to detect the collision and make it to where the player can't move through the object. The code that reads map file and draws image on the canvas is as follows:
public void loadLevel(BufferedImage levelImage){
tiles = new int[levelImage.getWidth()][levelImage.getHeight()];
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
Color c = new Color(levelImage.getRGB(x, y));
String h = String.format("%02x%02x%02x", c.getRed(),c.getGreen(),c.getBlue());
switch(h){
case "00ff00"://GRASS Tile - 1
tiles[x][y] = 1;
break;
case "808080"://Stone -2
tiles[x][y] = 2;
break;
case "894627"://Dirt -3
tiles[x][y] = 3;
break;
case "404040"://Rock on Grass -4
tiles[x][y] = 4;
break;
case "00b700"://Tree -5
tiles[x][y] = 5;
break;
case"000000"://Wall -6
tiles[x][y] = 6;
break;
case "cccccc"://Rock on stone -7
tiles[x][y] = 7;
break;
default:
tiles[x][y] = 1;
System.out.println(h);
break;
}
}
}
}
And the player class is as follows:
public class Player {
private int x,y;
public int locx,locy;
private Rectangle playerR;
private ImageManager im;
public boolean up =false,dn = false,lt=false,rt=false,moving = false,canMove = true;
private final int SPEED =2;
public Player(int x, int y, ImageManager im){
this.x = x;
this.y = y;
this.im = im;
locx = x;
locy = y;
playerR = new Rectangle(x,y,16,16);
}
public void tick(){
if (up) {
if(canMove){
y -= SPEED;
locx = x;
locy = y;
playerR.setLocation(locx, locy);
moving = true;
}
else{
y += 1;
canMove=true;
}
}
if (dn) {
y +=SPEED;
locx = x;
locy = y;
moving = true;
}
}
if (lt) {
x -= SPEED;
locx = x;
locy = y;
moving = true;
}
if (rt) {
x+=SPEED;
locx = x;
locy = y;
moving = true;
}
}
if(moving){
System.out.println("PLAYER\tX:"+locx+" Y:"+locy);
moving = false;
}
}
public void render(Graphics g){
g.drawImage(im.player, x, y, Game.TILESIZE*Game.SCALE, Game.TILESIZE*Game.SCALE, null);
}
}
I don't really know how to do collision, but i googled it and people said to make a rectangle for the player and all the objects that the player should collide with, and every time the player moves, move the player's rectangle. Is this the right way to do this?
EDIT EDIT EDIT EDIT
code for when collision is true:
if (rt) {
x+=SPEED;
locx = x;
locy = y;
playerR.setLocation(locx, locy);
for(int i = 0;i<Level.collisions.size();i++){
if(intersects(playerR,Level.collisions.get(i))==true){
x-=SPEED;
locx = x;
playerR.setLocation(locx, locy);
}
}
moving = true;
}
And the intersects method is as follows:
private boolean intersects(Rectangle r1, Rectangle r2){
return r1.intersects(r2);
}
I'm going to focus on your tick method since that is where most of this logic is going. There are a couple changes here. Most notably, we only move the rectangle before checking for collisions. Then loop through all the collideable objects in your level. Once one is found, we reset our x and y and break out of the loop (no sense in looking at any of the other objects since we already found the one we collided with). Then we update our player position. By doing it this way, I centralized the code so it is not being repeated. If you ever see yourself repeating code, there is a pretty good chance that it can be pulled out to a common place, or to a method.
public void tick() {
if (up) {
y -= SPEED;
} else if (dn) {
y += SPEED;
} else if (lt) {
x -= SPEED;
} else if (rt) {
x += SPEED;
}
playerR.setLocation(x, y);
for (Rectangle collideable : Level.collisions) {
if (intersects(playerR, collideable)) {
x = locx;
y = locy;
playerR.setLocation(x, y);
break;
}
}
locx = x;
locy = y;
}
There are different ways to do that. As you talk about a "rpg" i think your view is Isometric (45° top down).
I would do the collision detection in pure 90° top down, as it is easier and, imho, more realistic.
We have 2 possibilities:
Move your Player to the next position. If there is a collision, reset his position.
Calculate the next position, if there would be a collision don't move.
If you want to have a "gliding" collision response, you have to check in which axis the collision will happen, and stop / reset movement for this axis only.
To have a more efficient collision detection only check near objects, which will possibly collide.
Do this by comparing a squared "dangerRadius" with the squared distance between your player and the object:
if ((player.x - object.x)² + (player.y - object.y)² <= dangerRadius²)
// Check for intersection
This will sort out most of the objects by using a simple calculation of:
2 subtractions
1 addition
3 multiplications (the ²)
1 compare (<=)
In your game you should sepparate the logic and the view. So basicly you don't detect, if the two images overlapp, but you check, if the objects in your logic overlap. Then you draw the images on the right position.
Hope this helps.
EDIT: Important: If you update your character, depending on the time between the last and this frame (1/FPS) you have to limit the max timestep. Why? Because if for some reason (maybe slow device?) the FPS are really low, it is possible, that the character moves verry far between 2 frames and for that he could go through an object in 1 frame.
Also if you simply reset the movement on collision or just don't move the distance between you and the object could be big for low FPS. For normal FPS and not to high movementspeed this won't happen/ be noticeable.
I personally am fairly new to Java, though I have worked with C# in the past. I am making a similar game, and for collision detection I just check the locations of the player and objects:
if (z.gettileX() == p.gettileX()){
if (z.gettileY() == p.gettileY()){
System.out.println("Collision!");
}
}
If the player (p) has equal X coordinates and Y coordinates to z(the bad guy), it will send this message and confirm that the two have, in fact, collided. If you can make it inherent in the actual class behind z to check if the coordinates a equal, you can create an unlimited number of in-game objects that detect collision and react in the same way, i.e. walls.
This is probably what your looking for. I've made this class spicificly for collision of multiple objects and for individual side collisions.
abstract class Entity {
private Line2D topLine;
private Line2D bottomLine;
private Line2D leftLine;
private Line2D rightLine;
private Rectangle rectangle;
private Entity entity;
protected boolean top;
protected boolean bottom;
protected boolean left;
protected boolean right;
protected int x;
protected int y;
protected int width;
protected int height;
public Entity(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
updateLinesAndRects();
}
public void updateLinesAndRects() {
topLine = new Line(x + 1, y, width - 2, 0);
bottomLine = new Line(x + 1, y + height, width - 2, height);
leftLine = new Line(x, y + 1, 0, height - 2);
rightLine = new Line(x + width, y + 1, 0, height - 2);
rectangle = new Rectangle(x, y, width, height)
}
public void setCollision(Entity entity) {
this.entity = entity;
top = isColliding(new Line2D[]{topLine, bottomLine, leftLine, rightLine});
bottom = isColliding(new Line2D[]{bottomLine, topLine, leftLine, rightLine});
left = isColliding(new Line2D[]{leftLine, topLine, bottomLine, rightLine});
right = isColliding(new Line2D[]{rightLine, topLine, bottomLine, leftLine});
}
public void updateBounds() {
if(top) y = entity.y + entity.height;
if(bottom) y = entity.y - height;
if(left) x = entity.x + entity.width;
if(right) x = entity.x - width;
}
public boolean isColliding() {
return rectangle.intersects(entity.rect);
}
private boolean isLinesColliding(Line2D[] lines) {
Rectangle rect = entity.getRectangle();
return lines[0].intersects(rect) && !lines[1].intersects(rect) && !lines[2].intersects(rect) && !lines[3].intersects(rect);
}
private Line2D line(float x, float y, float width, float height) {
return new Line2D(new Point2D.Float(x, y), new Point2D.Float(x + width, x + height));
}
public Rectangle getRectangle() {
return rectangle;
}
}
Example:
class Player extends Entity{
Entity[] entities;
public Player(int x, int y, int width, int height) {
super(x, y, width, height);
}
public void update() {
updateLinesAndRects();
for(Entity entity : entities) {
setCollision(entity);
if(top) system.out.println("player is colliding from the top!");
if(isColliding()) system.out.println("player is colliding!");
updateBounds(); // updates the collision bounds for the player from the entities when colliding.
}
}
public void setEntities(Entity[] entities) {
this.entities = entities;
}
}