Breakout – Part 1

Breakout is a classic game. The original game of Breakout was invented by Steve Wozniak before he founded Apple with Steve Jobs.

The main part of the game is to have bricks at the top of the screen, in x rows going downwards, and you have a paddle (bat) and a ball which you hit with the paddle at the bottom of the screen to try and direct the ball to hit the bricks to get rid of them all. The name breakout comes from when you knock down one part of the wall (e.g. left hand side) you can direct the ball to go up that side and then it would have broken out of the bricks and start to knock down the wall from the top.

It is a classic game, and also a game that most people can do, but it is like most things and that is you have to break things into pieces of the puzzle.

To start with, the assignment documentation does make a good start with breaking things down in the pieces, here the main parts that I thought of as well added into the list from the assignment documentation.

  • Build the bricks (wall)
  • Paddle (bat), mouse to move the paddle
  • Bat to hit, and collide with objects
  • Make the ball move around the screen
  • Whilst the ball is moving, check for collisions (with the bricks/paddle)
  • If the ball collides with a brick, remove it and reverse the y direction to go in the opposite direction
  • If the ball collides with the paddle, alter the direction for the ball depending on where it hits the paddle
  • Create some textural information, e.g. score, click to start, etc
  • Extras, music, extra scores/life’s balls that are generated when you hit a brick with the ball
  • When all of the bricks are knocked out, display a message

So to start with, the bricks (wall of bricks), since there is some declarations already setup in the source file

/** Number of bricks per row */
	private static final int NBRICKS_PER_ROW = 10;
 
/** Number of rows of bricks */
	private static final int NBRICK_ROWS = 10;

then we can create a rows of bricks accordingly to the constant (final) values

		int startX, startY = BRICK_Y_OFFSET;
		GRect bricks;
		// iRow = going downwards
		for (int iRow =0; iRow < NBRICK_ROWS; iRow++)
		{
			startX = BRICK_SEP;
			// iAisle = going across
			for (int iAisle = 0; iAisle < NBRICKS_PER_ROW; iAisle++)
			{
				bricks = new GRect(startX,startY, BRICK_WIDTH,BRICK_HEIGHT);
				bricks.setFillColor(colours[iRow]);
				bricks.setFilled(true);
				bricks.setColor(colours[iRow]);
				add(bricks);
				startX += BRICK_WIDTH + BRICK_SEP;
			}
			startY += BRICK_HEIGHT + BRICK_SEP;
		}

here are my private variables so that the rest of the methods can use them to move/create that object in questions

	private GRect paddleObject;
	private GOval ballObject, extraScore, extraLife;
	private GLabel textDisplay, status;
	private double ballVX, ballVY, ballX, ballY;
	private int lifesLeft, score, pauseDelay;
	private RandomGenerator rgen = RandomGenerator.getInstance();
	private Color colours[] = new Color[NBRICK_ROWS];

The next thing, is to create a paddle and also a mouse listener for the mouse movement on the screen to move the paddle in the x direction (left and right). (paddleObject being the paddle from the private variables)

// mouse listener
	public void mouseMoved(MouseEvent e)
	{
		Point movePos = e.getPoint();
		if (movePos.x < (WIDTH- PADDLE_WIDTH))
			paddleObject.setLocation(movePos.x,HEIGHT - (PADDLE_Y_OFFSET + PADDLE_HEIGHT));
	}
// create the paddle
	private void addPaddle()
	{
		paddleObject = new GRect((WIDTH/2) - (PADDLE_WIDTH/2), HEIGHT - (PADDLE_Y_OFFSET + PADDLE_HEIGHT),
								PADDLE_WIDTH, PADDLE_HEIGHT);
		paddleObject.setColor(Color.BLACK);
		paddleObject.setFillColor(Color.BLACK);
		paddleObject.setFilled(true);
		add(paddleObject);
	}

