Question: Task Using the World, Ball and Vector classes that we wrote in a recent lab, and the David class utility, write an application that: Creates

Task Using the World, Ball and Vector classes that we wrote in a recent lab, and the David class utility, write an application that:  Creates a World object (recommended dimension: 800x600). [1 pts]  Creates 5 Ball objects (using an array). [1 pts]  Creates a surface for drawing (using David.createCanvas()) using the worlds dimensions. [1 pts]  Preloads a background image (using ImageIO.read()). [1 pts]  Starts a game loop, which refresh the scene continuously (using David.flushCanvas()). [1 pts]  In the game loop, the application:  Draws the background (using g.drawImage()). [1 pts]  Draws each Ball (using a new method ball.draw()). [2 pts]  Advances each Ball, handling bouncing off the limits of the World (modifying ball.tick()). [2 pts]  Bonus: Bounce off the balls edge instead of its center. [2 bonus pts] Changes Ive done a few minor changes to Ball.java (compared to the solution of the related lab):  World has public final members (because we need to be able to read the width and height).  Ball uses a Color instead of an int for its color (because that is what Graphics.setColor() expects).  Ball initializes its attributes relative to the World (to start in the middle, and avoid too big or fast balls).  Ball needs a World when it is constructed, and stores it (to be able to bounce off the limits of the world later in tick()). Ball.java In order to see the balls, we need to draw them. Implement the following method in Ball.java: public void draw(Graphics2D g) { // TODO change color // TODO draw an oval // HINT: g.fillOval(x, y, w, h) works by passing the bounding box rectangle around the oval. // HINT: This means that you probably want w and h to be twice the radius. // HINT: Interpret the this.position as the center of your ball. // HINT: The x and y given to fillOval() are the top left corner, not the center, youll need to compensate. } 1 In order to bounce of the worlds limit, we need to be aware of them when we advance the ball in tick(). public void tick(double seconds) { Vector scaledSpeed = speed.scale(seconds); // TODO bounce off the world limits // HINT: do one dimension at a time. // HINT: bounce doesnt have to be perfect physics (Instructor says: I wouldnt know how myself). // HINT: position.getX() + scaledSpeed.getX() is where your ball will end up if you dont interfere // HINT: position.getY() + scaledSpeed.getY() is where your ball will end up if you dont interfere // HINT: before advancing, check if we would bust the limit if we did advance // HINT: the worlds limit are [0, world.width] and [0, world.height] // HINT: bouncing/reflecting in one dimension is as simple as inverting x: this.speed.initXY(-speed.getX(), speed.getY()); // HINT: bouncing/reflecting in one dimension is as simple as inverting y: this.speed.initXY(speed.getX(), -speed.getY()); // HINT: if you do modify the speed, you need to recalculate scaledSpeed right away before adding it to the position. // BONUS: bounce at the edge of the ball instead of at its center. position.addBy(scaledSpeed); } Hints  Work one step at a time. Compile often.  Print your balls using System.out.println() if you cant see them, thats why we did the toString().  Slow down the simulation time instead of changing the ball speeds to verify your bounce is good enough. // get elapsed time long t1 = System.currentTimeMillis(); double frequency = (t1 - t0) / 1000.0; frequency /= 5; // slow down simulation by a factor of 5. t0 = t1; ... ball[i].tick(frequency); 

---------------------------------------------------------------------

// MAIN CLASS

import java.awt.Graphics2D; import java.awt.Image; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; public class Assignment4 { public static void main(String[] args) throws IOException { // create a World object (recommended dimension: 800x600). [1 pts] // create 5 Ball objects (using an array). [1 pts] // create a surface for drawing (using David.createCanvas()) using the worlds dimensions. [1 pts] // preload a background image (using ImageIO.read()). [1 pts] // start a game loop, which refresh the 'scene' continuously (using David.flushCanvas()). [1 pts] // draw the background (using g.drawImage()). [1 pts] // draw each Ball (using a new method ball.draw()). // advance each Ball, handling bouncing off the limits of the World (modifying ball.tick()). } } //BALL CLASS import java.awt.Color; import java.awt.Graphics2D; public class Ball { // Attributes private Vector position; // pixel private Vector speed; // pixel per second private double radius; // radius, in pixels private Color color; private World world; // Constructor public Ball(World world) { this.world = world; int worldSize = Math.min(world.width, world.height); // initializes the position to the center of the world this.position = new Vector(); this.position.initXY(world.width / 2, world.height / 2); // speed: ball will traverse screen's smallest dimension in 1 to 3 seconds double magnitude = Math.random() * worldSize * 2 / 3 + worldSize / 3; // direction double angle = Math.random() * 360; // [0, 360[ this.speed = new Vector(Math.toRadians(angle), magnitude); // radius (5 to 20% relative to world size) this.radius = Math.random() * .15 * worldSize + .05 * worldSize; // color int r = (int) (Math.random() * 256); // [0, 255] int g = (int) (Math.random() * 256); // [0, 255] int b = (int) (Math.random() * 256); // [0, 255] int a = (int) (Math.random() * 128 + 128); // [128, 255]; this.color = new Color(r, g, b, a); } public String toString() { return "Ball at " + position.toString() + " going at a speed of " + speed.toString(); } // Methods public void draw(Graphics2D g) { // TODO change color [.5 pts] // TODO draw an oval [1.5 pts] // HINT: g.fillOval(x, y, w, h) works by passing the bounding box rectangle around the oval. // HINT: This means that you probably want 'w' and 'h' to be twice the radius. // HINT: Interpret the this.position as the center of your ball. // HINT: The 'x' and 'y' given to fillOval() are the top left corner, not the center, you'll need to compensate. } public void tick(double seconds) { Vector scaledSpeed = speed.scale(seconds); // TODO bounce off the world limits [2 pts] // HINT: do one dimension at a time. // HINT: bounce doesn't have to be perfect physics (Instructor says: I wouldn't know how myself). // HINT: position.getX() + scaledSpeed.getX() is where your ball will end up if you don't interfere // HINT: position.getY() + scaledSpeed.getY() is where your ball will end up if you don't interfere // HINT: before advancing, check if we would bust the limit if we did advance // HINT: the world's limit are [0, world.width] and [0, world.height] // HINT: bouncing/reflecting in one dimension is as simple as inverting x: this.speed.initXY(-speed.getX(), speed.getY()); // HINT: bouncing/reflecting in one dimension is as simple as inverting y: this.speed.initXY(speed.getX(), -speed.getY()); // HINT: if you do modify the speed, you need to recalculate scaledSpeed right away before adding it to the position. // BONUS: bounce at the edge of the ball instead of at its center. [2 bonus points] position.addBy(scaledSpeed); } } 

---------------------------------------------------------------------

// VECTOR CLASS public class Vector {

 // Attributes private double x; private double y; // Constructor and initializer public Vector() { this.x = 0; this.y = 0; } public Vector(double angle, double length) { initAngleLength(angle, length); } public void initXY(double x, double y) { this.x = x; this.y = y; } public void initAngleLength(double rad, double length) { this.x = Math.cos(rad) * length; this.y = Math.sin(rad) * length; } // toString public String toString() { return String.format("(%.2f, %.2f)", x, y); } // Getters/Setters public double getLength() { return Math.sqrt(x * x + y * y); } public double getX() { return x; } public double getY() { return y; } public void scaleBy(double scale) { this.x *= scale; this.y *= scale; } public Vector scale(double scale) { Vector scaled = new Vector(); scaled.initXY(this.x * scale, this.y * scale); return scaled; } public void addBy(Vector vector) { this.x += vector.x; this.y += vector.y; } public void addBy(double dx, double dy) { this.x += dx; this.y += dy; } // Main (Test) public static void main(String [] args) { Vector a = new Vector(0, 1); Vector b = new Vector(Math.PI / 2, 1); System.out.println(a); // should be (1, 0) System.out.println(b); // should be (0, 1) a.addBy(b); System.out.println(a); // should be (1, 1) a.scaleBy(.5); System.out.println(a); // should be (.5, .5) } } 

// WORLD CLASS

public class World { // Attributes public final int width; // in pixels public final int height; // in pixels // Constructor public World(int width, int height) { this.width = width; this.height = height; } } 

// DAVID CLASS

import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.image.BufferedImage; import java.util.HashMap; import java.util.Map; import javax.swing.JFrame; import javax.swing.JPanel; public class David { // Canvas private static class DavidCanvas { private JPanel panel; private BufferedImage backbuffer; private BufferedImage frontbuffer; private void update() { synchronized (frontbuffer) { Graphics2D g = (Graphics2D) frontbuffer.getGraphics(); setQuality(g); g.setColor(Color.WHITE); g.fillRect(0, 0, frontbuffer.getWidth(), frontbuffer.getHeight()); g.drawImage(backbuffer, 0, 0, null); } panel.repaint(); Thread.yield(); } } public static Object createCanvas(int w, int h, String title, boolean kill_on_close) { // center a window in the screen JFrame frame = new JFrame(title); frame.setSize(w, h); frame.setLocationRelativeTo(null); // create a backbuffer for drawing offline, and a front buffer to use when drawing the JPanel final BufferedImage backbuffer = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); final BufferedImage frontbuffer = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); // JPanel for our window JPanel panel = new JPanel() { private static final long serialVersionUID = 1L; public void paint(Graphics g) { synchronized (frontbuffer) { setQuality((Graphics2D) g); int W = this.getWidth(); int H = this.getHeight(); int w = frontbuffer.getWidth(); int h = frontbuffer.getHeight(); // respect aspect ratio (i.e. black bars) double a = w / (double) h; double A = W / (double) H; int offsetX = 0; int offsetY = 0; int aspectW = W; int aspectH = H; // top/down black bars if (a / A > 1) { aspectH = W * h / w; offsetY = (H - aspectH) / 2; } // left/right black bars else { aspectW = H * w / h; offsetX = (W - aspectW) / 2; } g.drawImage(frontbuffer, offsetX, offsetY, aspectW, aspectH, null); } } }; // store everything in my opaque object DavidCanvas canvas = new DavidCanvas(); canvas.panel = panel; canvas.backbuffer = backbuffer; canvas.frontbuffer = frontbuffer; // draw first frame (white) canvas.update(); // show window frame.setContentPane(panel); frame.setVisible(true); if (kill_on_close) frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); return canvas; } public static void syncCanvas(Object _canvas) { // show backbuffer, but don't clear it DavidCanvas canvas = (DavidCanvas) _canvas; canvas.update(); } private static Color transparent = new Color(0, 0, 0, 0); public static void flushCanvas(Object _canvas) { // show backbuffer DavidCanvas canvas = (DavidCanvas) _canvas; canvas.update(); // clear backbuffer int w = canvas.backbuffer.getWidth(); int h = canvas.backbuffer.getHeight(); Graphics2D g = (Graphics2D) canvas.backbuffer.getGraphics(); g.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f)); g.setColor(transparent); g.fillRect(0, 0, w, h); } // @return a Graphics context with all quality rendering setting on public static Graphics2D getGraphics(Object _canvas) { Graphics2D g = (Graphics2D) ((DavidCanvas) _canvas).backbuffer.getGraphics(); setQuality(g); return g; } private static Map hints; static { hints = new HashMap(); hints.put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); hints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); hints.put(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); hints.put(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); } private static void setQuality(Graphics2D g) { g.addRenderingHints(hints); } } 

Step by Step Solution

There are 3 Steps involved in it

1 Expert Approved Answer
Step: 1 Unlock blur-text-image
Question Has Been Solved by an Expert!

Get step-by-step solutions from verified subject matter experts

Step: 2 Unlock
Step: 3 Unlock

Students Have Also Explored These Related Databases Questions!