import javalib.colors.*; import javalib.soundworld.*; import javalib.tunes.*; import javalib.worldimages.*; import tester.*; /** * Copyright 2012 Viera K. Proulx * This program is distributed under the terms of the * GNU Lesser General Public License (LGPL) * *

DrawFaceSound.java

* *

An example of the use of the drawing methods in the 'worldimages' * library, augmented to illustrate the behavior of the 'soundworld':

* *

On tick the face changes every four ticks from happy to sad, * one note plays for four ticks, another plays for the first two ticks only * the instrument changes from happy to sad (piano to tube) * *

key events can play bird-tweet on "up" key, change state with space bar, * force end of the world on "x", induce tick-controlled world ending through * "q" key (by setting the condition that is evaluated on each tick)

* * @author Viera K. Proulx * @since 8 August 2012 */ class DrawFace extends World { /** the width of the game canvas */ static int WIDTH = 100; /** the height of the game canvas */ static int HEIGHT = 100; /** is the face happy? */ boolean happy = true; /** happy song is sang by a choir */ int happyInstrument = CHOIR; /** sad song is played by tuba */ int sadInstrument = TUBA; /** C note played for 4 ticks */ Note note = new Note("C4n4"); /** E note played for 2 ticks */ Note note2 = new Note("E4n2"); /** we count the number of ticks to swithc between happy and sad */ int tickCount = 0; /** * Create a new DrawFace world * @param happy true if this is a happy face */ DrawFace(boolean happy){ super(); this.happy = happy; this.tickCount = 0; } /** * Select the instrument to play: a happy or a sad tune * @return the instrument to play */ int instrument() { if (happy) return this.happyInstrument; else return this.sadInstrument; } /** The image of a left blue eye with a white pupil */ WorldImage leftEyeImage = new DiskImage(new Posn(35, 35), 5, new Blue()).overlayImages( new DiskImage(new Posn(37, 35), 2, new White())); /** The image of a right blue eye with a white pupil */ WorldImage rightEyeImage = new DiskImage(new Posn(65, 35), 5, new Blue()).overlayImages( new DiskImage(new Posn(67, 35), 2, new White())); /** An image of a happy red mouth at location 50, 60 * assume it will be overlaid with the image of the face * that is a yellow disk of radius 40 */ WorldImage happyMouthImage = new DiskImage(new Posn(50, 60), 20, new Red()).overlayImages( new DiskImage(new Posn(50, 50), 20, new Yellow())); /** An image of a sad red mouth at location 50, 60 * assume it will be overlaid with the image of the face * that is a yellow disk of radius 40 */ WorldImage sadMouthImage = new DiskImage(new Posn(50, 60), 20, new Red()).overlayImages( new DiskImage(new Posn(50, 70), 20, new Yellow())); /** An image of the nose as black triangle */ WorldImage noseImage = new TriangleImage(new Posn(50, 40), new Posn(40, 60), new Posn(50, 60), new Black()); /** The image of a happy face on a green background */ WorldImage happyFaceImage = new RectangleImage(new Posn(50, 50), 100, 100, new Green()).overlayImages( new DiskImage(new Posn(50, 50), 40, new Yellow()), this.happyMouthImage, this.noseImage, this.leftEyeImage, this.rightEyeImage); /** The image of a sad face on a green background */ WorldImage sadFaceImage = new RectangleImage(new Posn(50, 50), 100, 100, new Green()).overlayImages( new DiskImage(new Posn(50, 50), 40, new Yellow()), this.sadMouthImage, this.noseImage, this.leftEyeImage, this.rightEyeImage); ////////////////////////////////////////////////////////////// // If this class did not extend the World and did not have the // methods draw, onTick, and onKeyEvent, the following two // field definitions would display the image // //Canvas c = new Canvas(100, 100); // //boolean showFace = this.c.show() && // this.c.drawImage(this.happyFaceImage()); ////////////////////////////////////////////////////////////// /** * Draw this world in the World's Canvas * @return the instance of the WorldImage that shows * a happy or a sad face. */ public WorldImage makeImage() { if (happy) { return this.happyFaceImage; } else { return this.sadFaceImage; } } /** * On every fourth tick change the face from sad to happy and back * and play either a happy or a sad tune */ public void onTick() { if (this.tickCount == 0) { this.happy = !this.happy; this.tickTunes.addNote(this.instrument(), this.note); this.tickTunes.addNote(this.instrument(), this.note2); } // we print the tick counts to see that they circle correctly System.out.println("tick count: " + this.tickCount); this.tickCount = (this.tickCount + 1) % 4; } /** *

on space bar change the mood of the face

*

on key "x" end the world

*

on key "q" signal the end of world

*

on key "up" play a bird tweet

*

ignore all other keys

*/ public void onKeyEvent(String ke) { if (ke.equals(" ")) { this.happy = !this.happy; } if (ke.equals("x")) { this.endOfWorld("Have a nice Day!"); } if (ke.equals("q")) { this.tickCount = 5; } if (ke.equals("up")) { this.keyTunes.addNote(BIRD_TWEET, new Note("G2n4")); } } /** * End the world if the key event "q" upped the tick count * @return WorldEnd with true and * the last image if the world is to end, * WorldEnd with false and this world's * image otherwise. */ public WorldEnd worldEnds(){ if (this.tickCount > 4) return new WorldEnd(true, this.makeImage()); else return new WorldEnd(false, this.makeImage()); } } /** * Examples and tests for the DrawFace world. * @author Viera K. Proulx * @version 11-12-2013 */ class ExamplesDrawFace{ /** a sample happy world */ DrawFace dfw = new DrawFace(true); /** a sample sad world */ DrawFace dfwSad = new DrawFace(false); /** * Reset the two worlds to their original state */ void resetDrawFace() { this.dfw = new DrawFace(true); this.dfwSad = new DrawFace(false); } /** * Produce the initial happy face world * @return the initial world that starts the game */ DrawFace initDrawFace() { return this.dfw; } /** * Test the method onTick * @param t the tester that runs the tests */ void testOnTick(Tester t){ resetDrawFace(); TuneBucket nowPlaying = this.dfw.nowPlaying(); t.checkExpect(nowPlaying.bucketSize(), 0); this.dfw.testOnTick(); t.checkExpect(this.dfw.tickCount, 1); t.checkExpect(this.dfw.happy, false); t.checkExpect(this.dfw.instrument(), this.dfw.sadInstrument); nowPlaying = this.dfw.nowPlaying(); t.checkExpect(nowPlaying.bucketSize(), 2); t.checkExpect(nowPlaying.contains(this.dfw.sadInstrument, new Note("C4n4")), true); t.checkExpect(nowPlaying.contains(this.dfw.sadInstrument, new Note("E4n2")), true); System.out.println("Now playing on tick count " + this.dfw.tickCount + "\n" + nowPlaying.toIndentedString(" ")); this.dfw.testOnTick(); t.checkExpect(this.dfw.tickCount, 2); t.checkExpect(this.dfw.happy, false); t.checkExpect(this.dfw.instrument(), this.dfw.sadInstrument); nowPlaying = this.dfw.nowPlaying(); t.checkExpect(nowPlaying.bucketSize(), 2); t.checkExpect(nowPlaying.contains(this.dfw.sadInstrument, new Note("C4n3")), true); t.checkExpect(nowPlaying.contains(this.dfw.sadInstrument, new Note("E4n1")), true); System.out.println("Now playing on tick count " + this.dfw.tickCount + "\n" + nowPlaying.toIndentedString(" ")); this.dfw.testOnTick(); t.checkExpect(this.dfw.tickCount, 3); t.checkExpect(this.dfw.happy, false); t.checkExpect(this.dfw.instrument(), this.dfw.sadInstrument); nowPlaying = this.dfw.nowPlaying(); t.checkExpect(nowPlaying.bucketSize(), 1); t.checkExpect(nowPlaying.contains(this.dfw.sadInstrument, new Note("C4n2")), true); t.checkExpect(nowPlaying.contains(this.dfw.sadInstrument, new Note("E4n2")), false); System.out.println("Now playing on tick count " + this.dfw.tickCount + "\n" + nowPlaying.toIndentedString(" ")); this.dfw.testOnTick(); t.checkExpect(this.dfw.tickCount, 0); t.checkExpect(this.dfw.happy, false); t.checkExpect(this.dfw.instrument(), this.dfw.sadInstrument); nowPlaying = this.dfw.nowPlaying(); t.checkExpect(nowPlaying.bucketSize(), 1); t.checkExpect(nowPlaying.contains(this.dfw.sadInstrument, new Note("C4n1")), true); t.checkExpect(nowPlaying.contains(this.dfw.sadInstrument, new Note("E4n2")), false); System.out.println("Now playing on tick count " + this.dfw.tickCount + "\n" + nowPlaying.toIndentedString(" ")); this.dfw.testOnTick(); t.checkExpect(this.dfw.tickCount, 1); t.checkExpect(this.dfw.happy, true); t.checkExpect(this.dfw.instrument(), this.dfw.happyInstrument); nowPlaying = this.dfw.nowPlaying(); t.checkExpect(nowPlaying.bucketSize(), 2); t.checkExpect(nowPlaying.contains(this.dfw.happyInstrument, new Note("C4n4")), true); t.checkExpect(nowPlaying.contains(this.dfw.happyInstrument, new Note("E4n2")), true); System.out.println("Now playing on tick count " + this.dfw.tickCount + "\n" + nowPlaying.toIndentedString(" ")); } /** * Test the method onKeyEvent * @param t the tester that runs the tests */ void testOnKeyEvent(Tester t){ // test space key event once resetDrawFace(); this.dfw.onKeyEvent(" "); t.checkExpect(this.dfw, this.dfwSad); // test ignored key event resetDrawFace(); this.dfw.onKeyEvent("b"); t.checkExpect(this.dfw, this.dfw); // test space key event again resetDrawFace(); this.dfwSad.onKeyEvent(" "); t.checkExpect(this.dfwSad, this.dfw); // test world ending key event this.dfw.onKeyEvent("x"); t.checkExpect(this.dfw.lastWorld, new WorldEnd(true, this.dfw.makeImage())); // test signal for world ending key event this.dfw.onKeyEvent("q"); t.checkExpect(this.dfw.tickCount, 5); this.dfw.testOnTick(); t.checkExpect(this.dfw.lastWorld, new WorldEnd(true, this.dfw.makeImage())); // we need more tests here .... } /** * Run the tests (DO NOT run the game) * @param argv unused */ public static void main(String[] argv){ ExamplesDrawFace edf = new ExamplesDrawFace(); Tester.runReport(edf, false, false); } }