I am not going to go through all of the source code, but just in parts of the interesting stuff, so collisions, to start with we need to know if a object X has any colliding parts to it to another object and thus return the object that it has collided with, why returning the object and also passing in a object reference ? , because then we are able to use a different graphics object (e.g. the ball or a extras) and also return the actual object that we are colliding with.

	// get any Graphics Object surrounding the ball Object, be it the bat and ball, or bat and extras
	private GObject getCollidingObject(GObject ballObj)
	{
		if (!ballObj.isVisible()) return null;
		GPoint ballPoint = ballObj.getLocation();
		GObject coll;
		Point addingPoints[] = new Point[4];
		addingPoints[0]= new Point(0,0);
		addingPoints[1]= new Point(0,BALL_RADIUS);
		addingPoints[2]= new Point(BALL_RADIUS,BALL_RADIUS);
		addingPoints[3]= new Point(BALL_RADIUS,0);
		for (int i =0; i< 4; i++)
		{
			coll = getElementAt(ballPoint.getX()+addingPoints[i].x, ballPoint.getY()+addingPoints[i].y);
			if (coll != null)
					return coll;
		}
		return null;
	}

the reason why I am doing the check to see if we have collided with 4 points, if you think about it, there are 4 points that the object can collide with, top left/right, bottom left/right and if any of those points are not null (e.g. a object) then just exit the for loop and return that object, there is no need to keep on checking because we have found a object.

Next is if we have collided with a brick, and thus see if there is any bricks left, we can either use the number of bricks and every time we collide with one use a local variable to minus from until we reach 0, or go through the list of graphical objects on the screen and see if there is any bricks (GRect) left on the screen if not then all the bricks are gone (of course there still will be one left because that is the paddle (paddleObject)). either way is a good way, just that I use bricks minus way because it uses less speed (e.g. not finding graphics objects).

			bricksLeft--;
			if (bricksLeft == 0) 
			{ 
			        emptyBricks = true; 
				break;
			}
			/*//another way of checking to see if there is any GRects left.!!.
			emptyBricks = true;
			for (int i =0; i < getElementCount(); i++)
			{
				if (getElement(i).getClass().getSimpleName().equalsIgnoreCase("GRect"))
				{
					if (!getElement(i).getClass().equals(paddleObject))
					{
						emptyBricks= false;
						break;
					}
				}
			}
			if (emptyBricks) break;
								 */

the other is if we have collided with the paddle, then move the ball in another direction depending on where on the paddle we hit

	// difference between two points.
	private GPoint differenceBetween(GPoint a, GPoint b)
	{
		return new GPoint(a.getX() - b.getX(), a.getY() - b.getY());
	}
.....
	GPoint difBetween = differenceBetween(ballObject.getLocation(), colliding.getLocation());
	ballVX = (difBetween.getX() - (PADDLE_WIDTH/2))/2;
	ballVY = -(difBetween.getY()/BALL_SPEED);
	// for when the ball may try and bounce of the side of the bat and then the wall!!.
	if (ballVY == 0.0) ballVY = 1.0;
	// move in the opposite direction
	ballVY = -ballVY;

so basically we need to the point on the bat where the ball has hit, left/right top/side, (how far from the middle of the bat) and then alter the balls velocity accordingly.

The rest of the assignment is creating more of the same and textural information (making sure that the ball is not colliding with them and move !!!) and also any extra’s that you can think of, I thought that I would create extras balls that had either extra points (score) or another one that is a extra life if you catch them with your paddle.

Here is the output of the breakout game and also the full source code (I have included the full source code in the zip file above and also the PDF assignment which has more details inside).

Breakout – Part 2

Breakout – Part 2, I have broken it down into 2 parts because of the size of the source code and also the post in general, the first is the problem and solution and this is the solution in code and images.

Here is the screen output of the start of the game.

Breakout  - the start
Breakout - the start

Here is the screen output of the extra life coming down the screen, (the one in grey!!) and also the ball as well, can you catch them both ?

Breakout - extra life coming down
Breakout - extra life coming down

And here is the end of the game with the display information about how much you have scored.

Breakout - the end
Breakout - the end

Here is the full source code from the break out assignment 3, I have included it in the zip file above and also the PDF of the assignment.

/*
 * File: Breakout.java
 * -------------------
 * Name:
 * Section Leader:
 * 
 * This file will eventually implement the game of Breakout.
 */
 
import acm.graphics.*;
import acm.program.*;
import acm.util.*;
 
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
 
