drawing random circles, storing their coorindates in an array - java

This is what I want to accomplish for homework: Design and implement a program that draws circles, with the radius and location of each circle determined at random. If a circle does not overlap with any other circle, draw that circle in black. If a circle overlaps one or more circles, draw it in cyan. Use an array to store a representation of each circle, then determine the color of each circle. Two circles overlap if the distance between their center points is less than the sum of their radii.
I am really close, but I just cannot figure out how to use the sqrt formula in order to compare the radii of the circles that overlap and then to redraw that circle in cyan. I've tried to figure this out in two other posts here: drawing random circles, storing their coorindates in an array and here: draw random circles, first storing the points in an array. I got some pointers, so can anyone give me specific pointers to figure out how to make my for loop use the Math.sqrt function properly in order to compare the radii and then redraw an overlapping circle in cyan? Thank you very much.
UPDATE: I have gotten the Math.sqrt forumla working, but I can't figure out how to structure my for loop in order to only make the circle that overlaps be filled in. I tried to do this using a nested for loop with a boolean in it, but that is making all of the circles fill in. Thank you for your recommendations so far.
Here is the code that I have so far:
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.*;
import java.awt.event.*;
import java.math.*;
public class RandomCircles extends JPanel
{
private int[] sizeArray = new int [5]; // radius of each circle
private int[] xArray = new int [5]; //array to store x coordinates of circles
private int[] yArray = new int [5]; //array to store y coordinates of circles
private int x1, x2, y1, y2;
private boolean overlap = false;
public RandomCircles()
{
Random r = new Random();
for (int i = 0; i<xArray.length; i++){
//random numbers from 1 to 20;
xArray[i] = r.nextInt(200) + 1;
}
for (int i = 0; i<yArray.length; i++){
yArray[i] = r.nextInt(200) + 1;
}
for (int i = 0; i<sizeArray.length; i++){
sizeArray[i] = r.nextInt(100) +1;
}
setBackground (Color.blue);
setPreferredSize (new Dimension(300, 200));
}
// generates all of the circles stored in the array.
public void paintComponent (Graphics page)
{
super.paintComponent(page);
for (int i = 0 ;i<xArray.length; i++) //this is an iterator that draws the circles and checks for overlapping radii
for (int j = 0 ;j<xArray.length; j++)
{
//boolean overlap = false;
//is supposed to compare radii of circles to check if they overlap
{
if (Math.sqrt((xArray[i]-xArray[j])*(xArray[i]-xArray[j])+(yArray[i]-yArray[j])*(yArray[i]-yArray[j])) >sizeArray[i]-sizeArray[j]);
boolean overlap = true;
page.fillOval(xArray[i], yArray[i], sizeArray[i], sizeArray[i]);
page.setColor (Color.cyan);
repaint();
} //draws the circles that are stored in the array
page.drawOval(xArray[i], yArray[i], sizeArray[i], sizeArray[i]);//outer for loop
}
}
public static void main (String[] args)
{
JFrame frame = new JFrame ("Circles");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add (new RandomCircles());
frame.pack();
frame.setVisible(true);
}
}

