/*********************************************** * CS2510 Spring 2011 * Lecture #8 * An example of a simple game ***********************************************/ import image.*; import world.*; import tester.*; import java.util.*; // add methods to the Posn class class CartPt extends Posn{ CartPt(int x, int y){ super(x,y); } // determine whether this CartPt is close to the given Posn boolean closeTo(Posn that){ return (Math.abs(this.x - that.x) < 3) && Math.abs(this.y - that.y) < 3; } } /** A simple example of World. * A World consists of a red circle with white middle and a blue blob. * On tick, the circle moves in the current direction (initially up). * On key event, the direction changes to the given one (up or down). * On mouse click, the circle moves to the location of the mouse. * When the circle center moves off the screen, * or when the circle gets too close to the pesky blue blob, * the World ends. */ class SimpleWorld extends World{ RedCircle rc; // the red circle BlueBlob bb; // the pesky blue blob /** Construct an empty World */ SimpleWorld(RedCircle rc, BlueBlob bb){ this.rc = rc; this.bb = bb; } /** Template: * Fields: * ... this.rc ... -- RedCircle * ... this.bb ... -- BlueBlob * * Methods: * ... this.tickRate() ... -- double * ... this.drawWorld(Scene) ... -- Scene * ... this.onDraw() ... -- Scene * ... this.onMouse(int, int, String) ... -- SimpleWorld * ... this.onTick() ... -- SimpleWorld * ... this.onKey(String) ... -- SimpleWorld * ... this.stopWhen() ... -- boolean */ /** Set the tick rate to 25/second */ double tickRate(){ return 0.04; } /** this world draws itself within the given scene */ Scene drawWorld(Scene scene){ return this.bb.drawBlueBlob(this.rc.drawRedCircle(scene)); } /** To draw the World, draw the world into an EmptyScene */ Scene onDraw(){ return this.drawWorld(new EmptyScene(400, 400)); } /** When the mouse is clicked, move the circle to the mouse location */ SimpleWorld onMouse(int x, int y, String me){ if(me.equals("button-down")){ return new SimpleWorld(this.rc.moveTo(x, y), this.bb); } else{ return this; } } /** On tick, move the circle in its current direction. */ SimpleWorld onTick(){ return new SimpleWorld(this.rc.move(), this.bb); } /** On up or down key event, set the direction to the specified one * Ignore all other key events */ SimpleWorld onKey(String ke){ return new SimpleWorld(this.rc.onKey(ke), this.bb); } /** Stop the world when the circle moves off the screen */ boolean stopWhen(){ return this.rc.offScreen() || this.rc.hitBlob(this.bb); } } /** A blue blob inside the world */ class BlueBlob{ int x; // the horizontal coordinate int y; // the vertical coordinate /** the image of the blue blob */ Image blobImage = new Circle(10, "solid", "blue"); /** Construct the blue blob */ BlueBlob(int x, int y){ this.x = x; this.y = y; } /** Template: * Fields: * ... this.x ... -- int * ... this.y ... -- int * * Methods: * ... this.drawBlueBlob(Scene) ... -- Scene * ... this.closeTo(int x, int y) ... -- boolean */ /** this blob places itself at its location within the given scene */ Scene drawBlueBlob(Scene scene){ return scene.placeImage(this.blobImage, this.x, this.y); } /** is this blob close to the given location? */ boolean closeTo(int x, int y){ return Math.abs(this.x - x) < 5 && Math.abs(this.y - y) < 5; } } /** A red circle moving in the world */ class RedCircle{ int dir; // direction: -1 is up, 1 is down int x; // the horizontal coordinate int y; // the vertical coordinate /** the image of the red circle with the white middle */ Image image = new Overlay(new Circle(10, "solid", "white"), new Circle(20, "solid", "red")); /** Construct a red circle */ RedCircle(int dir, int x, int y){ this.dir = dir; this.x = x; this.y = y; } /** Template: * Fields: * ... this.dir ... -- int * ... this.x ... -- int * ... this.y ... -- int * * Methods: * ... this.drawRedCircle(Scene) ... -- Scene * ... this.onKey(String) ... -- RedCircle * ... this.moveTo(int x, int y) ... -- RedCircle * ... this.move() ... -- RedCircle * ... this.offScreen() ... -- boolean * ... this.hitBlob(BlueBlob) ... -- boolean */ /** this circle places itself at its location within the given scene */ Scene drawRedCircle(Scene scene){ return scene.placeImage(this.image, this.x, this.y); } /** On up or down key event, set the direction to the specified one * Ignore all other key events */ RedCircle onKey(String ke){ if (ke.equals("up")){ return new RedCircle(-1, this.x, this.y); } else {if (ke.equals("down")){ return new RedCircle(1, this.x, this.y); } else { return this; }} } /** Produce a new circle from this one * at the given location with the current direction */ RedCircle moveTo(int x, int y){ return new RedCircle(this.dir, x, y); } /** Produce a new circle from this one * moved in its current direction by one pixel */ RedCircle move(){ return new RedCircle(this.dir, this.x, this.y + this.dir); } /** Is this circle off the screen? */ boolean offScreen(){ return (this.x > 400 || this.y > 400 || this.x < 0 || this.y < 0); } /** Did this circle hit the blue blob */ boolean hitBlob(BlueBlob bb){ return bb.closeTo(this.x, this.y); } } // tests and examples for the SimpleWorld class ExamplesSimpleWorld{ ExamplesSimpleWorld(){} CartPt p1 = new CartPt(20, 30); // test the method closeTo for the CartPt class boolean testCloseTo(Tester t){ return t.checkExpect(this.p1.closeTo(new CartPt(10, 20)), false) && t.checkExpect(this.p1.closeTo(new CartPt(16, 26)), true) && t.checkExpect(this.p1.closeTo(new CartPt(16, 34)), true) && t.checkExpect(this.p1.closeTo(new CartPt(24, 32)), true); } BlueBlob bb1 = new BlueBlob(20, 30); BlueBlob bb2 = new BlueBlob(30, 20); // test the method closeTo for the BlueBlob class boolean testCloseToBlob(Tester t){ return t.checkExpect(this.bb1.closeTo(10, 20), false) && t.checkExpect(this.bb1.closeTo(16, 26), true) && t.checkExpect(this.bb1.closeTo(16, 34), true) && t.checkExpect(this.bb1.closeTo(24, 32), true); } RedCircle rc1 = new RedCircle(-1, 20, 30); RedCircle rc2 = new RedCircle(1, 40, 50); // test the method move for the RedCircle class boolean testMove(Tester t){ return t.checkExpect(this.rc1.move(), new RedCircle(-1, 20, 29)) && t.checkExpect(this.rc2.move(), new RedCircle(1, 40, 51)); } // test the method onKey for the RedCircle class boolean testOnKey(Tester t){ return t.checkExpect(this.rc1.onKey("up"), new RedCircle(-1, 20, 30)) && t.checkExpect(this.rc2.onKey("down"), new RedCircle(1, 40, 50)); } // test the method move for the RedCircle class boolean testMoveTo(Tester t){ return t.checkExpect(this.rc1.moveTo(20, 20), new RedCircle(-1, 20, 20)) && t.checkExpect(this.rc2.moveTo(30, 20), new RedCircle(1, 30, 20)); } RedCircle rcLeft = new RedCircle(1, -40, 50); RedCircle rcRight = new RedCircle(1, 405, 50); RedCircle rcAbove = new RedCircle(1, 40, -50); RedCircle rcBelow = new RedCircle(1, 40, 500); // test the method offScreen for the RedCircle class boolean testOffScreen(Tester t){ return t.checkExpect(this.rcLeft.offScreen(), true) && t.checkExpect(this.rcRight.offScreen(), true) && t.checkExpect(this.rcAbove.offScreen(), true) && t.checkExpect(this.rcBelow.offScreen(), true) && t.checkExpect(this.rc2.offScreen(), false); } // test the method hitBlob for the RedCircle class boolean testHitBlob(Tester t){ return t.checkExpect(this.rc1.hitBlob(new BlueBlob(22, 33)), true) && t.checkExpect(this.rc1.hitBlob(new BlueBlob(19, 28)), true) && t.checkExpect(this.rc1.hitBlob(new BlueBlob(25, 36)), false); } // world with the red circle moving down World sw1 = new SimpleWorld(new RedCircle(1, 50, 20), new BlueBlob(200, 150)); // world with the red circle moving up and colliding with the blob World sw2 = new SimpleWorld(new RedCircle(-1, 20, 30), new BlueBlob(23, 32)); // test the method onMouse for the SimpleWorld class boolean testOnMouse(Tester t){ return t.checkExpect(this.sw1.onMouse(30, 50, "hello"), this.sw1) && t.checkExpect(this.sw1.onMouse(30, 50, "button-down"), new SimpleWorld(new RedCircle(1, 30, 50), new BlueBlob(200, 150))); } // test the method onTick for the SimpleWorld class boolean testOnTick(Tester t){ return t.checkExpect(this.sw1.onTick(), new SimpleWorld(new RedCircle(1, 50, 21), new BlueBlob(200, 150))) && t.checkExpect(this.sw2.onTick(), new SimpleWorld(new RedCircle(-1, 20, 29), new BlueBlob(23, 32))); } // test the method onKey for the SimpleWorld class boolean testOnKeySimpleWorld(Tester t){ return t.checkExpect(this.sw1.onKey("up"), new SimpleWorld(new RedCircle(-1, 50, 20), new BlueBlob(200, 150))) && t.checkExpect(this.sw1.onKey("down"), new SimpleWorld(new RedCircle(1, 50, 20), new BlueBlob(200, 150))) && t.checkExpect(this.sw2.onKey("up"), new SimpleWorld(new RedCircle(-1, 20, 30), new BlueBlob(23, 32))) && t.checkExpect(this.sw2.onKey("down"), new SimpleWorld(new RedCircle(1, 20, 30), new BlueBlob(23, 32))); } // example of a world with the red circle out of bounds World swx = new SimpleWorld(new RedCircle(-1, 200, 430), new BlueBlob(23, 32)); // test the method stopWhen for the SimpleWorld class boolean testStopWhen(Tester t){ return t.checkExpect(this.sw1.stopWhen(), false) && t.checkExpect(this.sw2.stopWhen(), true) && t.checkExpect(this.swx.stopWhen(), true); } // run this game boolean testRun(Tester t){ return t.checkExpect( new SimpleWorld(new RedCircle(1, 50, 20), new BlueBlob(200, 180)).bigBang(), new SimpleWorld(new RedCircle(1, 50, 20), new BlueBlob(200, 150))); } }