public class Breakout extends GraphicsProgram implements MouseListener {
 
/** Width and height of application window in pixels */
	public static final int APPLICATION_WIDTH = 400;
	public static final int APPLICATION_HEIGHT = 600;
 
/** Dimensions of game board (usually the same) */
	private static final int WIDTH = APPLICATION_WIDTH;
	private static final int HEIGHT = APPLICATION_HEIGHT;
 
/** Dimensions of the paddle */
	private static final int PADDLE_WIDTH = 60;
	private static final int PADDLE_HEIGHT = 10;
 
/** Offset of the paddle up from the bottom */
	private static final int PADDLE_Y_OFFSET = 30;
 
/** Number of bricks per row */
	private static final int NBRICKS_PER_ROW = 10;
 
/** Number of rows of bricks */
	private static final int NBRICK_ROWS = 10;
 
/** Separation between bricks */
	private static final int BRICK_SEP = 4;
 
/** Width of a brick */
	private static final int BRICK_WIDTH =
	  (WIDTH - (NBRICKS_PER_ROW - 1) * BRICK_SEP) / NBRICKS_PER_ROW;
 
/** Height of a brick */
	private static final int BRICK_HEIGHT = 8;
 
/** Radius of the ball in pixels */
	private static final int BALL_RADIUS = 10;
 
/** Offset of the top brick row from the top */
	private static final int BRICK_Y_OFFSET = 70;
 
/** Number of turns */
	private static final int NTURNS = 3;
 
	/** the starting pause delay between paddle hits **/ 
	private static final int PAUSE_DELAY = 20;
	/** text size of the display text */
	private static final int TEXT_SIZE = 5;
	/** ball speed */
	private static final double BALL_SPEED = 3.0;
	/** extras - if you catch the extra score, this is the extra value */
	private static final int EXTRA_SCORE_VALUE = 100;
	/** extras speed coming down the screen */
	private static final double EXTRAS_SPEED = 3.0;
 
	public void mouseMoved(MouseEvent e)
	{
		Point movePos = e.getPoint();
		if (movePos.x < (WIDTH- PADDLE_WIDTH))
			paddleObject.setLocation(movePos.x,HEIGHT - (PADDLE_Y_OFFSET + PADDLE_HEIGHT));
	}
 
	// setup the bricks, with different colours
	private void CreateBricks()
	{
// if there is any more colours, rows or less then this could be a problem of creating the list of colours.
		colours[0] = Color.RED;
		colours[1] = Color.RED;
		colours[2] = Color.ORANGE;
		colours[3] = Color.ORANGE;
		colours[4] = Color.YELLOW;
		colours[5] = Color.YELLOW;
		colours[6] = Color.GREEN;
		colours[7] = Color.GREEN;
		colours[8] = Color.CYAN;
		colours[9] = Color.CYAN;
 
		int startX, startY = BRICK_Y_OFFSET;
		GRect bricks;
		// iRow = going downwards
		for (int iRow =0; iRow < NBRICK_ROWS; iRow++)
		{
			startX = BRICK_SEP;
			// iAisle = going across
			for (int iAisle = 0; iAisle < NBRICKS_PER_ROW; iAisle++)
			{
				bricks = new GRect(startX,startY, BRICK_WIDTH,BRICK_HEIGHT);
				bricks.setFillColor(colours[iRow]);
				bricks.setFilled(true);
				bricks.setColor(colours[iRow]);
				add(bricks);
				startX += BRICK_WIDTH + BRICK_SEP;
			}
			startY += BRICK_HEIGHT + BRICK_SEP;
		}
	}
 
	private void addPaddle()
	{
		paddleObject = new GRect((WIDTH/2) - (PADDLE_WIDTH/2), HEIGHT - (PADDLE_Y_OFFSET + PADDLE_HEIGHT),
								PADDLE_WIDTH, PADDLE_HEIGHT);
		paddleObject.setColor(Color.BLACK);
		paddleObject.setFillColor(Color.BLACK);
		paddleObject.setFilled(true);
		add(paddleObject);
	}
 