//Math.sqrt((x1-x2)*(x1-x2)-(y1-y2)*(y1-y2)), go back and read chapter 7
should be
Math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))
(You need to take the square root of the sum of the squared X and Y distances, not the difference.)
Update:
There are a couple of problems with the overlap detection. Two circles overlap if
the sum of their radii is greater than the distance between their centers, but
you're taking the difference of the radii and checking if it's less than the
distance between the centers.
Also, you should skip the overlap check whenever i == j (since every circle overlaps
with itself; you're only interested in overlaps between different circles).

Related

Java beginning if statement in for loop being skipped while others work

Back again with another problem that has stumped me completely and cannot for the life of me fix.
So I had previously posted a question about my Java game I am making for a class that with the help of #MadProgrammer was fixed...mostly. Now there is a new problem that needs a post all to it's own
Previous Post:
Rows and columns with multidimensional array java
Problem:
In the code below I have it set up to loop through the variables x and y to make rows and columns on a jPanel. Each time it loops through it should randomly mark the "x,y" location with one of the "terrains" so that later it can "paint" that location with the appropriate colored 20x20 square.
The code runs great except for one thing, it looks like it skips the very first "if statement" that marks the "terran[0]" which is "floor". When the code is ran it "paints" the other three "terrains" and not a single "floor" "terrain".
I have looked for a solution on these posts but no success:
Java if statement is skipped
If statement being skipped during execution
Java - for loops being skipped
Java if-statement being skipped
Here is a working piece of code that results in the problem at hand:
import java.awt.*;
import javax.swing.*;
import java.util.*;
public class gamePanel extends JPanel
{
public gamePanel()
{
setBounds(115,93,480,480);
}
private Random generator = new Random();
int floor = 0; //initializes the variable floor to zero for later use
int dirt = 1;
int stone = 2;
int water = 3;
int width = 24;
int height = 24;
int x, y; // my x & y variables for coordinates
int[][] coords = new int[width][height]; //my array that I want to store the coordinates for later use in painting
int[] terrain = {floor, dirt, stone, water}; //my terrain that will determine the color of the paint
public void mapGen() //what should mark/generate the JPanel
{
for(x = 0; x < width; x++)
{
for(y = 0; y < height; y++)
{
int z = generator.nextInt(20);// part of the randomization
if(z <= 10)
{
coords[x][y] = terrain[0]; //should mark the coordinates as floor
}
if(z == 11)
{
coords[x][y] = terrain[3];//should mark the coordinates as water
}
if(z >= 12 && z <= 16)
{
coords[x][y] = terrain[2];//should mark the coordinates as stone
}
if(z >= 17 && z <= 19)
{
coords[x][y] = terrain[1];//should mark the coordinates as dirt
}
coords[0][0] = terrain[0]; // sets coordinate 0,0 to floor //need to have these always be floor
coords[23][23] = terrain[0]; // sets coordinate 24,24 to floor //^^^^^^^^^^
}
}
}
#Override
public void paintComponent(Graphics g)//what will paint each 20x20 square on the grid what it is assigned
{
super.paintComponent(g);
for(int x = 0; x < width; x++)
{
for(int y = 0; y < height; y++)
{
mapGen();
if(coords[x][y] == terrain[floor])//should paint the floor color at marked coordinates
{
g.setColor(Color.white);
g.fillRect((x*20), (y*20), 20, 20);
}
if(coords[x][y] == terrain[dirt]);//should paint the dirt color at marked coordinates
{
g.setColor(new Color(135,102,31));
g.fillRect((x*20), (y*20), 20, 20);
}
if(coords[x][y] == terrain[stone])//should paint the stone color at marked coordinates
{
g.setColor(new Color(196,196,196));
g.fillRect((x*20),(y*20),20,20);
}
if(coords[x][y] == terrain[water])//should paint the water color at marked coordinates
{
g.setColor(new Color(85,199,237));
g.fillRect((x*20),(y*20),20,20);
}
}
}
}//end paintComponent
public static void main(String[] args)
{
gamePanel panel = new gamePanel();
JFrame frame = new JFrame();
frame.setSize(500,550);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(panel);
frame.setVisible(true);
}//end main
}// end gamePanel
Please keep in mind that I am a novice programmer and I am still learning. So anything that is not considered "basic" code please explain in detail.

Drawing a Checkerboard using nested for loops

I have a couple of questions regarding the use of nested for loops. In this example in the book it uses nested for loops to draw a typical checkerboard.
1) Is my understanding correct when I assume the code below says the sequence of drawing the checkerboard squares will be vertically down from left to right until the entire checkerboard is drawn?
2) I'm have some questions about the purpose of double x, and double y inside the inner most for loop. Are they being calculated for the purpose of spacing one square to the next? Can you expand on the purpose of double x and double y and what occurs each cycle of one loop?
import acm.program.*;
import acm.graphics.*;
public class checkerBoard extends GraphicsProgram{
public void run(){
double sqSize = getHeight() / N_ROWS;
for ( int i = 0; i < N_ROWS; i++){
for (int j = 0; j < N_COLUMNS; j++){
double x = j * sqSize;
double y = i * sqSize;
GRect rect = new GRect(x, y, sqSize, sqSize);
rect.setFilled((i+ j) % 2 !=0);
add(rect);
}
}
}
private static final int N_ROWS = 8;
private static final int N_COLUMNS = 8;
}
1) Is my understanding correct when I assume the code below says the
sequence of drawing the checkerboard squares will be vertically down
from left to right until the entire checkerboard is drawn?
This is correct. Row by row, left to right, top to bottom.
2) I'm have some questions about the purpose of double x, and double y
inside the inner most for loop. Are they being calculated for the
purpose of spacing one square to the next? Can you expand on the
purpose of double x and double y and what occurs each cycle of one
loop?
They are the coordinates of the location where to draw the next square. Specifically, they are the coordinate for the upper left part of the square. You can figure out the start points for all squares by simply multiplying by the width of the squares, as they have done.

Java Methods to rotate, increase size, and clear Box image in Java

