/** *=========================================================================== * CSCI298c-java
* Programmer: Ping Wang
* Lab 4: Tank.java is to show Producer/Consumer and monitor concept for * the threads.
* Description:
* There are 4 classes in this project.
* Tank: As a interface for game control and applet will show up in * the screen.
* Producer: Put new enemy position to monitor.
* Consumer: Get the enemy position from the monitor, put new tank position * into the monitor.
* Monitor: Provide synchronized methods, put and get methods.
*============================================================================ */ import java.awt.*; import java.applet.Applet; import java.applet.AudioClip; import java.awt.event.*; /** *=========================================================================== * Class Name: * Tank
* Purpose: * This is an interface for applet
* Import: * None
* Export: * Web page shows the applet and animation. * *============================================================================ */ public class Tank extends Applet implements Runnable { // Locations for tank and enemy private Point tankPoint, enemyPoint; private Point tankStartingPoint, enemyStartingPoint; // Audit sound private AudioClip beginSound, bgSound, fireSound, explodeSound; // Thread declaration private volatile Thread tank = null; private volatile Thread producer, consumer; // Object declaration private Monitor monitor; // Image objects private Image tankImage, enemyImage, enemyImage2; // Flags for this program private boolean b_start = false, b_fire = false, b_stop = false; // Panel objects used to contain button and graphics private Panel canvas, buttonPanel; /** *Method: init()
*Purpose: * Initialization, and load into images and audio sounds.
*Pre-Condition: * None
*Post-Condition: * Initialization is done */ public void init() { // Set layout format setLayout(new BorderLayout(10, 5)); canvas = new Panel(); add(canvas, "Center"); buttonPanel = new Panel(); // Add buttons onto buttonPanel addButton(buttonPanel, "Start", new ActionListener() { /** *Method: actionPerformed()
*Purpose: * Method generated by Button Event
*Pre-Condition: * None
*Post-Condition: * Event method is performaed */ public void actionPerformed(ActionEvent e) { if (b_start == false) { start(); // Start this thread producer.start(); // Start producer thread consumer.start(); // Start consumer thread b_start = true; b_stop = false; } } }); addButton(buttonPanel, "Stop", new ActionListener() { /** *Method: actionPerformed()
*Purpose: * Method generated by Button Event
*Pre-Condition: * None
*Post-Condition: * Event method is performaed */ public void actionPerformed(ActionEvent e) { if (b_stop == false) { b_stop = true; b_start = false; stop(); // Stop all threads } } }); add(buttonPanel, "South"); // Get image files tankImage = getImage(getCodeBase(), "tankImage.gif"); enemyImage = getImage(getCodeBase(), "enemyImage.gif"); enemyImage2 = getImage(getCodeBase(), "enemyImage2.gif"); // Get sounds files beginSound = getAudioClip(getCodeBase(), "beginSound.au"); bgSound = getAudioClip(getCodeBase(), "bgSound.au"); fireSound = getAudioClip(getCodeBase(), "fireSound.au"); explodeSound = getAudioClip(getCodeBase(), "explodeSound.au"); } /** *Method: addButton()
*Purpose: * Add buttons onto comtainer
*Pre-Condition: * Panel p, String s, ActionListener a
*Post-Condition: * Button is added */ public void addButton(Panel p, String s, ActionListener a) { Button b = new Button(s); // Create new Button object p.add(b); // Add button to corresponding container b.addActionListener(a); // Registration of Listener } /** *Method: pause()
*Purpose: * Set Thread sleep time
*Pre-Condition: * int time
*Post-Condition: * Thread sleep time is set */ public void pause(int time) { try{ tank.sleep(time); // Thread sleep for some time }catch(InterruptedException e){} } /** *Method: stop()
*Purpose: * Stop Threads
*Pre-Condition: * None
*Post-Condition: * Threads are stop */ public void stop() { tank = null; // Stop tank thread producer = null; // Stop producer thread consumer = null; // Stop consumer thread bgSound.stop(); // Stop playing background sound } /** *Method: run()
*Purpose: * Run Threads
*Pre-Condition: * None
*Post-Condition: * Threads run */ public void run() { Graphics g; bgSound.loop(); // Play background sound while (b_start == false) { // Display blink sentence to prompt user to click button g = canvas.getGraphics(); g.drawString("Click the start button to begin", 225, 225); pause(1500); g.clearRect(200, 200, 300, 40); pause(500); } // Play beginning sound beginSound.play(); g = canvas.getGraphics(); g.clearRect(0, 0, 600, 600); while(tank != null) { g.drawRect(0, 0, 590, 450); try { // Draw tank image drawTank(tankImage, monitor.getTankPoint()); // Draw enemy image drawEnemy(enemyImage, monitor.getEnemyPoint()); tank.sleep(100); if (monitor.getFireStatus()) { fire(); // Handle fire tank.sleep(1000); // Set fire status back to false monitor.setFireStatus(false); // Produce random location for the enemy int temp_x = (int)(Math.random()*500+50); int temp_y = 10; Point enemyStartingPoint = new Point(temp_x, temp_y); monitor.setEnemyPoint(enemyStartingPoint); } g = canvas.getGraphics(); // Clean this enmey image before new one being drawn g.clearRect(monitor.getEnemyPoint().x, monitor.getEnemyPoint().y-20, 40, 80); // Clean this tank image before new one being drawn g.clearRect(monitor.getTankPoint().x-20, monitor.getTankPoint().y, 90, 50); }catch(Exception e) { e.printStackTrace(); // Print out any stack traces } } } /** *Method: start()
*Purpose: * Thread start. Draw the scence.
*Pre-Condition: * None
*Post-Condition: * Thread run */ public void start() { Point tempPoint; // Produce random starting position of enemy int temp_x = (int)(Math.random() * 500 + 50); int temp_y = 10; tempPoint = new Point(temp_x, temp_y); enemyStartingPoint = tempPoint; // Produce starting position of tank tankStartingPoint = new Point(250, 400); if (tank == null) { monitor = new Monitor(); // Create new Monitor object tank = new Thread(this); // Create new Tank thread monitor.setEnemyPoint(enemyStartingPoint); monitor.setTankPoint(tankStartingPoint); producer = new Producer(monitor); // Create new Producer thread consumer = new Consumer(monitor); // Create new Consumer thread tank.start(); } } /** Method Name: drawTank()
* Purpose: draw graphics
* Pre-Condition: Graphics g, Image aTank, Point aPoint.
* Post-Condition: Graphics is painted */ public void drawTank(Image aTank, Point aPoint) { Image tankImage = aTank; Point tankPoint = aPoint; Graphics g = canvas.getGraphics(); // Draw input tankImage g.drawImage(tankImage, tankPoint.x, tankPoint.y, this); } /** Method Name: drawEnemy()
* Purpose: draw graphics
* Pre-Condition: Graphics g, Image aEnemy, Point aPoint.
* Post-Condition: Graphics is painted */ public void drawEnemy(Image aEnemy, Point aPoint) { Image enemyImage = aEnemy; Point enemyPoint = aPoint; Graphics g = canvas.getGraphics(); // Draw input enemyImage g.drawImage(enemyImage, enemyPoint.x, enemyPoint.y, this); } /** Method Name: drawBullet()
* Purpose: draw bullets shooting and explosion
* Pre-Condition: Point aTankPoint
* Post-Condition: Bullets and explosion graphics is drawnk */ public void drawBullet(Point aTankPoint) { int temp_tank_x = aTankPoint.x; int temp_tank_y = aTankPoint.y; int temp_enemy_x, temp_enemy_y; Graphics g = canvas.getGraphics(); do { // draw bullets g.fillOval(temp_tank_x + 25, temp_tank_y - 5, 4, 4); g.fillOval(temp_tank_x + 25, temp_tank_y - 30, 6, 6); g.fillOval(temp_tank_x + 25, temp_tank_y - 60, 8, 8); pause(50); // clear bullets of last loop g = canvas.getGraphics(); g.clearRect(temp_tank_x + 25, temp_tank_y - 60, 10, 60); temp_tank_y = temp_tank_y - 30; // get coordinates of enemy tank temp_enemy_x = monitor.getEnemyPoint().x; temp_enemy_y = monitor.getEnemyPoint().y; }while((temp_tank_y - 60) > monitor.getEnemyPoint().y); // clean bullets from screen g = canvas.getGraphics(); g.clearRect(temp_tank_x + 25, temp_tank_y - 30, 10, temp_tank_y - temp_enemy_y); // draw explosion around the enemy explode(temp_enemy_x, temp_enemy_y); } /** Method Name: fire()
* Description: Handle fire sound playing and call drawBullet() method.
* Pre-Condition: * None.
* Post-Condition: * Fire sound is played three times, bullets and explosion drawn. */ public void fire() { // loop for playing fire sound for(int i = 0; i < 3; i++) { // play fire sound three times fireSound.play(); } // draw bullets drawBullet(monitor.getTankPoint()); } //The method below was modified from the explodeSequnce method presented //in Greg Murray's past year 298java program. /** Method Name: explode()
* Description: Handle explosion sequence.
* Pre-Condition: int x, int y.
* Post-Condition: Bullets and explosion graphics is drawn */ public void explode(int x, int y) { int destroy_x = x + 15; int destroy_y = y; int counter, temp1, temp2; Graphics g = canvas.getGraphics(); pause(100); explodeSound.play(); for (counter = 0; counter < 20; counter++) { // Produce random numbers temp1 = (int)(Math.random()*counter*4); temp2 = (int)(Math.random()*counter*4); // draw fragments of explosion ; g.setColor(Color.red); g.fillRect(destroy_x + temp1, destroy_y + temp2, counter/3, counter/3); pause(45); g.fillRect(destroy_x + temp1, destroy_y - temp2, counter/3, counter/3); pause(30); g.fillRect(destroy_x - temp1, destroy_y + temp2, counter/3, counter/3); pause(15); g.fillRect(destroy_x - temp1, destroy_y - temp2, counter/3, counter/3); } pause(1000); g.clearRect(destroy_x - 100, destroy_y - 100, 200, 200); } /** Method Name: paint()
* Description: Do nothing
* Pre-Condition: None
* Post-Condition: None */ public void paint(Graphics g) { } } // end of Tank class //****************************************************************************** /** *=========================================================================== * Class Name: * Producer
* Purpose: * This is a producer to produce enemy in the screen. It provides new enemy * locations
* Import: * None
* Export: * Enemy information is produced * *============================================================================ */ class Producer extends Thread { private Monitor monitor; // create monitor object private Point enemyPoint; // enemy information /** *Method: Producer()
*Purpose: * constructor
*Pre-Condition: * Monitor aMonitor
*Post-Condition: * Initialization is done */ public Producer(Monitor aMonitor) { monitor = aMonitor; } /** *Method: run()
*Purpose: * Producer thread runs
*Pre-Condition: * None
*Post-Condition: * Thread runs */ public void run() { int temp_x; int temp_y; while(this != null) { try { enemyPoint = monitor.getEnemyPoint(); // Get enemy position temp_x = enemyPoint.x; temp_y = enemyPoint.y; temp_y++; enemyPoint = new Point(temp_x, temp_y); // Set new enemy position monitor.setEnemyPoint(enemyPoint); // This thread sleep for some time this.sleep((int)(Math.random() * 50)); }catch(InterruptedException e){} } } } // end of Produder class //****************************************************************************** /** *=========================================================================== * Class Name: * Consumer
* Purpose: * This is a consumer to retrive enemy information from monitor . Then, * put new tank location into monitor.
* Import: * None
* Export: * Enemy information are retrived and tank location is modified. * *============================================================================ */ class Consumer extends Thread { private Monitor monitor; // create monitor object private Point enemyPoint, tankPoint; // enemy information /** *Method: Consumer()
*Purpose: * Constructor
*Pre-Condition: * None
*Post-Condition: * Initialization is done */ public Consumer(Monitor aMonitor) { // Create Monitor object monitor = aMonitor; } /** *Method: run()
*Purpose: * Consumer thread runs
*Pre-Condition: * None
*Post-Condition: * Thread runs */ public void run() { int temp_enemy_x; int temp_enemy_y; int temp_tank_x; int temp_tank_y; while(this != null) { try { enemyPoint = monitor.getEnemyPoint(); // Get enemy position temp_enemy_x = enemyPoint.x; tankPoint = monitor.getTankPoint(); // Get tank position temp_tank_x = tankPoint.x; temp_tank_y = tankPoint.y; if (temp_tank_x < temp_enemy_x - 13) { temp_tank_x++; } else if (temp_tank_x > temp_enemy_x - 13) { temp_tank_x--; } else { monitor.setFireStatus(true); } tankPoint = new Point(temp_tank_x, temp_tank_y); monitor.setTankPoint(tankPoint); // Set new tank position // Thread sleeps sometime this.sleep((int)(Math.random()*30)); }catch(InterruptedException e){} } } } // end of Consumer class //****************************************************************************** /** *=========================================================================== * Class Name: * Monitor
* Purpose: * This is a monitor to provided synchronized methods for producer and * consumer.
* Import: * None
* Export: * Locations of enemy and tank images. * *============================================================================ */ class Monitor { // Enemy and tank position information private Point enemyPoint; private Point tankPoint; private boolean b_fire = false; /** *Method: setFireStatus()
*Purpose: * Set new value of boolean variable
*Pre-Condition: * boolean bFire
*Post-Condition: * boolean variable is set with a value */ public synchronized void setFireStatus(boolean bFire) { b_fire = bFire; notifyAll(); } /** *Method: getFireStatus()
*Purpose: * Get value of boolean variable
*Pre-Condition: * None
*Post-Condition: * Value of boolean variable b_fire is returned */ public synchronized boolean getFireStatus() { notifyAll(); return b_fire; } /** *Method: setEnemyPoint()
*Purpose: * Set new position value of enemy
*Pre-Condition: * Point aPoint
*Post-Condition: * enemy postion variable is set with a new value */ public synchronized void setEnemyPoint(Point aPoint) { enemyPoint = aPoint; notifyAll(); } /** *Method: setTankPoint()
*Purpose: * Set new position value of Tank
*Pre-Condition: * Point aPoint
*Post-Condition: * tank postion variable is set with a new value */ public synchronized void setTankPoint(Point aPoint) { tankPoint = aPoint; notifyAll(); } /** *Method: getEnemyPoint()
*Purpose: * Get position value of enemy
*Pre-Condition: * None
*Post-Condition: * Value of position variable enemyPoint is returned */ public synchronized Point getEnemyPoint() { notifyAll(); return enemyPoint; } /** *Method: getTankPoint()
*Purpose: * Get position value of tank
*Pre-Condition: * None
*Post-Condition: * Value of position variable tankPoint is returned */ public synchronized Point getTankPoint() { notifyAll(); return tankPoint; } } // end of Monitor class