For this program, you will use inheritance to develop an Asteroid class that sat
ID: 3797424 • Letter: F
Question
For this program, you will use inheritance to develop an Asteroid class that satisfies certain requirements. You will also develop a separate AsteroidField test driver class to create a field of asteroids. Your test driver will use the "Blobz.jar" external JAR file discussed in lecture to display your asteroid field in a dynamic simulation context. The output of the program should appear as shown below, with the asteroids all flowing across the field of view in all directions. When the asteroids move offscreen, they will reappear near the opposite corners as described for the "flow" mode discussed in lecture.
To run the simulation, press the "Start New Game" button. The "Pause/Unpause" button will pause and unpause the motion of the objects. Press "Stop" to end the simulation. You can press "Start New Game" to start over while the simulation is running or after the "Stop" button has been pressed, but you must unpause first if the simulation has been paused.
The javadocs folder contains the Java API documentation for the classes in Blobz.jar. This documentation will be useful to you as you build the various parts of your Asteroids game. To view the javadocs, go into that folder and open the index.html file in your browser. Bookmark the page so it is easy to find later. From this page, you will be able to view the Javadocs for all classes in the Blobz package.
1. Create a Java application project called "AsteroidField" in NetBeans. Edit the "packaging" properties so that the source (.java) files will be included in the JAR file.
2. In the Project Properties for your project, select the "Libraries" category. Then, press the "Add JAR/Folder" button. A dialog will appear where you will be able to find and select the Blobz.jar file on your system. Select it. You should now see that Blobz.jar is included in the "Compile-time Libraries" window on the dialog. Select "OK". Your project is now set up to use Blobz.jar.
Program Development
1. Create an Asteroid.java class file in your project for your program. This class must satisfy the following requirements:
(a) it must extend the PolyBlob class, so that it inherits from PolyBlob, which in turn inherits from Blob. The class will will have only a constructor and no other methods.
(b) the constructor must take these three input parameters as arguments: (i) an int that represents the x-component of the asteroid's velocity vector; (ii) an int that represents the y-component of the asteroid's velocity vector; and (iii) a double that represents the angular rotation rate.
(c) the constructor must set the asteroid to start at the offscreen location (-100, -100), since we will be using "flow" mode, as discussed in lecture.
(d) the constructor must also initialize the asteroid's velocity vector with the velocity component values that the constructor receives as input.
(e) the constructor must create a random simple polygon (no lines crossing) shape for the asteroid that has between 5 and 9 sides and is between 10 and 30 pixels in diameter, as discussed in lecture. When displayed, the shape must not have any lines that cross.
2. Create a separate AsteroidField.java test driver class to create a field of asteroids. This class must satisfy the following requirements:
(a) it must implement the BlobGUI interface, as explained in lecture.
(b) it must have a one-line main() method that instantiates the class, as follows:
public static void main ( String [] args) {
new AsteroidField ();
}
(c) the constructor for the class must perform the following actions:
(i) create a sandbox object;
(ii) set the sandbox to "flow" mode;
(iii) set the sandbox to run at 15 frames per second; and
(iv) initialize the sandbox by passing "this" (the AsteroidField object) to the sandbox's init() method.
(d) the class must contain a generate() method, which is required by the BlobGUI interface. The generate() method must perform the following actions:
(i) it must create 10 asteroids using the velocity components and rotational values described here;
(ii) it must randomly choose x and y velocity components for each asteroid, where the x and y components are chosen independently of each other and where each of these values is an integer that may range from -3 to +3, but where zero values are disallowed, all as discussed in lecture;
(iii) it must randomly choose a rotation value of either -.1 or +.1 for each asteroid, with equal probability. Values in between -.1 and +.1 are not permitted; and
(iv) it must add each asteroid to the sandbox.
These are the two files that are needed.
http://www.filedropper.com/blobz
http://www.filedropper.com/javadoc
UCF UCF UCFExplanation / Answer
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.util.*;
//Primary class for the game
public class Asteroids extends Applet implements Runnable, KeyListener{
/**
*
*/
private static final long serialVersionUID = 1L;
//the main thread becomes the game loop
Thread gameloop;
//use this as a double buffer
BufferedImage backbuffer;
//the main drawing object for the back buffer
Graphics2D g2d;
//toggle for drawing bounding boxes
boolean showBounds = false;
//create the asteroid array
int ASTEROIDS = 20;
Asteroid[] ast = new Asteroid[ASTEROIDS];
//create the bullet array
int BULLETS = 10;
Bullet[] bullet = new Bullet[BULLETS];
int currentBullet = 0;
//the player's ship
Ship ship = new Ship();
//create the identity transform (0.0)
AffineTransform identity = new AffineTransform();
//create a random number generator
Random rand = new Random();
//applet init event
public void init(){
//create the back buffer for smooth graphics
backbuffer = new BufferedImage(640, 480,BufferedImage.TYPE_INT_RGB);
g2d = backbuffer.createGraphics();
//set up the ship
ship.setX(320);
ship.setY(240);
//set up the bullets
for (int n = 0; n < BULLETS; n++) {
bullet[n] = new Bullet();
}
//Create the asteroids
for (int n = 0; n < ASTEROIDS; n++) {
ast[n] = new Asteroid();
ast[n].setRotationVelocity(rand.nextInt(3)+1);
ast[n].setX((double)rand.nextInt(600)+20);
ast[n].setY((double)rand.nextInt(440)+20);
ast[n].setMoveAngle(rand.nextInt(360));
double ang = ast[n].getMoveAngle() - 90;
ast[n].setVelX(calcAngleMoveX(ang));
ast[n].setVelY(calcAngleMoveY(ang));
}
//start the user input listener
addKeyListener(this);
}
// applet update event to redraw the screen
public void udpate(Graphics g) {
//start off the transforms at identity
g2d.setTransform(identity);
//erase the background
g2d.setPaint(Color.BLACK);
g2d.fillRect(0, 0, getSize().width, getSize().height);
//print some status information
g2d.setColor(Color.WHITE);
g2d.drawString("Ship: "+ Math.round(ship.getX()) + "," + Math.round(ship.getY()), 5 , 10);
g2d.drawString("Move angle: " + Math.round(ship.getMoveAngle()) + 90, 5, 25);
g2d.drawString("Face angle: " + Math.round(ship.getFaceAngle()),5 , 40);
//draw the game graphics
drawShip();
drawBullets();
drawAsteroids();
//repaint the applet window
paint(g);
}
//drawShip called by applet udpate event
public void drawShip() {
g2d.setTransform(identity);
g2d.translate(ship.getX(), ship.getY());
g2d.rotate(Math.toRadians(ship.getFaceAngle()));
g2d.setColor(Color.ORANGE);
g2d.fill(ship.getShape());
}
//drawbullets called by applet udpate event
public void drawBullets() {
//iterate through the array of bullets
for (int n = 0; n < BULLETS; n++){
//is this bullet currently in use?
if (bullet[n].isAlive()) {
//draw bullet
g2d.setTransform(identity);
g2d.translate(bullet[n].getX(), bullet[n].getY());
g2d.setColor(Color.MAGENTA);
g2d.draw(bullet[n].getShape());
}
}
}
//drawAsteroids called by applet update event
public void drawAsteroids() {
for (int n = 0; n < ASTEROIDS; n++) {
//is this asteroid being used?
if (ast[n].isAlive()){
//draw asteroid
g2d.setTransform(identity);
g2d.translate(ast[n].getX(), ast[n].getY());
g2d.rotate(Math.toRadians(ast[n].getMoveAngle()));
g2d.setColor(Color.DARK_GRAY);
g2d.fill(ast[n].getShape());
}
}
}
//applet window repaint event draw the back buffer
public void paint(Graphics g) {
//draw the back buffer onto the applet window
g.drawImage(backbuffer, 0, 0, this );
}
// thread start event - start the game loop running
public void start() {
//create the gameloop thread for real - time updates
gameloop = new Thread(this);
gameloop.start();
}
// thread run event (game loop)
public void run() {
//acquire the current thread
Thread t = Thread.currentThread();
//keep going as long as the thread is alive
while (t == gameloop) {
try {
//update gameloop
gameUpdate();
//target framerate is 50fps
Thread.sleep(20);
}
catch(InterruptedException e) {
e.printStackTrace();
}
repaint();
}
}
//thread stop event
public void stop() {
//kill the gameloop thread
gameloop = null;
}
//move and animate the objects in the game
private void gameUpdate() {
updateShip();
updateBullets();
updateAsteroids();
checkCollisions();
}
//update the ship position based on velocity
public void updateShip() {
//update ships X position
ship.incX(ship.getVelX());
//warp around left/right
if (ship.getX() < -10)
ship.setX(getSize().width + 10);
else if (ship.getX() > getSize().width + 10)
ship.setX(-10);
//update ships Y position
ship.incY(ship.getVelY());
//wrap around top/bottom
if (ship.getY() < -10)
ship.setY(getSize().height + 10);
else if (ship.getY() > getSize().height + 10)
ship.setY(-10);
}
// update the bullets based on velocity
public void updateBullets() {
//move each of the bullets
for (int n = 0; n < BULLETS; n++) {
//is this bullet being used?
if (bullet[n].isAlive()) {
//update bullets x position
bullet[n].incX(bullet[n].getVelX());
//bullet disappears at left/right edge
if (bullet[n].getX() < 0 || bullet[n].getX() > getSize().width) {
bullet[n].setAlive(false);
}
//update bullets y position
bullet[n].incY(bullet[n].getVelY());
//bullet disappears at top/bottom edge
if (bullet[n].getY() < 0 || bullet[n].getY() > getSize().height) {
bullet[n].setAlive(false);
}
}
}
}
//update the asteroids based on velocity
public void updateAsteroids() {
//move and rotate the asteroids
for (int n = 0; n < ASTEROIDS; n++) {
//is this asteroid being used?
if (ast[n].isAlive()) {
//update asteroid X value
ast[n].incX(ast[n].getVelX());
//warp the asteroid at the screen edges
if (ast[n].getX() < -20)
ast[n].setX(getSize().width + 20);
else if (ast[n].getX() > getSize().width +20)
ast[n].setX(-20);
//update the asteroid Y value
ast[n].incY(ast[n].getVelY());
//warp around bottom and top of screen
if (ast[n].getY() < -20)
ast[n].setY(getSize().height + 20);
else if (ast[n].getY() > getSize().height +20)
ast[n].setY(-20);
//update the asteroids rotation
ast[n].incMoveAngle(ast[n].getRotationVelocity());
//keep the angle within 0-359 degrees
if (ast[n].getMoveAngle() < 0)
ast[n].setMoveAngle(360 - ast[n].getRotationVelocity());
else if (ast[n].getMoveAngle() > 360)
ast[n].setMoveAngle(ast[n].getRotationVelocity());
}
}
}
//test asteroids for collisions with ship or bullets
public void checkCollisions() {
//iterate through the asteroids array
for (int m = 0; m < ASTEROIDS; m++) {
// is this asteroid being used?
if (ast[m].isAlive()) {
//check for collision with bullet
for (int n = 0; n < BULLETS; n++) {
//is this bullet being used?
if (bullet[n].isAlive()) {
//perform the collision test
if (ast[m].getBounds().contains(bullet[n].getX(), bullet[n].getY())) {
bullet[n].setAlive(false);
ast[m].setAlive(false);
continue;
}
}
}
//check for collision with ship
if(ast[m].getBounds().intersects(ship.getBounds())) {
ast[m].setAlive(false);
ship.setX(320);
ship.setY(240);
ship.setFaceAngle(0);
ship.setVelX(0);
ship.setVelY(0);
continue;
}
}
}
}
//key listener events
public void keyReleased(KeyEvent k) {}
public void keyTyped(KeyEvent k) {}
public void keyPressed(KeyEvent k) {
int keyCode = k.getKeyCode();
switch (keyCode) {
case KeyEvent.VK_LEFT:
//left arrow rotates ship left 5 degrees
ship.incFaceAngle(-5);
if(ship.getFaceAngle() < 0) ship.setFaceAngle(360-5);
break;
case KeyEvent.VK_RIGHT:
//right arrow rotates ship right 5 degrees
ship.incFaceAngle(5);
if(ship.getFaceAngle() > 360) ship.setFaceAngle(5);
break;
case KeyEvent.VK_UP:
//up arrow thrust to ship (1/10 normal speed)
ship.setMoveAngle(ship.getFaceAngle() - 90);
ship.incVelX(calcAngleMoveX(ship.getMoveAngle()) * 0.1);
ship.incVelY(calcAngleMoveY(ship.getMoveAngle()) * 0.1);
break;
//CTRL ENTER OR SPACE used to fire weapon
case KeyEvent.VK_CONTROL:
case KeyEvent.VK_ENTER:
case KeyEvent.VK_SPACE:
//fire a bullet
currentBullet++;
if(currentBullet > BULLETS - 1) currentBullet = 0;
bullet[currentBullet].setAlive(true);
//point bullet in same direction as ship is facing
bullet[currentBullet].setX(ship.getX());
bullet[currentBullet].setY(ship.getY());
bullet[currentBullet].setMoveAngle(ship.getFaceAngle() - 90);
//fire bullet at angle of ship
double angle = bullet[currentBullet].getMoveAngle();
double svx = ship.getVelX();
double svy = ship.getVelY();
bullet[currentBullet].setVelX(svx + calcAngleMoveX(angle) * 2);
bullet[currentBullet].setVelY(svy + calcAngleMoveY(angle) * 2);
break;
}
}
//calculate X movement value based on direction angle
public double calcAngleMoveX(double angle) {
return (double) (Math.cos(angle * Math.PI / 180));
}
// calculate Y movement value based on direction angle
public double calcAngleMoveY (double angle) {
return (double) (Math.sin(angle * Math.PI / 180));
}
}
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.