	private void setUpBall()
	{
		// middle !!
		ballX = WIDTH / 2;
		ballY = HEIGHT / 2;
		// ballVX / VY are the velocity of movement 
		ballObject = new GOval(ballX, ballY, BALL_RADIUS, BALL_RADIUS);
		ballObject.setFillColor(Color.BLACK);
		ballObject.setFilled(true);
		add(ballObject);
		// setup the ball to move a random direction
		ballVX = rgen.nextDouble(1.0, 3.0);
		if (rgen.nextBoolean(0.5)) ballVX -= ballVX;
		ballVY = BALL_SPEED;
	}
 
	// move the ball and check for collision around the screen, if gone to the bottom return true else false
	private Boolean moveBall()
	{
		GPoint ballPoint = ballObject.getLocation();
		if (ballPoint.getX() > WIDTH) ballVX = -ballVX;
		if (ballPoint.getX() <= 0) ballVX = -ballVX;
		if (ballPoint.getY() <= 0) ballVY = -ballVY;
		if (ballPoint.getY() > HEIGHT) return true;//ballVY = -ballVY; // basically lost
		ballObject.move(ballVX,ballVY);
		return false;
	}
 
	// get any Graphics Object surrounding the ball Object, be it the bat and ball, or bat and extras
	private GObject getCollidingObject(GObject ballObj)
	{
		if (!ballObj.isVisible()) return null;
		GPoint ballPoint = ballObj.getLocation();
		GObject coll;
		Point addingPoints[] = new Point[4];
		addingPoints[0]= new Point(0,0);
		addingPoints[1]= new Point(0,BALL_RADIUS);
		addingPoints[2]= new Point(BALL_RADIUS,BALL_RADIUS);
		addingPoints[3]= new Point(BALL_RADIUS,0);
		for (int i =0; i< 4; i++)
		{
			coll = getElementAt(ballPoint.getX()+addingPoints[i].x, ballPoint.getY()+addingPoints[i].y);
			if (coll != null)
					return coll;
		}
		return null;
	}
 
	// display the text on the screen to give some information.
	private void displayText(String text)
	{
		textDisplay = new GLabel(text,(WIDTH/2 - (text.length() * TEXT_SIZE)), HEIGHT/2);
		textDisplay.setFont(Font.SANS_SERIF);
		add(textDisplay);
	}
 
	// display the status , score and also lives left
	private void displayStatus()
	{
		if (status != null) remove(status);
		status = new GLabel("Score : "+score +" : Lives : "+lifesLeft,WIDTH/2, (BRICK_HEIGHT*2));
		add(status);
	}
 
	// difference between two points.
	private GPoint differenceBetween(GPoint a, GPoint b)
	{
		return new GPoint(a.getX() - b.getX(), a.getY() - b.getY());
	}
 
	// type = true - extra life, false - extra score (+100) 
	private void generateExtra(Boolean type, GObject startingPoint)
	{
		if (type)
		{
			// create a extraLife object if not one already
			extraLife.setLocation(startingPoint.getX(), startingPoint.getY());
			extraLife.setColor(Color.MAGENTA);
			extraLife.setFilled(true);
			extraLife.setVisible(true);
			add(extraLife);
		}
		else
		{
			// create a extraScore object if not one already
			extraScore.setLocation(startingPoint.getX(), startingPoint.getY());
			extraScore.setColor(Color.GRAY);
			extraScore.setFilled(true);
			extraScore.setVisible(true);
			add(extraScore);
		}
	}
 
