package Code.graphics.searchGame; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import edu.cmu.ri.createlab.terk.robot.finch.Finch; /** * Created by: Eric Cheek (echeek@andrew.cmu.edu) * Date: 15 February 2009 * A Treasure Hunt Game using the Finch as a controller/feedback device * * Instructions: Tilt the finch to control movement of the circle. * Monitor feedback to find treasure in the window. * * Feedback options: * Voice: "warmer"/"colder" * Buzzing: higher pitched buzzing means you are closer * LED: red is closer, blue is further */ public class SearchGameMain implements ActionListener { SearchGameView view; SearchGameTiltControl controller; Finch myFinch; //feedback on/off states boolean voiceOn = true, buzzOn = false, ledOn = true; // game states static final int GAME_ACTIVE = 0, GAME_INACTIVE = 1, GAME_OVER = 2; int gameState; //other game vairables int targetX, targetY, targetRadius; int curX, curY; double curDistance; //times used to limit slow actions like LED setting long lastSpeechTime = 0; long lastLEDTime = 0; double lastReportedDistance;// used for hot/cold reporting long gameStartTime, gameTotalTime; /** * Constructor * connect to finch, create view and controller */ public SearchGameMain() { myFinch = new Finch(); System.out.println("Finch ready."); view = new SearchGameView(); view.setListener(this); view.show(); fetchFeedbackStates(); controller = new SearchGameTiltControl(myFinch); controller.setLimits(0, 0, view.getScreenWidth(), view.getScreenHeight()); controller.centerPosition(); fetchSensitivity(); //initialize game variables gameState = GAME_INACTIVE; } /** * main game control */ public void run() { while (true) { //clear and reset game to initial states view.clearScreen(); view.makeStatusBig(); view.setStatus("Start New Game"); myFinch.setLED(0, 0, 0); while (gameState == GAME_INACTIVE) {// wait for new game to start updatePlayer();//let user move circle around screen before game } //setup and start new game startNewGame(); while (gameState == GAME_ACTIVE) { //while game is running processGame(); //do game logic } while (gameState == GAME_OVER) { //while game is in game over state //show player and target view.setPlayerPosition(curX, curY); view.showTarget(targetX, targetY, targetRadius); //flash random colors on finch LED myFinch.setLED((int)(Math.random() * 255), (int)(Math.random() * 255), (int)(Math.random() * 255)); } } } /** * Initiate new game. Set/Reset necessary variables */ public void startNewGame() { //move player to center controller.setLimits(0, 0, view.getScreenWidth(), view.getScreenHeight()); controller.centerPosition(); updatePlayer(); //choose random position for treasure targetX = (int)(Math.random() * view.getScreenWidth()); targetY = (int)(Math.random() * view.getScreenHeight()); targetRadius = 30; //record game start time gameStartTime = System.currentTimeMillis(); } /** * Calls main game logic */ public void processGame() { //update and display game time gameTotalTime = System.currentTimeMillis() - gameStartTime; view.setStatus("Time: " + (double)(gameTotalTime / 1000.0)); //game logic: updatePlayer(); provideFeedback(); //test for game win if (curDistance < targetRadius) { gameOver(); } } /** * update variables related to player */ public void updatePlayer() { int tmpX = curX, tmpY = curY; //update player position controller.update(); curX = controller.getX(); curY = controller.getY(); //redraw player view.clearPlayerPosition(tmpX, tmpY); view.setPlayerPosition(curX, curY); //use distance formula to determine distance between treasure and player curDistance = Math.sqrt((targetX - curX) * (targetX - curX) + (targetY - curY) * (targetY - curY)); } /** * Determine and issue appropriate feedback */ public void provideFeedback() { //if voice feedback is on and 1.5 seconds have passed sense last update if (voiceOn && System.currentTimeMillis() - lastSpeechTime > 1500) { if (curDistance < lastReportedDistance) { myFinch.saySomething("warmer"); //closer than last time } else if (curDistance == lastReportedDistance) { myFinch.saySomething("no change"); //no change since last time } else { myFinch.saySomething("colder"); //further than last time } lastReportedDistance = curDistance; //store distance lastSpeechTime = System.currentTimeMillis(); //record time of this message } //if LED feedback is on and 0.25 seconds have passed if (ledOn && System.currentTimeMillis() - lastLEDTime > 250) { //calculate red value //prevent division by zero by capping distance to >1 //prevent red value from exeeding 255 int red = (int)Math.min(255, 10 * 255 / Math.max(curDistance, 1)); //calculate blue value //try creating your own function to determine blue value int blue = (int)Math.min(255, 10 * 255 / Math.max(1000 - curDistance, 1)); //set LED to color myFinch.setLED(red, 0, blue); lastLEDTime = System.currentTimeMillis();//store last update time } //if Buzzer feedback is on if (buzzOn) { //calculate frequency so higher pitches correspond to less distance int frequency = (int)(100000 / Math.max(curDistance, 1)); // System.out.println(frequency); //sound buzzer myFinch.buzz(frequency, 50); } } /** * Called when game is won */ public void gameOver() { //change game state gameState = GAME_OVER; //give congratulatory response view.makeStatusBig(); view.setStatus("<html>You Win! <br/>Total time: " + (double)(gameTotalTime / 1000.0) + "s</html>"); if (voiceOn) { myFinch.saySomething("You win! Total time: " + (double)(gameTotalTime / 1000.0) + " seconds"); } } /** * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) * * Handle events fired by view */ public void actionPerformed(ActionEvent e) { String command = e.getActionCommand(); if (command.equals(SearchGameView.START_GAME)) { gameState = GAME_ACTIVE; } else if (command.equals(SearchGameView.END_GAME)) { gameState = GAME_INACTIVE; } else if (command.equals(SearchGameView.CHANGE_SENSITIVITY)) { //game alerted to change in sensitivity setting fetchSensitivity(); } else if (command.equals(SearchGameView.TOGGLE_FEEDBACK)) { //game alerted to change in feedback types fetchFeedbackStates(); } } /** * Fetch on/off state of various feedback systems */ public void fetchFeedbackStates() { voiceOn = view.isVoiceOn(); buzzOn = view.isBuzzOn(); ledOn = view.isLEDOn(); if (!ledOn) { //turn off LED if led feedback is disabled myFinch.setLED(0, 0, 0); } } /** * Get level selection from view and set controller movement scales * */ public void fetchSensitivity() { switch (view.getSensitivityLevel()) { case 2: controller.setScales(15, 15); break; case 1: controller.setScales(10, 10); break; case 0: controller.setScales(5, 5); break; } } /** * Entry point */ public static void main(String[] args) { SearchGameMain sgm = new SearchGameMain(); sgm.run(); } }