// ************************************************** // ** The (void) Cowabunga Game (for Java/Swing) ** // ************************************************** // ** Written by Chadwick ** // ************************************************** //** Running JavaWorld for Swing... import image.*; import world.*; //** Always Test... import tester.*; // Represents the Java Application public class VoidCowabunga{ public static void main(String[] args){ CowWorld start = new CowWorld(); start.bigBang(); } } // Represents a Cartesian point, X/Y come from the // super class, Posn class CartPt extends Posn{ CartPt(int x, int y){ super(x,y); } // Move this CartPt by the given dX/dY void move(int dx, int dy){ this.x = this.x + dx; this.y = this.y + dy; } // Return a new CartPt moved by the given dX/dY CartPt newMove(int dx, int dy){ CartPt n = new CartPt(this.x, this.y); n.move(dx, dy); return n; } // Is this point (offset by dx) off the screen boolean offScreenX(int dx, int maxx){ return this.x < dx || maxx-dx < this.x; } // Is this point (offset by dy) off the screen boolean offScreenY(int dy, int maxy){ return this.y < dy || maxy-dy < this.y; } // Calculate the square of the given number double sqr(double d){ return d*d; } // Calculate the distance between this and that CartPt double dist(CartPt that){ return Math.sqrt(this.sqr(that.x-x) + this.sqr(that.y-y)); } } // Represents a/the Cow class Cow{ // The size of the Cow's step int moveAmt = 7; // Images for a left and right moving Cow Image cowLeft = new FromFile("cow-left.png"); Image cowRight = new FromFile("cow-right.png"); CartPt loc; boolean left; // Convenience constructor, give me X/Y Cow(int x, int y, boolean left){ this(new CartPt(x, y), left); } // Full constructor, takes a CartPt Cow(CartPt loc, boolean left){ this.loc = loc; this.left = left; } // Place this Cow into the given Scene Scene place(Scene scn){ if(left) return scn.placeImage(this.cowLeft, this.loc); else return scn.placeImage(this.cowRight, this.loc); } // Tick this Cow, move then maybe flip void tick(int maxx){ this.move(); this.flip(maxx); } // Make this Cow change direction if it hits the wall void flip(int maxx){ if(this.loc.offScreenX(this.cowLeft.width()/2, maxx)) this.left = !this.left; } // Move this Cow in the direction it's going void move(){ if(left) this.loc.move(-this.moveAmt, 0); else this.loc.move(this.moveAmt, 0); } // Is this Cow within range of the Ship? boolean inRange(Ship s){ return s.inRange(this.loc); } } // Represents a simple Cow World class CowWorld extends VoidWorld{ // Width/Height of the Scene int WIDTH = 320; int HEIGHT = 480; Scene initial = new EmptyScene(this.WIDTH, this.HEIGHT); Image grass = new Rectangle(this.WIDTH, 20, "solid", "darkgreen"); Cow cow; Ship alien; // Default constructor is a fresh Cow and Ship CowWorld(){ this.cow = new Cow(this.WIDTH/2, this.HEIGHT-36, true); this.alien = new Ship(this.WIDTH/2, 50); } CowWorld(Cow cow, Ship alien){ this.cow = cow; this.alien = alien; } // Draw this CowWorld, include the Cow, Ship, and Grass public Scene onDraw(){ return this.cow.place(this.alien.place(this.initial) .placeImage(this.grass, this.WIDTH/2, this.HEIGHT-10)); } // Move the Cow and the Ship, check for abduction public void onTick(){ this.cow.tick(this.WIDTH); this.alien.moveDown(); } // Move the Ship if an arrow key has been hit public void onKey(String ke){ if(ke.equals("down")){ this.alien.moveDown(); }else if(ke.equals("left")){ this.alien.moveHoriz(-10); }else if(ke.equals("right")){ this.alien.moveHoriz(10); } } // Set the tick rate for the Cow world public double tickRate(){ return 0.05; } // Game ends when the Cow is abducted or the ship crashes public boolean stopWhen(){ return (this.cow.inRange(this.alien) || this.alien.crashed(this.HEIGHT-20)); } // Did the aliens Win? public boolean alienWins(){ return (this.cow.inRange(this.alien) && !this.alien.crashed(this.HEIGHT-20)); } // Return the message when the game's over String lastMessage(){ if(this.alienWins()) return "Abduction Success!"; else return "You Crashed!"; } // Last World, Win or Loose public Scene lastScene(){ return this.onDraw().placeImage(new Text(this.lastMessage(), 30, "black"), this.WIDTH/2, 100); } } // Represents an Alien Ship class Ship{ Image ship = new FromFile("ship.png"); Image shipCrash = new FromFile("ship-crash.png"); int dropAmt = 4; CartPt loc; // Convenience Constructor Ship(int x, int y){ this(new CartPt(x, y)); } // Construct a Ship at the given location Ship(CartPt loc){ this.loc = loc; } // Place this Ship into the given Scene Scene place(Scene scn){ if(this.crashed(scn.height()-20)) return scn.placeImage(this.shipCrash, this.loc.newMove(0, -2)); else return scn.placeImage(new Triangle(this.ship.width()/2, "solid", "pink"), this.loc.newMove(0, this.ship.height())) .placeImage(this.ship, this.loc); } // Move/Float this Ship down void moveDown(){ this.loc.move(0, this.dropAmt); } // Move/Float this Ship down void moveHoriz(int dx){ this.loc.move(dx, 0); } // Did this ship crash? boolean crashed(int maxy){ return this.loc.offScreenY(this.ship.height()/2, maxy); } // Is this Ship within range of the Cow location? boolean inRange(CartPt cow){ return this.loc.dist(cow) < this.ship.width()/2; } } // Examples and Tests for VoidCowabunga class VoidCowabungaExamples{ CartPt posn1 = new CartPt(3,4); void testCartPt(Tester t){ t.checkExpect(this.posn1.sqr(5), 25.0); t.checkExpect(this.posn1.newMove(5, 3), new CartPt(8, 7)); t.checkExpect(this.posn1.newMove(-5, -3), new CartPt(-2, 1)); this.posn1.move(5, 3); t.checkExpect(this.posn1, new CartPt(8, 7)); this.posn1.move(-5, -3); t.checkExpect(this.posn1, new CartPt(3, 4)); t.checkExpect(this.posn1.offScreenX(0, 10), false); t.checkExpect(this.posn1.offScreenX(10, 20), true); t.checkExpect(this.posn1.offScreenX(1, 3), true); t.checkExpect(this.posn1.dist(new CartPt(0, 0)), 5.0); t.checkExpect(this.posn1.dist(new CartPt(-3, -4)), 10.0); } Cow cow1 = new Cow(20, 10, false); Cow cow2 = new Cow(new CartPt(20, 10), false); void testCow(Tester t){ t.checkExpect(this.cow1, this.cow2); this.cow1.move(); t.checkExpect(this.cow1, new Cow(27, 10, false)); this.cow1.flip(20); t.checkExpect(this.cow1, new Cow(27, 10, true)); this.cow2.tick(20); t.checkExpect(this.cow2, new Cow(27, 10, true)); } Ship ship1 = new Ship(20, 10); Ship ship2 = new Ship(new CartPt(20, 10)); void testShip(Tester t){ t.checkExpect(this.ship1, this.ship2); t.checkExpect(this.ship1.crashed(5), true); this.ship1.moveDown(); t.checkExpect(this.ship1, new Ship(20, 14)); this.ship1.moveHoriz(5); t.checkExpect(this.ship1, new Ship(25, 14)); this.ship1.moveHoriz(-10); t.checkExpect(this.ship1, new Ship(15, 14)); t.checkExpect(this.ship1.inRange(this.cow1.loc), true); t.checkExpect(this.ship1.inRange(this.cow1.loc.newMove(100, 0)), false); } Cow initCow = new Cow(160, 444, true); CowWorld world1 = new CowWorld(); CowWorld world2 = new CowWorld(this.initCow, new Ship(160, 50)); void testCowWorld(Tester t){ t.checkExpect(this.world1, this.world2); this.world1.onTick(); this.initCow.move(); t.checkExpect(this.world1, new CowWorld(this.initCow, new Ship(160, 54))); this.world1.onKey("down"); t.checkExpect(this.world1, new CowWorld(this.initCow, new Ship(160, 58))); this.world1.onKey("left"); t.checkExpect(this.world1, new CowWorld(this.initCow, new Ship(150, 58))); this.world1.onKey("right"); t.checkExpect(this.world1, new CowWorld(this.initCow, new Ship(160, 58))); t.checkExpect(this.world1.stopWhen(), false); t.checkExpect(new CowWorld(this.initCow, new Ship(160, 480)).stopWhen(), true); t.checkExpect(new CowWorld(this.initCow, new Ship(160, 480)).alienWins(), false); t.checkExpect(new CowWorld(this.initCow, new Ship(160, 440)).alienWins(), true); t.checkExpect(new CowWorld(this.initCow, new Ship(160, 480)).lastMessage(), "You Crashed!"); t.checkExpect(new CowWorld(this.initCow, new Ship(160, 440)).lastMessage(), "Abduction Success!"); } }