	/* move the extraLife/Score if they are visible.*/
	private void moveExtras()
	{
		if (extraLife.isVisible())
		{
			extraLife.move(0, EXTRAS_SPEED);
			if (extraLife.getLocation().getY() > HEIGHT) remove(extraLife);
		}
		if (extraScore.isVisible())
		{
			extraScore.move(0,EXTRAS_SPEED);
			if (extraScore.getLocation().getY() > HEIGHT) remove(extraScore);
		}
	}
/* Method: run() */
/** Runs the Breakout program. */
	public void run() {
		/* You fill this in, along with any subsidiary methods */
		getGCanvas().setSize(WIDTH, HEIGHT);
		GObject colliding;
		AudioClip bounceSound = MediaTools.loadAudioClip("bounce.au");
		Boolean bottomHit, emptyBricks = true;
		int bricksLeft=0, paddleHit, randomExtra;
 
		extraLife = new GOval(0, 0, BALL_RADIUS,BALL_RADIUS);
		extraScore = new GOval(0,0, BALL_RADIUS, BALL_RADIUS);
		score = 0;
		lifesLeft = NTURNS;
		pauseDelay = PAUSE_DELAY;
		// loop through for the amount of lives
		while (lifesLeft > 0)
		{
			/* setup the display and then ask the user to click to start */
 
			if (emptyBricks)
			{
				/* clear the screen and rebuild the bricks, if come to the end of that level, or just starting*/
				removeAll();
				bricksLeft = NBRICKS_PER_ROW * NBRICK_ROWS;
				CreateBricks();
				addPaddle();
				addMouseListeners();
				emptyBricks = false;
			}
			displayText("Click to start");
			displayStatus();
			waitForClick();
			remove(textDisplay);
			setUpBall();
			paddleHit =0;
			bottomHit =false;
			randomExtra = rgen.nextInt(5);
			/* end of setup display*/
			while (true)
			{
				// moveBall returns true if the bottom has been hit.
				if (moveBall()) {
					bottomHit = true;
					break;
				}
				moveExtras();
				colliding = getCollidingObject(ballObject);
				// if the ball has collided with anything
				if (colliding != null)
				{
					if (!colliding.equals(paddleObject))
					{
						if (!colliding.equals(status))
						{
							if (randomExtra <=0)
							{
								randomExtra = rgen.nextInt(5);
								// create a extra life if next random extra is even else extra score
								if ((randomExtra % 2)==0)
									generateExtra(true,colliding);
								else
									generateExtra(false,colliding);
							}
							// delete the object that we just collided with, e.g. the brick
							if (colliding.getClass().getSimpleName().equalsIgnoreCase("GRect"))
							{
								// decrement the randomExtra 
								randomExtra--;
								// increment the score by finding out the colour of brick that we hit.
								Color collidColor = colliding.getColor();
								for (int i = (NBRICK_ROWS-1); i > 0; i--)
								{
									score++;
									if (colours[i] == collidColor) break;
								}
								displayStatus();
								remove(colliding);
								/* if no more bricks.. exit */
								bricksLeft--;
								if (bricksLeft == 0) 
								{ 
									emptyBricks = true; 
									break;
								}
								/*//another way of checking to see if there is any GRects left.!!.
								emptyBricks = true;
								for (int i =0; i < getElementCount(); i++)
								{
									if (getElement(i).getClass().getSimpleName().equalsIgnoreCase("GRect"))
									{
										if (!getElement(i).getClass().equals(paddleObject))
										{
											emptyBricks= false;
											break;
										}	
									}
								}
								if (emptyBricks) break;
								 */
								ballVY = -ballVY;
							}
						}
					}
					else
					{
						// handle the increase of speed (less delay)
						paddleHit++;
						if ((paddleHit % 7) ==0) pauseDelay--;
 
						bounceSound.play();
						GPoint difBetween = differenceBetween(ballObject.getLocation(), colliding.getLocation());
						ballVX = (difBetween.getX() - (PADDLE_WIDTH/2))/2;
						ballVY = -(difBetween.getY()/BALL_SPEED);
						// for when the ball may try and bounce of the side of the bat and then the wall!!.
						if (ballVY == 0.0) ballVY = 1.0;
						// move in the opposite direction
						ballVY = -ballVY;
					}
				}
				/* extra items */
				colliding = getCollidingObject(extraLife);
				if (colliding != null)
				{
					if (colliding.equals(paddleObject))
					{
						extraLife.setVisible(false);
						lifesLeft++;
						displayStatus();
					}
				}
				colliding = getCollidingObject(extraScore);
				if (colliding != null)
				{
					if (colliding.equals(paddleObject))
					{
						extraScore.setVisible(false);
						score+=EXTRA_SCORE_VALUE;
						displayStatus();
					}
				}
				pause(pauseDelay);
			}
			if (bottomHit) 
			{
				lifesLeft--;
				displayStatus();
				if (lifesLeft > 0)
				{
					displayText("Bottom hit : lives left = " + lifesLeft);
				}
				else 
					displayText("End of Game : your score " + score);
			}
			if (emptyBricks)
				displayText("Yeppy you do it!! click to start again");
			waitForClick();
			remove(textDisplay);
		}
	}
 
