package example7_2.game; import java.awt.Point; import java.util.Collections; import java.util.List; import java.util.Random; import javax.swing.JOptionPane; import example7_2.game.characters.*; /** * The Game program */ public class Game { /*package*/ static int timeCounter; // game timer; counts how long the game has run // Modify these constants as you wish to see how the game is affected. /*package*/ static final int BOARDSIZE=500; // size of the board (width & height) in pixels /*package*/ static final int GRIDSIZE=20; // the number of rows and columns the board is divided into /*package*/ static final int TIMER_PAUSE_TIME = 2; // number of milliseconds between each turn /*package*/ static final int GAME_TIME = 100; // number of milliseconds to play the game /*package*/ static final int INITIAL_POINTS = 25; // you start out with this many points /*package*/ static final int TURN_POINTS = 1; // each turn is worth this many points /*package*/ static final int MAX_MOVE_DISTANCE=3; // used to limit how far a character can move each turn /*package*/ static final int ADVANCED_GAME_MODE_TIME = (int)(GAME_TIME * 0.2); // game time when the game mode is switched to advanced private static TagBehavior tagBehavior; // This is the start of the whole program! public static void main(String[] args) { //IMPORTANT NOTE: The way this application deals with Swing is technically incorrect // and somewhat dangerous (if you don't know what you're doing). We should really be // running ALL Swing-related code on the "event dispatch thread", but since we don't // know about threads yet, you'll have to trust that this implementation really works. GameBoard.createBoard("Angry Bees" ); // create the virtual gameboard createFlowers(); // see method below createBees(); // see method below runGame(); // see method below } // This method creates Bees and adds them to the board. Bees are derived from GameCharacter, whose // constructor does the work of initializing various data fields and adding the Bee to the GameBoard in a random location. private static void createBees() { new Swarm("Buzz", "bee-1.jpg", "buzz.wav", MoveBehavior.behaviorType.GREEDY); //MoveBehavior.behaviorType.RANDOM) // Bee.createBee("Buzz", "bee-1.jpg", "buzz.wav", MoveBehavior.behaviorType.RANDOM); // Bee.createBee("Honey", "bee-2.jpg", "buzz.wav", MoveBehavior.behaviorType.SMART); // Bee.createBee("Hive", "bee-2.jpg", "buzz.wav", MoveBehavior.behaviorType.GREEDY); // Bee.createBee("Stinger", "bee-3.jpg", "buzz.wav", MoveBehavior.behaviorType.SUPER_SMART); } // This method creates Flowers and adds them to the board. Flowers are derived from GameCharacter, whose // constructor does the work of initializing various data fields and adding the Flowers to the GameBoard in random locations. private static void createFlowers() { Random r = new Random(System.currentTimeMillis()); // create a random number generator for( int i=0; i<15; i++ ) { // create 15 Flowers int num = 1+r.nextInt(6); // random value from 1 to 6 determines what kind of Flower to create switch(num) { case 1: Flower.createFlower("asterd", "aster.jpg"); break; case 2: Flower.createFlower("coneflower", "coneflower.jpg"); break; case 3: Flower.createFlower("daisy", "daisy.jpg"); break; case 4: Flower.createFlower("rose", "rose.jpg"); break; case 5: Flower.createFlower("violet", "violet.jpg"); break; case 6: Flower.createFlower("nightshade", "nightshade.jpg"); break; } } } // This method runs the actual game. It executes the game as discrete "turns" which each take a fixed amount // of time. After each turn, a timer is decremented, and when the time runs out, the game is over. At each turn, // GameCharacter is given the opportunity to plan a move. The Game then moves each character according to their respective // plan. After all moves are completed, the Game gives each character the opportunity to ask to take some action at the new location, // before proceeding to the next turn. private static void runGame() { timeCounter = GAME_TIME; // initialize the timer to GAME_TIME; it is decremented with each turn until it hits 0 tagBehavior = new StandardTagBehavior(); while(timeCounter > 0 ) { // loop until turns run out, each time making each GameCharacter take a turn if (timeCounter == ADVANCED_GAME_MODE_TIME) { tagBehavior = new AdvancedTagBehavior(); } // Shuffle the collection of characters each turn so that each GameCharacter does not always have the same order in the turn. // This adds some randomness to the game. Collections.shuffle(GameBoard.characters); // In this section, we give each GameCharacter the opportunity to plan a move from its current position // to a new position. for( GameCharacter c: GameBoard.characters ) { // make each GameCharacter plan its next move c.planMove(GameBoard.characters); } // In this section, we make each GameCharacter move from its current position // to its new planned position, using small increments to result in smooth animation. int NSTEPS = 10; for(int count=1; count<=NSTEPS; count++ ) { // take NSTEPS increments to make the GameCharacter move smoothly for( GameCharacter c: GameBoard.characters ) { // for each Prey in the pond, make it take it's turn double step = ((double)count)/NSTEPS; if( count == NSTEPS ) step = 1.0; // ensure exact value of 1.0 executeMove(c, step); try { Thread.sleep(TIMER_PAUSE_TIME); // pause for a few ms } catch(InterruptedException e) { // not used; but required in case something wakes us from our nap /* yawn */ } } } // Finally, at the end of the turn, give each GameCharacter the opportunity to take action on completion of the move for( GameCharacter c: GameBoard.characters ) { c.finishMove(GameBoard.grid.getCharactersAt(c.getTargetRow(), c.getTargetColumn())); // deduct points from Bees for each turn, and award points to Flowers. This is an arbitrary rule of the game. if( c instanceof Bee ) c.setScore( c.getScore()-Game.TURN_POINTS); if( c instanceof Flower ) c.setScore( c.getScore()+Game.TURN_POINTS); c.getImage().repaint(); // update the images } // adjust the time left timeCounter -= TIMER_PAUSE_TIME; // decrement with each turn if(timeCounter < 0) timeCounter = 0; GameBoard.displayTime(timeCounter); // display the time left } GameCharacter winner = null; int winningScore = Integer.MIN_VALUE; for(GameCharacter c: GameBoard.characters) { if(c instanceof Bee && c.getScore() > winningScore) { winner = c; winningScore = c.getScore(); } } if (winner != null) { JOptionPane.showMessageDialog(null, "The winning bee is: " + winner.getName() + " with " + winningScore + " points!"); } } /** * This method must be called from the specific GameCharacter-derived class's * implementation of planMove(). This method validates the planned move to ensure * that it does not put the GameCharacter out of window bounds, etc. * Note that this method may alter the targetPos generated by the GameCharacter's * implementation of planMove in order to keep the target position valid. * @param gc the GameCharater whose planned move is to be validated. */ public static void validateMove( GameCharacter gc ) { Random r = new Random(System.currentTimeMillis()); // random number generator used below // prevent movement beyond the window boundaries if( gc.targetPos.x >= Game.GRIDSIZE ) // leaving the window's right edge gc.targetPos.x = Game.GRIDSIZE-1; if( gc.targetPos.x < 0 ) // ...or left edge gc.targetPos.x = 0; if( gc.targetPos.y >= Game.GRIDSIZE ) // leaving the window's bottom edge gc.targetPos.y = Game.GRIDSIZE-1; if( gc.targetPos.y < 0 ) // ...or top edge gc.targetPos.y = 0; // Now check to see how far the planned move will be. Limit the maximum // distance that can be traveled in any given move, and randomize that limit // a little to make the game more unpredictable. int dist = gc.targetPos.x - gc.getCurrentPosition().x; if( dist > MAX_MOVE_DISTANCE ) gc.targetPos.x = gc.getCurrentPosition().x + 1+r.nextInt(MAX_MOVE_DISTANCE); if( dist < -MAX_MOVE_DISTANCE ) gc.targetPos.x = gc.getCurrentPosition().x - (1+r.nextInt(MAX_MOVE_DISTANCE)); dist = gc.targetPos.y - gc.getCurrentPosition().y; if( dist > MAX_MOVE_DISTANCE ) gc.targetPos.y = gc.getCurrentPosition().y + 1+r.nextInt(MAX_MOVE_DISTANCE); if( dist < -MAX_MOVE_DISTANCE ) gc.targetPos.y = gc.getCurrentPosition().y - (1+r.nextInt(MAX_MOVE_DISTANCE)); gc.moveValid = true; } /* * Manages incremental movement of a GameCharacter. */ private static void executeMove(GameCharacter gc, double step) { if( !gc.moveValid ) // do not move if the planned move has not been validated return; if( gc.score <=0 ) // do not move if score is depleted return; int pixelSize = Game.BOARDSIZE/Game.GRIDSIZE; double incr = (gc.getTargetRow()-gc.getCurrentRow())*pixelSize; // row increment in pixels double incc = (gc.getTargetColumn()-gc.getCurrentColumn())*pixelSize; int r = (int)(gc.getCurrentRow()*pixelSize + incr*step); // new row in pixels int c = (int)(gc.getCurrentColumn()*pixelSize + incc*step); Point imagePos = new Point(c,r); gc.image.setLocation(imagePos); if( step >= 1.0) { // end of move GameBoard.grid.removeAt(gc, gc.getCurrentRow(), gc.getCurrentColumn() ); GameBoard.grid.addAt(gc, gc.getTargetRow(), gc.getTargetColumn() ); gc.setCurrentPosition(gc.getTargetRow(), gc.getTargetColumn()); gc.moveValid = false; // reset the flag for the next turn } } /** * This method retrieves the collection of all GameCharacters on the entire board * @return List of GameCharacters on the board */ public static List getCharacters() { return GameBoard.characters; } /** * This generic "tag" method is called when the current GameCharacter catches * another GameCharacter. This method determines how many points will be awarded * by the tag action. This method implements some simple rules for playing the game: * 1) A tagger must be in the same cell on the game board as the GameCharacter being tagged * 2) A Bee may only tag a Flower (Bees cannot tag other Bees, and Flowers cannot tag anything) * Note this is an arbitrary rule of the game, which you may want to modify... * * @param tagger the GameCharacter doing the tagging (in order to get points) * @param gc the GameCharacter to tag (and get points from) * @return the number of points acquired as a result of tagging */ public static int tag(GameCharacter tagger, GameCharacter gc) { return tagBehavior.tag(tagger, gc); } }