I'm creating a java program to draw an image of a box. I have most of my code finished. But, I'm having trouble figuring out a method to rotate the box by a specific number of degrees. I'm also trying to create a method to increase the size of the box by percentage and to clear my canvas of all images drawn.
This is the code I have thus far:
// My Box class
import java.awt.Rectangle;
public class Box
{
public Box(Shapes canvasRef, int leftSide, int topLeft, int theWidth, int theHeight)
{
left = leftSide;
top= topLeft;
width = theWidth;
height = theHeight;
canvas = canvasRef;
theBox = new Rectangle(left, top, width, height);
canvas.addToDisplayList(this);
show = false;
}
public void draw()
{
show = true;
theBox = new Rectangle(left, top, width, height);
canvas.boxDraw();
}
public void unDraw()
{
show = false;
theBox = new Rectangle(left, top, width, height);
canvas.boxDraw();
}
public Rectangle getBox()
{
return theBox;
}
public void moveTo(int newX, int newY)
{
left = newX;
top = newY;
draw();
}
// This is the method that I tried but doesn't do anything
public void turn(int degrees)
{
int newAngle = angle + degrees;
angle = newAngle % 60;
}
clearWorld()
{
// Clears the "canvas" upon which boxes are drawn
}
public void grow(int percentage)
{
//The box grows the specified percentage,
about the center, i.e. increase each side of the box
the percentage indicated, with the center unchanged
}
// My Driver Program
import javax.swing.JFrame;
public class DisplayList
{
public static void main(String[] args)
{
JFrame frame = new JFrame("Joe The Box");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(250, 250);
Shapes component = new Shapes();
frame.add(component);
frame.setVisible(true);
Box b1 = new Box(component, 150, 100, 30, 50);
Box b2 = new Box(component, 100, 100, 40, 60);
b1.draw();
b2.draw();
b1.turn(90);
b2.grow(100);
b1.clearWorld();
Delay.sleep(2);
b2.moveTo(10,10);
}
}
public boolean showBox()
{
return show;
}
private int left;
private int top;
private int width;
private int height;
private int angle = 0;
private Shapes canvas;
private Rectangle theBox;
private boolean show;
}
Can anyone please help me with the last three methods of my Box class?
I'm really struck on what to add?
I'm open to any suggestions.
Thanks for your time!
If you are rotating the box around (0,0) pre-multiply each coordinate, by a rotation matrix:
x=x*Math.cos(t)-y*Math.sin(t)//result of matrix multiplication.
y=x*Math.sin(t)+y*Math.cos(t)//t is the angle
Alternatively, convert to polar coordinates, r=Math.hypot(x,y) theta=Math.atan2(x,y) and add an angle to theta: theta+= rotationAngle. Then convert back to rectangular coordinates: x=r*Math.cos(theta) y=r*Math.sin(theta)
By the way you don't need the modulus; Angles greater than 360 are also ok. Oh, and all angles should be in radians. If they are in degrees, first multiply by 2pi/360 to convert them to radians.
To scale the box, multiply each coordinate by a constant scaling factor.
There are at least two ways to rotate a point around the origin, both of which are mathematically equivalent:
Use trigonometry to calculate the new (x, y) coordinates for the point.
Use linear algebra, specifically a linear transformation matrix, to represent the rotation.
I suggest that you google some keywords to learn more about either of these solutions. If you encounter specific details that you don't understand, please come back with more questions. You may also want to check out our sister site http://math.stackexchange.com where you can ask questions which are specific to the mathematics behind rotation animations.
Once you understand how to apply a rotation to a single point, you will simply need to repeat the calculations for each of the vertices of your box. This will be easiest if you encapsulate the calculations for a single point into its own method.

Substitute rectangle objects on screen when 10 rectangles are reached?