	private GRect paddleObject;
	private GOval ballObject, extraScore, extraLife;
	private GLabel textDisplay, status;
	private double ballVX, ballVY, ballX, ballY;
	private int lifesLeft, score, pauseDelay;
	private RandomGenerator rgen = RandomGenerator.getInstance();
	private Color colours[] = new Color[NBRICK_ROWS];
}

Problem 5

The problem is “Determining the Range, Write a ConsoleProgram that reads in a list of integers, one per line, until a sentinel value of 0 (which you should be able to change easily to some other value). When the sentinel is read, your program should display the smallest and largest values in the list.

Your program should handle the following special cases:

  • If the user enters only one value before the sentinel, the program should report that value as both the largest and smallest.
  • If the user enters the sentinel on the very first input line, then no values have been entered, and your program should display a message to that effect.

So once again broken down the problem into parts, first part need to read in the values from the keyboard and the next part is to set the lowest and the highest values (whilst making sure that no value takes the sentinel value).

Here is a example of the output from the running program

This program finds the smallest and largest integers in a list.  Enter values, one per line, using a 0 to signal the end of the list
?32
?2
?4
?5
?45
?1
?0
Smallest value was 1
Largest value was 45

source code in full, I have included within zip file and also the PDF file of the full assignment problems.

/*
 * File: FindRange.java
 * --------------------
 * This program is a stub for the FindRange problem, which finds the
 * smallest and largest values in a list of integers.
 */
 
import acm.program.*;
import java.io.Console;
 
public class FindRange extends ConsoleProgram {
 
	public void run() {
		int readInValue=sential;
		println("This program finds the smallest and largest integers in a list.  Enter values, one per line, using a "+sential+" to signal the end of the list");
		do 
		{
			readInValue = readInt("?");
			if (readInValue != sential)
			{
				if (readInValue > largestValue)
					largestValue = readInValue;
				if (readInValue < smallestValue || smallestValue == sential)
					smallestValue = readInValue;
			}
		} while (readInValue != sential);
		if (largestValue == smallestValue && largestValue == sential)
		{
			println("No values inputted");
		}
		else
		{
			println("Smallest value was "+ smallestValue);
			println("Largest value was " + largestValue);
		}
	}
 
	private int largestValue = 0, smallestValue = 0;
	private static final int sential = 0;
}

Problem 3

The problem 3 is Graphics Hierarchy : which means to write a GraphicsProgram subclass that draws a partial diagram of the acm.graphics class hierarchy (if you look below at the output to see what it does look like), the rules as such are

  • The width and height of the class boxes should be specified as named constants so that they are easy to change.
  • The labels should be centered in their boxes. You can find the width of a label by calling label.getWidth() and the height it extends above the baseline by calling label.getAscent(). If you want to center a label, you need to shift its origin by half of these distances in each direction.
  • The connecting lines should start and end at the center of the appropriate edge of the box.
  • The entire figure should be centered both vertically and horizontally.

The way that I looked at the problem was to break it into 2 parts, one is displaying the box on the screen with the text centred within that box. And the second part was to display the boxes within the correct part on the screen.

The first part of the problem, only need to pass in the X,Y coordinates and the text and then find the size of the text and move that text to the middle of the box, the second part is place the boxes within the screen accordingly to the size of the screen and the boxes dimensions, thus bottom four they are centred in the middle (screen width / 2 – ((box width * 4) / 2)), then join to the middle of the boxes to the middle of the top box.

Here is the output of the Graphics Hierarchy problem,

Graphics Hierarchy
Graphics Hierarchy

Here is the java source file, but the zip file above has the whole assignment within it.

/*
 * File: GraphicsHierarchy.java
 * ----------------------------
 * This program is a stub for the GraphicsHierarchy problem, which
 * draws a partial diagram of the acm.graphics hierarchy.
 */
 
import acm.graphics.*;
import acm.program.*;
 
public class GraphicsHierarchy extends GraphicsProgram {
 
	private void createBox(int X, int Y, String name)
	{
		GRect gObjectBox = new GRect(X, Y, boxWidth, boxHeight);
		GLabel text = new GLabel(name);
 
		// replace the X,Y with the new cords to place the text into the middle of the box
		X += (boxWidth / 2) - (text.getWidth()/2);
		Y += (boxHeight / 2) + (text.getAscent()/2);
		text.setLocation(X, Y);
 
		add(gObjectBox);
		add(text);
	}
 
