I've been working on this project for last week and can't figure out how to fix it. I feel like I'm so close but can't spot my error!
My assignment calls for me to draw circles along an imaginary line using the Java Graphics class. Draw a circle in the center with a radius of n. Then draw two circles with radius of n/2 whose endpoints intersect with the left and right arc of the circle.
I have been able to draw the 2nd step of two circles to the right and left of the first circle. However, my program is supposed to then draw four circles of the same size recursively. One circle to both the right and left side of the left circle AND one circle to both the right and left side of the right circle. Something is suspect with my code.
Any help would be greatly appreciated.
package fractalcircles;
import java.awt.*;
import javax.swing.*;
public class FractalCircles {
/**
* #param args the command line arguments
*/
public static void main(String[] args)
{ //create a MyCanvas object
MyCanvas canvas1 = new MyCanvas();
//set up a JFrame to hold the canvas
JFrame frame = new JFrame();
frame.setTitle("FractalCircles.java");
frame.setSize(500,500);
frame.setLocation(100,100);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//add the canvas to the frame as a content panel
frame.getContentPane().add(canvas1);
frame.setVisible(true);
}//end main
}//end class
class MyCanvas extends Canvas
{
public MyCanvas()
{} //end MyCanvas() constructor
//this method will draw the initial circle and invisible line
public void paint (Graphics graphics)
{
int x1,x2,y1,y2; //future x and y coordinates
int radius=125; //radius of first circle
int xMid=250, yMid=250; //center point (x,y) of circle
//draw invisible line
graphics.drawLine(0,250,500,250);
//draw first circle
graphics.drawOval(xMid-radius,yMid-radius,radius*2,radius*2);
//run fractal algorithm to draw 2 circles to the left and right
drawCircles(graphics, xMid, yMid, radius);
}
void drawCircles (Graphics graphics, int xMid, int yMid, int radius)
{
//used to position left and right circles
int x1 = xMid-radius-(radius/2);
int y1 = yMid-(radius/2);
int x2 = xMid+radius-(radius/2);
int y2= yMid-(radius/2);
if (radius > 5)
{
//draw circle to the left
graphics.drawOval(x1, y1, (radius/2)*2, (radius/2)*2);
//draw circle to the right
graphics.drawOval(x2, y2, (radius/2)*2, (radius/2)*2);
}
drawCircles (graphics, xMid, yMid, radius/2);
}
Some adapted version using recursion...
Draw the circle, then draw its 2 children by calling the same function again.
void drawCircles(Graphics graphics, int xMid, int yMid, int radius) {
// end recursion
if(radius < 5)
return;
// Draw circle
graphics.drawOval(xMid - radius, yMid - radius, radius * 2, radius * 2);
// start recursion
//left
drawCircles(graphics, xMid-radius, yMid, radius / 2);
//right
drawCircles(graphics, xMid+radius, yMid, radius / 2);
}
It looks to be like you only have one drawCircles call inside your drawCircles function. This can't be right because each time you draw a circle you need to call the recursive function twice. I see that you are drawing two circles, but that is actually backwards.
To get this to work, you need to draw one circle, and call the recursive function twice.
Here is what you need to change:
Make it so that the drawCircle draws one circle, centered on the coordinates
in drawCircle, call drawCircle twice, once with the left circle coords, once with the right
That should do it.
You are only drawing 1 circle from each side of the big circle. You need to change the code. I only write a short fix but don't tested. Good luck
void drawCircles (Graphics graphics, int xMid, int yMid, int radius)
{
//used to position left and right circles
int x1 = xMid-radius-(radius/2);
int x2 = xMid+radius-(radius/2);
int x3 = xMid+radius+(radius/2);
int x4 = xMid-radius+(radius/2);
int y = yMid-(radius/2);
if (radius > 5)
{
//draw 4 circles
graphics.drawOval(x1, y, (radius/2)*2, (radius/2)*2);
graphics.drawOval(x2, y, (radius/2)*2, (radius/2)*2);
graphics.drawOval(x3, y, (radius/2)*2, (radius/2)*2);
graphics.drawOval(x4, y, (radius/2)*2, (radius/2)*2);
}
//left
drawCircles(graphics, xMid-radius, yMid, radius / 2);
//right
drawCircles(graphics, xMid+radius, yMid, radius / 2);
}
Related
I have a simple elevator simulator. The painting class of that simulator, paints a wall on the left side and a wall on the right - both are Line2D Objects. In the center is a rectangle that represents the cabin.
My Member Variables are:
private PaintableElevator paintableObject;
private Line2D wallLeftSide = new Line2D.Double();
private Line2D wallRightSide = new Line2D.Double();
private Rectangle2D elevator = new Rectangle2D.Double();
paintableObject gives the information where to paint as proportions. For example, if it says that the cabin has a height of 0.1, than its height on the panel is: this.getHeight * 0.1
I also have a component Listener that just reacts on rezize Events as follows:
#Override
public void componentResized (ComponentEvent e)
{
wallLeftSide.setLine(new Point2D.Double(0, changeYCoordsOrigin(getHeight() * paintableObject.getTotalHeight())), new Point2D.Double(0, getWidth()));
wallRightSide.setLine(new Point2D.Double(getWidth(), changeYCoordsOrigin(getHeight() * paintableObject.getTotalHeight())), new Point2D.Double(getWidth(), getHeight()));
elevator.setRect(0, changeYCoordsOrigin(getHeight() * paintableObject.getHeightInShaft()), getWidth(), paintableObject.getCabinHeight() * getHeight() *-1);
}
My Problem is that Graphics 2D sets the origin of their coords to the top left hand side. I would like it to have on the button left side. thats why i use my method changeYCoordOrigin()
public double changeYCoordsOrigin (double coord)
{
return getHeight() - coord;
}
My hope was that I could convert my coords by calculating them minus the current height. That worked. But when I want to set a negative height for the rectangle, my component dont show anything.
But this is very important, because I want to drive my little cabin by the following code:
#Override
public void setHeigth (double height)
{
elevator.setRect(0, getHeight() * height, getWidth(), paintableObject.getCabinHeight());
repaint();
}
When just dont use changeYCoordOrigin and use a positive height, my elevator drives down, when i want to drive up. Because of that it is important to change the origin of the coordinates, or simulate that.
My paint Method just paints that objects:
#Override
public void paint (Graphics g)
{
if (g instanceof Graphics2D)
{
Graphics2D g2 = (Graphics2D) g;
g2.draw(wallLeftSide);
g2.draw(wallRightSide);
g2.setBackground(Color.gray);
g2.draw(elevator);
}
}
I was looking to rotate a rectangle by a specific angle, as I have a game using java fx which has comets move at an angle. If the rocket intersects with that comet, the game is over. However, a diagonal comet possesses a rectangle at 0 degrees, which covers unnecessary space. I tried using following code, but the rectangles are still 0 degrees:
public void isRocketHit(){
Rectangle2D rocketrec = new Rectangle2D(rocket.getX(), rocket.getY(), rocket.getImage().getWidth(), rocket.getImage().getHeight());
for(Streak i : rstreaks){
double width = i.getImage().getWidth();
double height = i.getImage().getHeight();
Rectangle2D cometrec = new Rectangle2D(i.gmarkX(), i.gmarkY(), width, height);
double rotationCenterX = (i.gmarkX() + width)/2;
double rotationCenterY = (i.gmarkY() + height)/2;
gc.save();
gc.translate(rotationCenterX, rotationCenterY);
gc.rotate(i.getAngle());
gc.translate(-rotationCenterX, -rotationCenterY);
gc.fillRect(i.gmarkX(), i.gmarkY(), width, height);
gc.setFill(Color.AZURE);
if(rocketrec.intersects(cometrec)){
play = false;
System.out.println("HIT");
}
gc.restore();
}
}
Table t1= new Table(300, 300);
float power=0;
float dx=0;
float dy=0;
void setup()
{
size(1000, 600);
frameRate(10);
}
void draw()
{
strokeWeight(1);
stroke(0, 0, 0);
strokeWeight(10);
stroke(255, 0, 0);
fill(26, 218, 35);
rect(0, 0, 1000, 600);
noStroke();
fill(0);
ellipse(0, 0, 80, 80);
ellipse(1000, 0, 80, 80);
ellipse(0, 600, 80, 80);
ellipse(1000, 600, 80, 80);
strokeWeight(1);
stroke(0, 0, 0);
fill(255);
ellipse(t1.cue_ball.center.x, t1.cue_ball.center.y, 20, 20);
dx=friction(dx);
dy=friction(dy);
if (mousePressed)
{
power+=5;
}
if (t1.cue_ball.center.x+30>1000 || t1.cue_ball.center.x-30<0)
{
dx*=-1;
}
if (t1.cue_ball.center.y+30 >=600 || t1.cue_ball.center.y -30<=0)
{
dy*=-1;
}
t1.cue_ball.center.x +=dx;
t1.cue_ball.center.y +=dy;
}
void mouseReleased()
{
dx=power*2;
dy=power*2;
}
float friction (float c)
{
c*=0.9;
return c;
}
class Ball
{
float rad;
Point center;
Point contact_point;
color col;
Ball ( float a, float b)
{
center = new Point (a+=dx, b+=dy);
//contact_point= new Point(
}
}
class Table
{
Ball [] b_arr;
Stick st;
Ball cue_ball;
Table ( float a, float b )
{
cue_ball= new Ball( a, b);
}
}
class Point
{
float x;
float y;
Point(float a, float b)
{
x=a;
y=b;
}
}
class Stick
{
Point start_p;
Point end_p;
color col;
int length;
}
So we want to add something so that when the ball is clicked, it will move accordingly. For example, if it is clicked in the top left, it will move diagonally right down. If clicked bottom left, it will move diagonally right up. Also, is there a way to correspond this to the angle? So a larger angle between the click point and the center will make a steeper diagonal.
Added lines of code I'm not sure where needs to be added:
t1.cue_ball.center.x+=dx;
t1.cue_ball.center.y+=dy;
dx=t1.cue_ball.center.x-mouseX;
dy=t1.cue_ball.center.y-mouseY;
float n= sqrt(pow(dx,2)+pow(dy,2));
dx*=power/n;
dy*=power/n;
If you have or know how to compute the angle between the x-axis and the cue (I'm assuming this is billiards), then to make the ball go in that direction, if I understand your code correctly, you could just set the dx and dy of the ball that you strike according to
dx = power*cos(angle)
dy = power*sin(angle)
You might have to take the negative angle instead, depending on the coordinate system (if going up is positive or negative in the y-direction), and precisely what angle you compute. The easiest is probably to just plug it in and see what happens!
EDIT:
Not related to your question, but as a matter of style, it might be a good idea to move your logic for moving and drawing the ball to the Ball class. So that every tick, you draw the balls on the screen by calling an appropriate draw() method for each instance of the Ball class. Then it would be much easier to move several balls at once.
EDIT2:
I just realized you can actually solve the problem without trigonometry, if you know the point where you click. Let's say cx,cy is the point where you click, and x,y is the center of the ball, then your dx and dy for the ball can be computed as:
dx = x-cx
dy = y-cy
n = sqrt(dx^2 + dy^2)
dx *= power/n
dy *= power/n
Explanation:
The outgoing velocity for the ball should be in the same direction as the click relative to the ball. So we already have the relative lengths of dx and dy, and to get the right power we just need to normalize and multiply by the power.
I'm working on a simple game and i need these squareBumpers which simply stands idle and when got hit, collides and reflects the ball. But currently the ball just flies through my squareBumpers. I can only use java awt and swing libraries. Here's the code:
class squareBumper {
private int x = 300;
private int y = 300;
private Color color = new Color(66,139,139);
public void paint(Graphics g) {
Rectangle clipRect = g.getClipBounds();
g.setColor(color);
g.fillRect(x, y, 31, 31);
}
}
class BouncingBall {
// Overview: A BouncingBall is a mutable data type. It simulates a
// rubber ball bouncing inside a two dimensional box. It also
// provides methods that are useful for creating animations of the
// ball as it moves.
private int x = 320;
private int y = 598;
public static double vx;
public static double vy;
private int radius = 6;
private Color color = new Color(0, 0, 0);
public void move() {
// modifies: this
// effects: Move the ball according to its velocity. Reflections off
// walls cause the ball to change direction.
x += vx;
if (x <= radius) { x = radius; vx = -vx; }
if (x >= 610-radius) { x = 610-radius; vx = -vx; }
y += vy;
if (y <= radius) { y = radius; vy = -vy; }
if (y >= 605-radius) { y = 605-radius; vy = -vy; }
}
public void randomBump() {
// modifies: this
// effects: Changes the velocity of the ball by a random amount
vx += (int)((Math.random() * 10.0) - 5.0);
vx = -vx;
vy += (int)((Math.random() * 10.0) - 5.0);
vy = -vy;
}
public void paint(Graphics g) {
// modifies: the Graphics object <g>.
// effects: paints a circle on <g> reflecting the current position
// of the ball.
// the "clip rectangle" is the area of the screen that needs to be
// modified
Rectangle clipRect = g.getClipBounds();
// For this tiny program, testing whether we need to redraw is
// kind of silly. But when there are lots of objects all over the
// screen this is a very important performance optimization
if (clipRect.intersects(this.boundingBox())) {
g.setColor(color);
g.fillOval(x-radius, y-radius, radius+radius, radius+radius);
}
}
public Rectangle boundingBox() {
// effect: Returns the smallest rectangle that completely covers the
// current position of the ball.
// a Rectangle is the x,y for the upper left corner and then the
// width and height
return new Rectangle(x-radius, y-radius, radius+radius+1, radius+radius+1);
}
}
Take a look at the classes that implement the Shape interface. There are ellipses and other shapes, and they all implement a intersects(Rectangle2D) method. It might help you if you don't want to perform intersection yourself.
As for dealing with the collision, well, it depends on the level of accuracy you want. Simply deflecting the ball of edges is quite easy. Just determine whether the collided side of the rectangle is vertical or horizontal, and negate the corresponding velocity component accordingly. If you want to handle the corners, well that is a bit more complicated.
You need to detect when the ball has collided with the bumper. You have the boundingBox() method of BouncingBall, this will get you a rectangle that contains your ball. So you need to check if this rectangle intersects your square bumper (which implies a collision), and then do something with that.
I am trying to draw a rectangle in JPanel that would translate and then rotate itself to mimic the movement of a car. I have been able to make the rectangle translate and rotate, however it rotates around the origin of (0,0). I'm very pleased that I was able to have the rectangle move and rotate as I am very new to Java GUI, but I can not seem to get how to have the rectangle rotate around itself, because I experimented more with it, and when I initialized the rectangle and rotate it 45 degrees it's position was changed, which I would assume is the transform matrix that is appended from the rotate method.
I checked through the site on how would I solve this, however I only found how to rotate a rectangle and not on how to rotate and move like the movement of a simulated car. I would presume it is concerning about its transform matrix, but I'm only speculating. So my question is how would I be able to have the rectangle be able to rotate and move around itself and not against a point in JPanel.
Here's the code that I have come up so far:
public class Draw extends JPanel implements ActionListener {
private int x = 100;
private int y = 100;
private double theta = Math.PI;
Rectangle rec = new Rectangle(x,y,25,25);
Timer timer = new Timer(25,this);
Draw(){
setBackground(Color.black);
timer.start();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setColor(Color.white);
rec.x = 100;
rec.y = 100;
g2d.rotate(theta);
g2d.draw(rec);
g2d.fill(rec);
}
public void actionPerformed(ActionEvent e) {
x = (int) (x + (Math.cos(theta))*1);
y = (int) (y + (Math.sin(theta))*1);
theta = theta - (5*Math.PI/180);
repaint();
}
One of two approaches are commonly used:
Rotate the graphics context around the center (x, y) of the Shape, as shown here.
rotate(double theta, double x, double y)
Translate to the origin, rotate and translate back, as shown here.
g2d.translate(this.getWidth() / 2, this.getHeight() / 2);
g2d.rotate(theta);
g2d.translate(-image.getWidth(null) / 2, -image.getHeight(null) / 2);
Note the apparent reverse order of concatenation in the second example.
Addendum: Looking more closely at your example, the following change rotates the Rectangle around the panel's center.
g2d.rotate(theta, getWidth() / 2, getHeight() / 2);
Also, use the #Override annotation, and give your panel a reasonable preferred size:
#Override
public Dimension getPreferredSize() {
return new Dimension(640, 480);
}
Use affine transform to rotate the rectangle and convert it into the rotated polynomial. Check the code below:
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.white);
/* rotate rectnagle around rec.x and rec.y */
AffineTransform at = AffineTransform.getRotateInstance(theta,
rec.x, rec.y);
/* create the plunomial */
Polygon p = new Polygon();
/* path interator of the affine transformed polynomial */
PathIterator i = rec.getPathIterator(at);
while (!i.isDone()) {
double[] points = new double[2];
i.currentSegment(points);
p.addPoint((int) points[0], (int) points[1]);
i.next();
}
g2d.fill(p);
}