I need to create a class that displays 10 rectangles on the canvas, each with a random color and position. When it reaches 11, the first rectangle is replaced with a new random color and position. 12th rect replaces the 2nd box, and so on. I am using the acm.jar for this, http://jtf.acm.org/javadoc/student/index.html.
import acm.graphics.*;
import acm.program.*;
import java.awt.Color;
import java.util.Random;
public class Rect extends GraphicsProgram
{
public void run()
{
final int width = 800;
final int height = 600;
final int boxWidth = 50;
final int maxBoxes = 10;
this.setSize(width, height);
Random random = new Random();
for(;;) {
int x = random.nextInt(width-boxWidth);
int y = random.nextInt(height-boxWidth);
Color c = new Color(random.nextInt(255), random.nextInt(255), random.nextInt(255));
GRect r = new GRect(x, y, boxWidth, boxWidth);
r.setFilled(true);
r.setLocation(x, y);
r.setFillColor(c);
this.add(r);
this.pause(100);
}
}
}
I already figured out how to make the colors random, I cant figure out how I will substitute the boxes with the old ones.
EDIT:::--------------------------------------------------------------------------------
I did manage to get it working with the help of the guys below. Here is what the new for loop looks like:
for(;;) {
int x = random.nextInt(width-boxWidth);
int y = random.nextInt(height-boxWidth);
Color c = new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256));
GRect r = new GRect(boxWidth, boxWidth);
r.setFilled(true);
r.setLocation(x, y);
r.setFillColor(c);
add(r, x, y);
int n = getElementCount();
if (n>maxBoxes)
{
remove(getElement(0));
}
this.pause(100);
}
One thing I dont understand is why the remove(getElement(0)) works,, how does the element change its index once one is removed? If I have 10 elements 0-9, and I remove element(0) why does the other elements change its index?
This really looks like homework , so I won't do it for you but give some clues.
You can use the getElementCount() method to know the current number of rectangles in your frame.
Create a list of GObjects, and populate it with your rectangles as you create them.
Once you reach ten, the process becomes
remove rectangle from screen using remove(GObject gobj)
remove first element, add to end of list.
And here you are :)
You need to store the list of rectangles drawn so far. Every time you add a new rectangle, if the list is already 10 rectangles long, remove the first rectangle and add a new one. Then you need to redraw ALL rectangles every time you refresh the display, using double buffering to prevent screen flickering.

Rectangle collision detection algorithm half working