	public void run() {
		// You fill this in
		// find the centre, to then build around it
		int centreX = getWidth() / 2;
		int centreY = (getHeight() / 2)-boxHeight;
 
		String names[] = new String[5];
		names[0] = "GObject";
		names[1] = "GLabel";
		names[2] = "GLine";
		names[3] = "GOval";
		names[4] = "GRect";
 
		createBox(centreX - (boxWidth / 2), centreY - (rowDistances / 2),names[0]);
 
		int placeX = centreX - ((belowBoxs * boxWidth)/2) - ((belowBoxs * boxDistances)/2);
		for (int i =0; i < belowBoxs; i++)
		{
			createBox(placeX, centreY + (rowDistances / 2), names[i+1]);
			GLine joiningLine = new GLine(centreX, centreY - ((rowDistances / 2)-boxHeight),
										placeX + (boxWidth/2), centreY + (rowDistances/2));
			add(joiningLine);
			placeX += (boxWidth + boxDistances);
		}
	}
 
	private static final int belowBoxs = 4;
	private static final int boxWidth = 100;
	private static final int boxHeight = 50;
	private static final int boxDistances = 20;
	private static final int rowDistances = 150;
}

Problem 2

This problem 2 is “Rainbow Write a GraphicsProgram subclass that draws a rainbow”, the basics of the problem are “Starting at the top, the six arcs are red, orange, yellow, green, blue, and magenta, respectively; cyan makes a lovely colour for the sky. The top of the arc should not be off the screen. Each of the arcs in the rainbow should get clipped along the sides of the window,and not along the bottom. Your rainbow should be symmetric and nicely drawn, regardless of window size.”

The way that I thought about this, is to basically use the GOval to create a circle that is placed in the centre width and slowly go down on the Y coordinates, the size of the GOval is going to be twice the size of the screen itself, thus will meet the problem above. I setup a array of colours, that will then go through within a for loop to draw the GOval(circles) on the screen as below

Color colours[] = new Color[7];
colours[0] = Color.RED;
colours[1] = Color.ORANGE;
colours[2] = Color.YELLOW;
colours[3] = Color.GREEN;
colours[4] = Color.BLUE;
colours[5] = Color.MAGENTA;
colours[6] = Color.CYAN;
 
for (int i =0; i < 7; i++)
{
	GOval newCircle = new GOval(-getWidth()/2,10+(i*10), getWidth()*2, getHeight()*2);
	newCircle.setColor(colours[i]);
	newCircle.setFillColor(colours[i]);
	newCircle.setFilled(true);
	add(newCircle);
}

Here is my output of my Rainbow to the solution of the problem

CS106A Assignment 2 Problem 2
CS106A Assignment 2 Problem 2

I have included the full source code in the zip file above., but here is the full source code for this problem.

/*
 * File: Rainbow.java
 * ------------------
 * This program is a stub for the Rainbow problem, which displays
 * a rainbow by adding consecutively smaller circles to the canvas.
 */
 
import acm.graphics.*;
import acm.program.*;
import java.awt.*;
 
public class Rainbow extends GraphicsProgram {
 
	public void run() {
		Color colours[] = new Color[7];
		colours[0] = Color.RED;
		colours[1] = Color.ORANGE;
		colours[2] = Color.YELLOW;
		colours[3] = Color.GREEN;
		colours[4] = Color.BLUE;
		colours[5] = Color.MAGENTA;
		colours[6] = Color.CYAN;
 
		GRect background = new GRect(0,0,getWidth(), getHeight());
		background.setColor(Color.CYAN);
		background.setFillColor(Color.CYAN);
		background.setFilled(true);
		add(background);
 
		for (int i =0; i < 7; i++)
		{
			GOval newCircle = new GOval(-getWidth()/2,10+(i*10), getWidth()*2, getHeight()*2);
			newCircle.setColor(colours[i]);
			newCircle.setFillColor(colours[i]);
			newCircle.setFilled(true);
			add(newCircle);
		}
	}
}