Basically my entire program is to have shapes move across a JFrame,
and the problem I am having is that I cannot get my object to move.
I have a class called Creatures and the constructor creates my body and tail of my fish.
(I'm making an aquarium). This class extends to another class that has a move() method, so that everytime a timer event happens the picture moves.
Again my problem is that I cannot get the picture/shape/object to move.
If anyone could lend a hand I would be most grateful =]
Here is the full class of Creatures
import java.awt.geom.Ellipse2D;
import java.awt.Color;
import java.awt.Polygon;
import java.awt.Graphics2D;
public class Creatures extends Moveable2DShape{
private Color color;
private int delay, number;
private int xPos2, yPos2;
private final int POINTS = 3;
private int []x = new int[POINTS];
private int []y = new int[POINTS];
private double width, height;
Ellipse2D.Double body;
Polygon tail;
public Creatures(int xPos, int yPos, int shapeWidth, int shapeHeight, int bwidth, int bheight, double xSpeed, double ySpeed, Color c){
super(xPos, yPos, shapeWidth, shapeHeight, bwidth, bheight, xSpeed, ySpeed);
color = c;
xPos2 = xPos;
yPos2 = yPos;
width = shapeWidth;
height = shapeHeight;
}
public Polygon triangle(int xPos, int yPos){
x[0] = xPos + 100;
x[1] = x[0];
x[2] = (int)(xPos + width/2);
y[0] = (int)(yPos + (height));
y[1] = yPos;
y[2] = (int)(yPos + height/2);
tail = new Polygon(x,y,POINTS);
return tail;
}
//public void move(){
}
public void draw(Graphics2D g){
body = new Ellipse2D.Double(xPos2, yPos2, width, height);
//System.out.println(xPos2 + " " + yPos2 + " " + width + " " + height);
triangle(xPos2, yPos2);
g.setColor(color);
g.fill(body);
g.fill(tail);
}
}
I'm supposed to override the move() method that is inherited from the Moveabled2DShape class but i havent yet because I just wanted to test out the method before overriding it. But now my problem is that I need to update xPos2 and yPos2
MY FULL SOLUTION OF THE CREATURES CLASS
import java.awt.geom.Ellipse2D;
import java.awt.Rectangle;
import java.awt.Color;
import java.awt.Polygon;
import java.awt.Graphics2D;
public class Creatures extends Moveable2DShape{
private Color color;
private int delay, number, t;
private int xPos, yPos;
private double xSpeed, ySpeed;
private final int POINTS = 3;
private int []x = new int[POINTS];
private int []y = new int[POINTS];
private double width, height;
private boolean dead;
Ellipse2D.Double body;
Polygon tail;
public Creatures(int xPos, int yPos, int shapeWidth, int shapeHeight, int bwidth, int bheight, double xSpeed, double ySpeed, Color c, int type, boolean l){
super(xPos, yPos, shapeWidth, shapeHeight, bwidth, bheight, xSpeed, ySpeed);
color = c;
this.xPos = xPos;
this.yPos = yPos;
this.xSpeed = xSpeed;
this.ySpeed = ySpeed;
width = shapeWidth;
height = shapeHeight;
t = type;
dead = l;
}
/*#x[3] calculate the x position points of the tail
*#y[3] calculate the y position points of the tail
*#tail create the polygon using the points and a defined constant of 3
*#return the polygon #tail*/
public Polygon triangle(int xP, int yP){
x[0] = xP + 100;
x[1] = x[0];
x[2] = (int)(xP + width/2);
y[0] = (int)(yP + (height));
y[1] = yP;
y[2] = (int)(yP + height/2);
tail = new Polygon(x,y,POINTS);
return tail;
}
/*#newBW will determine the new width of the bounding box
*#return the new bounding box width*/
public int newBWidth(){
int newBW;
newBW = (int)(x[0] - getBoundingBoxMaxX()) + (int)getBoundingBoxWidth();
return newBW;
}
/*when called, the move method of Creatures will move along the x-values\
*set the new bounding box with the new calculated width */
public void move(){
this.xPos=(int) (getXPos() - xSpeed);
int overShoot = (int) (xPos + getBoundingBoxWidth() - environmentWidth);
if (xPos <= 0)
{
xPos = 0;
xSpeed = -xSpeed ;
}
else if (overShoot > 0)
{
xPos = (int)(environmentWidth - getBoundingBoxWidth());
xSpeed = - xSpeed ;
}
/*
Reflect the object if it goes too far
*/
overShoot = (int) (yPos + getBoundingBoxHeight() - environmentHeight);
if (yPos <= 0)
{
yPos = 0;
ySpeed = -ySpeed ;
}
else if (overShoot > 0)
{
yPos = (int) (environmentHeight - getBoundingBoxHeight());
ySpeed = - ySpeed ;
}
if(xPos == 0 || xPos == 880){
this.yPos =+ (int)(getYPos() + ySpeed);
}
if(yPos == 650){
this.yPos =+ (int)(getYPos() + ySpeed);
}
// move the shape to the new position
moveTo(xPos,yPos);
setBoundingBox(getXPos() , getYPos() , newBWidth(), height);
}
/*Detect if two bounding boxes intersects with one another if two intersects
*call the collision response method and #return true, else #return false. */
public boolean collisionDetect(Moveable2DShape other){
if(getBoundingBox().intersects(other.getBoundingBox())){
return true;
}
return false;
}
/*#other2 cast the Moveable2DShape object into a Creatures object and compare
*if #other2 object type is greater than the current object then the current object dies
*if the two objects are equal to each other then change the color of both objects randomly
*otherwise #other2 dies. */
public void collisionResponse(Moveable2DShape other){
int []c2 = new int[3];
int []c3 = new int[3];
Creatures other2 = (Creatures) other;
if (getType() < other2.getType()){
fishiesDie();
}else if(getType() == other2.getType()){
for(int a = 0; a < 3; a++){
c2[a] = (int)(Math.random()*255) + 1;
c3[a] = (int)(Math.random()*255) + 1;
}
color = new Color(c2[0], c2[1], c2[2]);
other2.color = new Color(c3[0], c3[1], c3[2]);
}else{
other2.fishiesDie();
}
}
/*#return the type of the fish */
public int getType(){
return t;
}
/*#dead equals to true when called */
public void fishiesDie(){
dead = true;
}
/*#return dead */
public boolean isDead(){
return dead;
}
/*#body draw the general body ellipse
*#g set the colour and draw the general fish shape(body and tail)*/
public void draw(Graphics2D g){
body = new Ellipse2D.Double((int)getXPos(), (int)getYPos() , width, height);
triangle((int)getXPos(), (int)getYPos());
//g.draw(getBoundingBox());
g.setColor(color);
g.fill(body);
g.fill(tail);
}
}
Related
My partner and I are trying to remake Tetris for our final project of the year in my Computer Science class we currently have a for loop that draws individual rectangles in an overwritten paint method.
private final int spacer = 30;
public int getSpacer()
{
return spacer;
}
public void paint(Graphics g) {
setBackground(Color.GRAY);
for(int i = getHeight()/2 - (spacer * 10); i < getHeight()/2 + (spacer * 10); i += spacer) {
for(int x = getWidth()/2 - (spacer * 5); x < getWidth()/2 + (spacer * 5); x += (spacer)) {
g.drawRect(x, i, (spacer), (spacer));
}
}
setForeground(Color.black);
}
The method basically takes the width and height of the window and makes a 10 x 20 grid of boxes that are 30 units, pixels I think, wide.
We'd like to make a Grid.java class that takes in color, the spacer int, and an x and y int. The constructor for Grid.java should draw the exact same thing as the code above using the for loop, but when we tried it gave us a white screen that would not resize with the window.
private final int spacer = 30;
private static Grid[][] arr = new Grid[10][20];
public int getSpacer()
{
return spacer;
}
public void paint(Graphics g) {
setBackground(Color.GRAY);
int countY = 0;
int countX = 0;
for(int y = getHeight()/2 - (spacer * 10); y < getHeight()/2 + (spacer * 10); y += spacer) {
for(int x = getWidth()/2 - (spacer * 5); x < getWidth()/2 + (spacer * 5); x += spacer) {
arr[countX][countY] = new Grid(x, y, spacer, g);
countX++;
}
countY++;
}
setForeground(Color.black);
}
*Grid.java Class*
package Tetris_Shapes;
import javax.swing.*;
import java.awt.*;
public class Grid {
private int x;
private int y;
private int side;
private Graphics g;
public Grid(int x, int y, int side, Graphics g) {
// g.drawRect(x, y, spacer, spacer);
this.x = x;
this.y = y;
this.side = side;
this.g = g;
paint(this.g);
}
private void paint(Graphics g) {
g.drawRect(x, y, side, side);
}
}
When we try and run this we get the white box that doesn't resize. My question is does anyone know of a way to get a constructor to draw shapes. Thank you in advance, this is pretty niche so I'm also going to apologize in advance.
I asked this question on Math.se a few days ago, and got the following answer in pseudocode:
Function RandomCircleInside(centerX, centerY, radius):
Let newRadius = radius * Random()
Let radians = 2.0 * 3.14159265358979323846 * Random()
Let deviation = (radius - newRadius) * Sqrt(Random())
Let newX = centerX + deviation * Cos(radians)
Let newY = centerY + deviation * Sin(radians)
Return (newX, newY, newRadius)
End Function
I changed the pseudocode to Java and added my own changes to fit my needs. The new code looks like this:
Circle createNewCircle(int centerX, int centerY, int radius, int newR, Color newColor) {
int newRadius = radius * Random();
double radians = 2.0 * 3.141592653589793 * Random();
double deviation = (radius - newRadius) * Math.sqrt(Random());
System.out.println(radius + " - " + newRadius + " * sqrt(0 or 1) = " + (radius-newRadius) + " * (0 or 1) = " + deviation);
double newX = centerX + deviation * Math.cos(radians);
System.out.println(centerX + " + " + deviation + " * cos(" + radians + ") = " + (centerX + deviation) + " * " + Math.cos(radians));
double newY = centerY + deviation * Math.sin(radians);
int newCirX = (int) newX;
int newCirY = (int) newY;
Circle newCir = new Circle(newCirX, newCirY, newR*2, newR*2, newR, newColor, true);
return newCir;
}
The code itself is supposed to create a new Circle inside of a preexisting one. I created a circle class that looks like this:
import java.awt.Color;
import java.awt.Graphics;
public class Circle {
public int X, Y, Width, Height, radius;
public Color color;
public boolean toFill;
public Circle(int x, int y, int width, int height, int radius, Color color, boolean fill) {
X = x;
Y = y;
Width = width;
Height = height;
this.radius = radius;
this.color = color;
toFill = fill;
}
public void render(Graphics g) {
g.setColor(color);
for(int i=-5; i<5; i++) {
if(toFill) {
g.fillOval(X+i, Y+i, Width-i, Height-i);
} else {
g.drawOval(X+i, Y+i, Width-i, Height-i);
}
}
}
public boolean contains(Circle pBound) {
int pBoundCenterX = pBound.X+pBound.radius;
int cirCenterX = X+radius;
int diffBetweenCentersX = Math.abs(pBoundCenterX-cirCenterX);
int pBoundCenterY = pBound.Y+pBound.radius;
int cirCenterY = Y+radius;
int diffBetweenCentersY = Math.abs(pBoundCenterY-cirCenterY);
if(diffBetweenCentersX<= (pBound.radius+radius) && diffBetweenCentersX>=Math.abs(pBound.radius-radius)) { // X
if(diffBetweenCentersY>=Math.abs(pBound.radius-radius)) { // Y
return true;
}
}
return false;
}
public int getX() {
return X;
}
public int getWidth() {
return Width;
}
public int getRadius() {
return radius;
}
public void setWidth(int width) {
Width = width;
}
public int getHeight() {
return Height;
}
public void setHeight(int height) {
Height = height;
}
public void setX(int x) {
X = x;
}
public int getY() {
return Y;
}
public void setY(int y) {
Y = y;
}
}
My way of creating the new circle is this:
if(secInGame==timesForCircle[X] && !hasChanged) { // circle 2
Circle cir1 = cir;
cir = createNewCircle(cir1.X+(cir1.Width/2), cir1.Y+(cir1.Height/2), cir1.getRadius(), 135, Color.cyan);
hasChanged = true;
circleOn++;
circ++;
}
Where cir1 is the preexisting Circle and cir is the new circle.
Is there anything I didn't code correctly? I've tried a few different variations, but they all give the same result.
Before I implemented the pseudocode, my circles looked like this:
but now it looks like this:
All of my code can be found on github at: link
I think there are several issues in your code.
1. First of all it is not clear why your Circle has radius, Width and Height. For a circle all 3 things should be the same. Also your render in case toFill is true looks strange. Here is a simplified version (note: I didn't compile it so there might be some bugs):
public class Circle {
public int X, Y, radius;
public Color color;
public boolean toFill;
public Circle(int x, int y, int radius, Color color, boolean fill) {
X = x;
Y = y;
this.radius = radius;
this.color = color;
toFill = fill;
}
public void render(Graphics g) {
g.setColor(color);
final int r2 = 2*radius;
if(toFill) {
g.fillOval(X, Y, r2, r2);
}
else {
for(int i=-5; i<5; i++) {
g.drawOval(X+i, Y+i, r2-i, r2-i);
}
}
}
public boolean contains(Circle pBound) {
int pBoundCenterX = pBound.X+pBound.radius;
int cirCenterX = X+radius;
int diffBetweenCentersX = Math.abs(pBoundCenterX-cirCenterX);
int pBoundCenterY = pBound.Y+pBound.radius;
int cirCenterY = Y+radius;
int diffBetweenCentersY = Math.abs(pBoundCenterY-cirCenterY);
if(diffBetweenCentersX<= (pBound.radius+radius) && diffBetweenCentersX>=Math.abs(pBound.radius-radius)) { // X
if(diffBetweenCentersY>=Math.abs(pBound.radius-radius)) { // Y
return true;
}
}
return false;
}
public int getX() {
return X;
}
public int getRadius() {
return radius;
}
public void setX(int x) {
X = x;
}
public int getY() {
return Y;
}
public void setY(int y) {
Y = y;
}
}
I didn't check your code, but I'd consider as a good practice:
renaming x and y into leftX and topY to avoid confusion with centerX/centerY meaning. Or change meaning to more typical center one.
declaring all your fields as private (see encapsulation);
declaring all your fields as final and remove all the setXyz methods (see immutability)
2. I don't understand why your createNewCircle has newR parameter and at the same time you generate a random newRadius in the first line. One of these definitely should be removed. Given that the parameter is always a constant 135 I think it should be removed.
3. Now I believe the main bug in your translation is in the lines
int newCirX = (int) newX;
int newCirY = (int) newY;
It probably should be something like
int newCirX = (int) newX - newRadius;
int newCirY = (int) newY - newRadius;
It looks like you messed with center vs top-left. Actually I think the fact that you made such a bug is an argument that supports renaming x and y I suggested in item #1.
Hey if i have a simple rectangle class, how can i make it so that it creates that rectangle next to each other in a grid like pattern? maybe like 10 rows 10 columns?
public class Vak {
private int posX = 0;
private int posY = 0;
private int width = 50;
private int height = 50;
private Color colour;
public Vak(Color c, int x, int y){
this.colour = c;
this.posX = x;
this.posY = y;
}
public int vakPosY(){
return this.posY;
}
public int vakPosX(){
return this.posX;
}
public void draw (Graphics g){
g.setColor(this.colour);
g.drawRect(posX, posY, width, height);
}
public void move(int numberPixelsX, int numberPixelsY){
this.posX = this.posX + numberPixelsX;
this.posY = this.posY + numberPixelsY;
}
}
this is my code for rectangle "vak"
Is this what you are looking for?
int mapWidth = 10;
int mapHeight = 10;
// tileWidth and tileHeight should probably be public static const fields or static readonly properties of some class, but I put them here for now.
int tileWidth = 50; // Pixels
int tileHeight = 50; // Pixels
// tiles should probably be a field of a Map class (if you have one)
Vak[][] tiles = new Vak[mapWidth][mapHeight];
for(int x = 0; x < mapWidth; x++)
{
for(int y = 0; y < mapHeight; y++)
{
tiles[x][y] = new Vak(Color.white, x*tileWidth, y*tileHeight);
}
}
And then in the drawing part of the main loop:
for(Vak[] row : tiles)
{
for(Vak tile : row)
{
tile.draw(g);
}
}
I'm working on a java programming exercise where we have to draw a circular spiral using the drawArc method so that the result looks similar to this:
I've been working on this for a while and this is what I have so far:
import java.awt.Graphics;
import javax.swing.JPanel;
import javax.swing.JFrame;
public class CircSpiral extends JPanel {
public void paintComponent(Graphics g) {
int x = 100;
int y = 120;
int width = 40;
int height = 60;
int startAngle = 20;
int arcAngle = 80;
for (int i = 0; i < 5; i++) {
g.drawArc(x, y, width, height, startAngle, arcAngle);
g.drawArc(x + 10, y + 10, width, height, startAngle + 10, arcAngle);
x = x + 5;
y = y + 5;
startAngle = startAngle - 10;
arcAngle = arcAngle + 10;
}
}
public static void main(String[] args) {
CircSpiral panel = new CircSpiral();
JFrame application = new JFrame();
application.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
application.add(panel);
application.setSize(300, 300);
application.setVisible(true);
}
}
My code gives me this result:
I know the problem lies in my arguments for the drawArc method because the numbers aren't right, but I don't know how to go about making the numbers go in a circular manner. Any help is appreciated. Thank you!
Your idea is almost right. I did some modifications. You need to inverse the angle to draw the other side of the spiral and use fixed point to startAngle.
import java.awt.Graphics;
import javax.swing.JPanel;
import javax.swing.JFrame;
public class CircSpiral extends JPanel {
public void paintComponent(Graphics g) {
int x = getSize().width / 2 - 10;
int y = getSize().height/ 2 - 10;
int width = 20;
int height = 20;
int startAngle = 0;
int arcAngle = 180;
int depth = 10;
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) {
// g.drawArc(x + 10, y + 10, width, height, startAngle + 10, -arcAngle);
// x = x - 5;
y = y - depth;
width = width + 2 * depth;
height = height + 2 * depth;
g.drawArc(x, y, width, height, startAngle, -arcAngle);
} else {
// g.drawArc(x + 10, y + 10, width, height, startAngle + 10, arcAngle);
x = x - 2 * depth;
y = y - depth;
width = width + 2 * depth;
height = height + 2 * depth;
g.drawArc(x, y, width, height, startAngle, arcAngle);
}
}
}
public static void main(String[] args) {
CircSpiral panel = new CircSpiral();
JFrame application = new JFrame();
application.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
application.add(panel);
application.setSize(300, 300);
application.setVisible(true);
}
}
If this were my project, yes I'd draw my arcs in a loop, but within the loop, I'd try to make the arc's bounding box bigger but still centered over the same location. To do this I'd decrement x and y by some small constant, say DELTA (which I'd set to == 1), and I'd increment width and height by 2 * DELTA. I'd also leave my arcAngle unchanged but rather would change my startAngle in the loop like so: startAngle = startAngle - arcAngle;.
For example, this:
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JPanel;
import javax.swing.JFrame;
#SuppressWarnings("serial")
public class CircSpiral extends JPanel {
private static final int DELTA = 1;
private static final int ARC_ANGLE = 20;
private static final int PREF_W = 300;
private static final int PREF_H = PREF_W;
private static final int LOOP_MAX = 400;
public void paintComponent(Graphics g) {
int x = PREF_W / 2;
int y = PREF_H / 2;
int width = 1;
int height = 1;
int startAngle = 0;
int arcAngle = ARC_ANGLE;
for (int i = 0; i < LOOP_MAX; i++) {
g.drawArc(x, y, width, height, startAngle, arcAngle);
x = x - DELTA;
y = y - DELTA;
width += 2 * DELTA;
height += 2 * DELTA;
startAngle = startAngle - arcAngle;
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
public static void main(String[] args) {
CircSpiral panel = new CircSpiral();
JFrame application = new JFrame();
application.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
application.add(panel);
application.pack();
application.setLocationRelativeTo(null);
application.setVisible(true);
}
}
Would result in this:
The following code will output this image:
import java.awt.Graphics;
import javax.swing.JPanel;
import javax.swing.JFrame;
public class CircSpiral extends JPanel {
public void paintComponent(Graphics g) {
int centerX = getWidth() / 2;
int centerY = getHeight() / 2;
int numIterations = 5;
int arcWidth = 10;
int arcGrowDelta = 30;
for (int i = 0; i < numIterations; i++) {
g.drawArc(centerX - arcWidth, centerY - arcWidth, 2 * arcWidth, 2 * arcWidth, 0, 180);
arcWidth += arcGrowDelta;
g.drawArc(centerX - arcWidth, centerY - arcWidth, 2 * arcWidth - arcGrowDelta, 2 * arcWidth, 180, 180);
}
}
public static void main(String[] args) {
CircSpiral panel = new CircSpiral();
JFrame application = new JFrame();
application.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
application.add(panel);
application.setSize(300, 300);
application.setVisible(true);
}
}
The idea is very simple, just draw the upper half of a circle, like this:
Then increment the arc size by a constant factor and draw the bottom half of the circle but making the end point of this circle and the upper circle match, for it, just substrate the arcGrowDelta from the bottom circle width:
And repeat.
This is my solution:
package mainpack;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JPanel;
public class SpiralPanel extends JPanel {
private static final long serialVersionUID = 1L;
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
int width = 10;
int height = 10;
int startAngle = 0;
int arcAngle = 180;
int x = (getWidth() - width) / 2;
int y = (getHeight() - height) / 2;
int i = 0;
int t = 0;
while (i < 36) {
g2d.drawArc(x + t, y, width, height, startAngle, arcAngle);
if (i % 2 == 0) {
t -= 10;
}
y -= 5;
width += 10;
height += 10;
startAngle += 180;
i++;
}
}
}
I am a beginner to java and finally managed how to create the spiral.
Here is my code:
int lineLength = 20; //starting line length
int x = getWidth() / 2; //start drawing from center of JPanel
int y = getHeight() / 2; //start drawing from center of JPanel
for( int counter = 0; counter < 10; counter++ )
{
g.drawArc( x, y, lineLength, lineLength, 0, 180 ); //draws top semicircle of equal width and height
lineLength += 20; //increases arc diameter
x -= 20; //moves x coordinate left
g.drawArc( x, y - 10, lineLength, lineLength, 0, -180 ); //draws bottom semicircle; 'y - 10' joins the 2 semicircles
lineLength += 20; //increases arc diameter
y -= 20; //moves y coordinate up
}
If you're willing to let some good old trigonometry do the work, you could use this:
import java.awt. *;
import javax.swing. *;
import java.math.*;
public class Spiral extends JFrame {
public Spiral()
{
// Set Window
setTitle("Spirale");
setSize(1500, 1500);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setVisible(true);
}
public void paint(Graphics g)
{
super.paint(g);
for(double i = 1; i < 50000; i++)
{
int locY = 600 - (int) (Math.cos((Math.PI*i)/1800)*i/50);
int locX = 600 - (int) (Math.sin((Math.PI*i)/1800)*i/50);
g.drawLine(locX, locY, locX, locY);
}
}
public static void main(String[] args) {
new Spiral();
}
}
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Closed 9 years ago.
Improve this question
Well since you folks helped me a lot with my last project, I thought I might find some assistance with the current one :)
The project has us practicing recursion and objects (just started learning about the latter). So we first create a "BasicStar", later a "Snowflake", then comes the "SuperSnowflake" and finally the dreaded "KochCurve".
So I the "BasicStar" was quite easy, and now the idea of the "Snowflake" is to recursively draw "BasicStar"s with smaller radiuses. I have uploaded three images (basic star, which I did successfully, snowflake the way it should be, and my snowflake) so it's easy to understand what I mean. My recursive method draws something very different, and I have no idea what I'm doing wrong. Any help would be great.
Thanks!
(P.S. The Main and Painter classes were made by the university faculty so even if there are things to improve there it won't be relevant. The rest was written by myself)
Main:
package recursion;
import java.util.Scanner;
/*
* the class main get from the user the shape he wish to draw,
* and call the drew method of the desired shape .
*/
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("Please enter the number of the shape you wish to draw:\n" +
" 1-example\n" +
" 2-BasicStar\n" +
" 3-Snowflake\n" +
" 4-SuperSnowflake\n" +
" 5-KochCurve\n" +
" 6-KochSnowflake\n");
int shape = sc.nextInt();
// chooses which shape to draw based on the number received
switch(shape){
/*
* An example given to you so you can see how the painted works.
* This example opens a frame, and draws a red line.
*/
case 1:
drawExample();
break;
case 2:
drawBasicStar();
break;
case 3:
drawSnowflake();
break;
case 4:
drawSuperSnowflake();
break;
case 5:
drawKochCurve();
break;
case 6:
drawKochSnowflake();
break;
default: System.out.println("invalid shape");
}
sc.close();
}
// Draw the example line
public static void drawExample(){
Painter.draw("example");
}
// Draw a BasicStar
public static void drawBasicStar(){
Painter.draw("BasicStar");
}
// Draw a Snowflake
public static void drawSnowflake(){
Painter.draw("Snowflake");
}
// Draw a SuperSnowflake
public static void drawSuperSnowflake(){
Painter.draw("SuperSnowflake");
}
// Draw a KochCurve
public static void drawKochCurve(){
Painter.draw("KochCurve");
}
// Draw a KochSnowflake
public static void drawKochSnowflake(){
Painter.draw("KochSnowflake");
}
}
Painter:
package recursion;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
/*
* open a frame named aShape and drew the given shape
*/
public class Painter extends Component {
private static final long serialVersionUID = 1L;
private static int SIZE = 600;
private static Painter painter;
private static Graphics g;
private static String shape = null;
// Create a frame and display it
public static void draw(String aShape) {
shape = aShape;
JFrame frame = new JFrame(shape);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
painter = new Painter();
frame.add(painter, null);
frame.pack();
frame.setVisible(true);
}
// returns the Frame's width
public static int getFrameWidth () {
return painter.getSize().width;
}
// returns the Frame's height
public static int getFrameHeight () {
return painter.getSize().height;
}
// changes the color of the lines to be drawn
public static void setColor (String color) {
if (color.equals("red")){
g.setColor(Color.red);
}
else if (color.equals("blue")){
g.setColor(Color.blue);
}
else if (color.equals("green")){
g.setColor(Color.green);
}
}
public static void drawLine (Pixel p1, Pixel p2) {
drawLine((int)Math.round(p1.getX()),(int)Math.round(p1.getY()),(int)Math.round(p2.getX()),(int)Math.round(p2.getY()));
}
// Draw a line on the frame
public static void drawLine (int x1, int y1, int x2, int y2) {
g.drawLine(x1, getFrameHeight()-y1, x2, getFrameHeight()-y2);
}
// Set the default size of the window frame to SIZE*SIZE pixels
public Dimension getPreferredSize() {
return new Dimension(SIZE, SIZE);
}
// paint the frame - draw the shape given (call the draw method in that shape object)
public void paint(Graphics g) {
Painter.g = g;
try{
Object myShape = (Class.forName("recursion." + shape)).newInstance();
Object [] objs = null;
Class [] classes = null;
(Class.forName("recursion." + shape)).getMethod("draw", classes).invoke(myShape, objs);
}
catch(Exception e)
{
System.out.println("Can't handle shape " + shape);
System.out.println(e.toString());
System.out.println(e.getCause());
}
}
}
Pixel:
package recursion;
public class Pixel {
private double x;
private double y;
public Pixel(){
x = 0;
y = 0;
}
public Pixel(double x, double y){
this.x = x;
this.y = y;
}
public Pixel(Pixel center){
this();
if(center != null){
this.x = center.x;
this.y = center.y;
}
}
public double getX(){
return x;
}
public double getY(){
return y;
}
public void translate(Pixel p){
this.x = this.x + p.x;
this.y = this.y + p.y;
}
public void rotateRelativeToAxesOrigin(double theta){
double tempX = this.x;
double tempY = this.y;
this.x = ((tempX)*(Math.cos(theta)) - ((tempY)*(Math.sin(theta))));
this.y = ((tempX)*(Math.sin(theta)) - ((tempY)*(Math.cos(theta))));
}
public void rotateRelativeToPixel(Pixel p1, double theta){
double tempX = this.x;
double tempY = this.y;
Pixel translatedPixel = new Pixel(tempX-p1.getX(), tempY-p1.getY());
translatedPixel.rotateRelativeToAxesOrigin(theta);
this.x = translatedPixel.getX() + p1.getX();
this.y = translatedPixel.getY() + p1.getY();
}
}
BasicStar:
package recursion;
public class BasicStar {
private Pixel center;
private double radius;
public BasicStar(){
double height = Painter.getFrameHeight()/2;
double width = Painter.getFrameWidth()/2;
this.center = new Pixel (width, height);
double maxRadius = Math.min(width, height)/2;
this.radius = maxRadius/4;
}
public BasicStar(Pixel center, double radius){
this.center = new Pixel(center);
this.radius = radius;
}
public Pixel getCenter(){
return new Pixel(center);
}
public double getRadius(){
return this.radius;
}
public void draw(){
Pixel begin = new Pixel(this.center);
Pixel end = new Pixel(center.getX() + getRadius(), center.getY());
Painter.drawLine(begin, end);
end.rotateRelativeToPixel(center, (2*Math.PI)/6);
Painter.drawLine(begin, end);
end = new Pixel(center.getX() + getRadius(), center.getY());
end.rotateRelativeToPixel(center, (4*Math.PI)/6);
Painter.drawLine(begin, end);
end = new Pixel(center.getX() + getRadius(), center.getY());
end.rotateRelativeToPixel(center, (6*Math.PI)/6);
Painter.drawLine(begin, end);
end = new Pixel(center.getX() + getRadius(), center.getY());
end.rotateRelativeToPixel(center, (8*Math.PI)/6);
Painter.drawLine(begin, end);
end = new Pixel(center.getX() + getRadius(), center.getY());
end.rotateRelativeToPixel(center, (10*Math.PI)/6);
Painter.drawLine(begin, end);
}
}
Snowflake:
package recursion;
public class Snowflake {
private BasicStar basic;
private int depth;
public Snowflake(){
double height = Painter.getFrameHeight()/2;
double width = Painter.getFrameWidth()/2;
Pixel center = new Pixel (width, height);
double maxRadius = Math.min(width, height)/2;
double radius = maxRadius/4;
this.basic = new BasicStar(center, radius);
this.depth = 2;
}
public Snowflake(BasicStar basic, int depth){
this();
if(basic!=null){
this.basic = basic;
this.depth = depth;
}
}
public int getDepth(){
return this.depth;
}
public BasicStar getBasic(){
return this.basic;
}
public double getRadius(BasicStar basic){
return this.basic.getRadius();
}
public Pixel getBasicCenter(BasicStar basic){
return this.basic.getCenter();
}
public void draw(){
draw(this.depth, basic.getCenter(), basic.getRadius());
}
private void draw(int depth, Pixel center, double radius){
BasicStar basic = new BasicStar(center, radius);
if(depth==1){
basic.draw();
}
else{
Pixel p = new Pixel(center.getX() + radius, center.getY());
draw(depth - 1, p, (radius/3));
for(int i=0; i<6; i=i+1){
p.rotateRelativeToPixel(center, (2*Math.PI)/6);
BasicStar temp = new BasicStar(p, radius/3);
temp.draw();
}
}
}
}
This looks overly complicated to me. To be honest, I did not read all your code, but you can create a simple recursive function for drawing a snowflake just like this:
public void drawSnowflake(Graphics g, int x, int y, int size, int level) {
for (int a = 0; a < 360; a += 60) {
double rad = a * Math.PI / 180;
int x2 = (int) (x + Math.cos(rad) * size);
int y2 = (int) (y + Math.sin(rad) * size);
g.drawLine(x, y, x2, y2);
if (level > 0) {
drawSnowflake(g, x2, y2, size/3, level-1);
}
}
}
What this code does is: It draws the lines of a star using basic trigonometry (don't forget to convert angles to radians!), and then calls itself with a smaller size and level for the positions at the ends of the spikes. Embedding this into an actual GUI is left as an excercise to the reader.