I am writing an algorithm for collision detection in slick2d + java that I will eventually use in a platformer game that I will be making. How the algorithm works is it detects how much the player is overlapping a rectangle and then moves the player out of the rectangle by that overlap. The problem is, the algorithm has quite a few issues that I can't figure out how to fix. First, sometimes the player move too far out of the rectangle so it looks it is bouncing off it. Secondly sometimes the player is able to move a small but noticeable amount inside of the rectangle. Lastly, if I increase the velocity sometimes the player can pass all the way through the rectangle. This is quite a vague question but I really need some help figuring out what is wrong. Any ideas at all would be greatly appreciated. The source code should compile without any problems if you have Slick2D installed.
Algorithm:
public void Collision(Polygon player, Polygon poly, Vector2f translation){
Vector2f magnitude = new Vector2f();
//Find the vectre of each object
Vector2f p1Centre = new Vector2f(player.getX() + (player.getWidth()/2), player.getY() + (player.getHeight()/2));
Vector2f p2Centre = new Vector2f(poly.getX() + (poly.getWidth()/2), poly.getY() + (poly.getHeight()/2));
//Calculate the distance between the two
Vector2f distance = new Vector2f(p1Centre);
distance.sub(p2Centre);
//Get the absolute distance
Vector2f absDistance = new Vector2f(distance.x<0 ? -distance.x : distance.x, distance.y<0 ? -distance.y : distance.y);
//Get the combined half widths and heights of each object
Vector2f halvedBounds = new Vector2f((player.getWidth() + poly.getWidth())/2.0f, (player.getHeight() + poly.getHeight())/2.0f);
//If the absolute distance is less thate the halved widths heights then there is a collision
if((absDistance.x < halvedBounds.x) && (absDistance.y < halvedBounds.y)){
//Set the magnitude vector to the halved bounds minus the absolute distance
magnitude.x = halvedBounds.x - absDistance.x;
magnitude.y = halvedBounds.y - absDistance.y;
//Only react to the lesser overlap;
if(magnitude.x < magnitude.y){
magnitude.x = (distance.x > 0) ? magnitude.x : -magnitude.x;
magnitude.y = 0;
}
else{
magnitude.y = (distance.y > 0) ? magnitude.y : -magnitude.y;
magnitude.x = 0;
}
//Debug
System.out.println(magnitude.x+" "+magnitude.y);
System.out.println(translation.x+" "+translation.y+"\n");
//Add the magnitude to the player position
position.add(magnitude);
}
}
Full Source:
import java.util.ArrayList;
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;
import org.newdawn.slick.geom.Polygon;
import org.newdawn.slick.geom.Vector2f;
public class TestCode extends BasicGame {
private Vector2f position = new Vector2f(300, 300);
private ArrayList<Polygon> solids;
private Polygon player;
public TestCode(String title) {
super(title);
}
public static void main(String[] args) throws SlickException{
AppGameContainer game = new AppGameContainer(new TestCode("test"));
game.setDisplayMode(800, 600, false);
game.start();
}
#Override
public void render(GameContainer gc, Graphics g) throws SlickException {
if(gc.isPaused()){
g.setColor(Color.red);
g.drawString("Paused", 90, 10);
}else{
g.setColor(Color.green);
g.drawString("Playing", 90, 10);
}
g.setColor(Color.red);
for(Polygon p : solids)
g.fill(p);
g.setColor(Color.cyan);
g.fill(player);
}
#Override
public void init(GameContainer gc) throws SlickException {
gc.setVSync(true);
solids = new ArrayList<Polygon>();
player = new Polygon(new float[]{
50, 50, // upper left point
70, 50, // upper right
70, 90, // lower right
50, 90 // lower left
});
for(int i=0, x=200, y=200; i<10; i++, x+=40){
solids.add(new Polygon(new float[]{
x, y, // upper left point
x+40, y, // upper right
x+40, y+40, // lower right
x, y+40 // lower left
}));
}
}
#Override
public void update(GameContainer gc, int delta) throws SlickException {
Input input = gc. getInput();
Vector2f translation = new Vector2f(0, 0);
if(input.isKeyDown(Input.KEY_UP))
translation.y = -1f;
if(input.isKeyDown(Input.KEY_DOWN))
translation.y = 1f;
if(input.isKeyDown(Input.KEY_LEFT))
translation.x = -1f;
if(input.isKeyDown(Input.KEY_RIGHT))
translation.x = 1f;
translation.normalise();
translation.x*=2;
translation.y*=2;
position.add(translation);
for(Polygon p : solids)
Collision(player, p, translation);
player.setLocation(position);
}
public void Collision(Polygon player, Polygon poly, Vector2f translation){
Vector2f magnitude = new Vector2f();
//Find the vectre of each object
Vector2f p1Centre = new Vector2f(player.getX() + (player.getWidth()/2), player.getY() + (player.getHeight()/2));
Vector2f p2Centre = new Vector2f(poly.getX() + (poly.getWidth()/2), poly.getY() + (poly.getHeight()/2));
//Calculate the distance between the two
Vector2f distance = new Vector2f(p1Centre);
distance.sub(p2Centre);
//Get the absolute distance
Vector2f absDistance = new Vector2f(distance.x<0 ? -distance.x : distance.x, distance.y<0 ? -distance.y : distance.y);
//Get the combined half widths and heights of each object
Vector2f halvedBounds = new Vector2f((player.getWidth() + poly.getWidth())/2.0f, (player.getHeight() + poly.getHeight())/2.0f);
//If the absolute distance is less thate the halved widths heights then there is a collision
if((absDistance.x < halvedBounds.x) && (absDistance.y < halvedBounds.y)){
//Set the magnitude vector to the halved bounds minus the absolute distance
magnitude.x = halvedBounds.x - absDistance.x;
magnitude.y = halvedBounds.y - absDistance.y;
//Only react to the lesser overlap;
if(magnitude.x < magnitude.y){
magnitude.x = (distance.x > 0) ? magnitude.x : -magnitude.x;
magnitude.y = 0;
}
else{
magnitude.y = (distance.y > 0) ? magnitude.y : -magnitude.y;
magnitude.x = 0;
}
//Debug
System.out.println(magnitude.x+" "+magnitude.y);
System.out.println(translation.x+" "+translation.y+"\n");
//Add the magnitude to the player position
position.add(magnitude);
}
}
}
The issue with a high velocity and the player passing through the rectangle has to do with how often you're sampling the collision data.
Lets suppose that I'm really dumb, and I only check for collisions once a second. If an object is moving at 15 meters per second, and there's a 1 meter square in its way. If I check for collisions when the object is 7 meters away from the square, and then one second later, I'll completely miss that the object went through the square.
The way a lot of collision detection libraries deal with this is they have fast moving objects be checked more often than regular objects. How "fast" is your player moving when this happens?
So just turn your problem around: check before moving, not after. If the player would land in the rectangle don't allow him.
And here comes the more important part of your problem: how far is "just touching the surface" (and really depends on how you do your collision detection; if you are doing bounding-box collisions it translates into a calculation, if you are doing pixel-perfect collisions you might have to test a few what-if cases).
Since this happens all the time, try to avoid unnecessary work (why test pixel by pixel, interval splitting might be better approach; do bounding box calculations first, pixel perfect then; for "rectangular enough" objects bounding box ~~ pixel pirfect ...)
Welcomme to the world of programming, it's more about solving problems, not so much about slapping a buch of "paint a spire, move it by x pixels & goto 10" statements together ;-)

Categories