Sie sind auf Seite 1von 12

// // // // // // // //

SmileyRacer.java ICS 21: Lab Assignment 3 Originally coded by Norm Jacobson, October 2006 Minor modifications introduced by Alex Thornton, Summer 2009 Modified for ICS21 Fall 2009 by Norman Jacobson, September 2009 Clarify comments for ICS 21 Winter 2010 by Norman Jacobson, December 2009

import java.awt.Color; import java.util.Random; // A SmileyRacer is a special kind of SmileyFace that is capable of // participating in a smiley race and tracking its own progress. // When we say that SmileyRacer "extends SmileyFace", we're saying // that SmileyRacer objects can do anything that SmileyFace objects // can do, and can do some other things additionally. The methods // and fields in SmileyFace are automatically "inherited" by SmileyRacer, // making them available to us without us having to copy them into the // SmileyRacer class. public class SmileyRacer extends SmileyFace { // The name of this smiley, which is displayed on top of the smiley // in the graphics window, and also in the statistics area after the // race concludes. private String smileyName; // The color that should be used to show the name of the smiley in the // graphics window. private Color smileyNameColor; // A random number generator, to be used in choosing speeds at random. private Random generator; // The number of ticks that this smiley has been running. private int ticks; // The direction that the smiley is currently moving: RIGHT or LEFT. private int directionMoving; // The number of laps that have been completed by this smiley. private int lapsCompleted; // The number of pixels this smiley moves per tick (i.e., its present // speed). private int pixelsToMovePerTick; // The speed change that this smiley will make when each lap is // completed. A steady (unchanging) speed would be indicated by // the value 0 in this field; a negative value would indicate // that the smiley will get slower after every lap; a positive // value means it would get faster. private int perLapSpeedChange;

// The distance that the smile of the racer should be moved after each lap, // which is part of what needs to be done to make the racer appear to // reverse direction. private int distanceToMoveSmile; // The fastest possible speed that a smiley may have. private static final int MAX_MOVEMENT_PER_TICK = 10; // Value to store in directionMoving to indicate that this smiley is // moving to the right. private static final int RIGHT = 1; // Value to store in directionMoving to indicate that this smiley is // moving to the left. private static final int LEFT = -1; // This constructor initializes a SmileyRacer from an existing SmileyFace. // (Because SmileyRacers are also SmileyFaces, you can also use an // existing SmileyRacer.) You also need to pass in its name and the // name's color. public SmileyRacer(SmileyFace existingFace, String name, Color nameColor) { // To build a racer, we first build the smiley face itself super(existingFace); // Translate the SmileyRacer so that its leftmost point is at the // left edge of the window. This ensures that there's no cheating // -- everyone has to start at the left edge. translate(-super.getLeftEdge(), 0); // Initialize the smiley's name and name color. smileyName = name; smileyNameColor = nameColor; // Construct a random number generator. generator = new Random(); // Initialize ticks and laps completed to zero. // direction to RIGHT. ticks = 0; lapsCompleted = 0; directionMoving = RIGHT; // // // // // // When a racer hits a wall, it needs to face the other direction. To do this, the mouth has to move to the other side of the face, so that it's off-center on one side by the same amount that it's off-center presently. The distance that the smile should move is twice the distance that the center of the smile is away from the center of the face. Set the current

distanceToMoveSmile = 2*(super.getSmile().getCenterX() super.getFace().getCenterX()); // Choose the current speed randomly, so that it lies between 1 and // MAX_MOVEMENT_PER_TICK (inclusive). pixelsToMovePerTick = generator.nextInt(MAX_MOVEMENT_PER_TICK)+1; // // // // // Choose the per-lap speed change randomly, so that it lies between 0 and pixelsToMovePerTick / 2. Choose its sign (i.e., positive or negative) randomly, with a 50% chance of it being an increase and a 50% chance of it being a decrease. (Hint: Generate a 0 or 1 randomly; if a 0 is generated, make perLapSpeedChange negative.)

int chance = (generator.nextInt(2) -1); if( chance == 0) { chance = -1*chance; } perLapSpeedChange = chance*generator.nextInt((pixelsToMovePerTick/2)); } // finishedRace() returns true if the SmileyRacer has finished the race, // false if not. public boolean finishedRace() { if(lapsCompleted == 4) { return true; } else { return false; } } // raceForOneTick() moves the racer forward the distance that it moves // for one tick. Also, it increases the number of ticks that the racer // has been in the race. // // A loop is a handy way to accomplish this task: loop over the number of // pixels that the racer should move, moving one pixel forward and // checking if adjustments are needed (e.g., reverse direction when // edge is hit) each iteration. Since moveForwardOnePixel() handles these // tasks, all this method has to do is loop through moveForwardOnePixel() // for each pixel the racer should move in this turn public void raceForOneTick() {

for(int i = 0; i < pixelsToMovePerTick; i++) { moveForwardOnePixel(); ticks++; } } // moveForwardOnePixel(): If the racer has not already finished the race: // moves the racer forward one pixel // If a wall has been hit: // increase by 1 the number of laps completed // reverse the racer's profile // reverse the direction of movement // adjust the number of pixels moved per tick by the perLapSpeedChange // Remember when adjusting the speed that, post-adjustment, the speed is // not permitted to be outside of the range 1..MAX_MOVEMENT_PER_TICK. private void moveForwardOnePixel() { if(!finishedRace()) super.translate(directionMoving, 0); if(hitSomething()) { lapsCompleted++; reverseProfile(); } if(directionMoving > 0) { directionMoving = LEFT; } else { directionMoving = RIGHT; } if (pixelsToMovePerTick + perLapSpeedChange < 1) { pixelsToMovePerTick = 1; } else { pixelsToMovePerTick = pixelsToMovePerTick + perLapSpeedChange; } } // reverseProfile() reverses the appearance of the racer, by swapping // the colors of its left and right eyes and moving its smile to the // opposite side of its face. private void reverseProfile() { if (directionMoving > 0) {

Color right = super.getRightEye().getColor(); super.getRightEye().setColor(super.getLeftEye().getColor()); super.getLeftEye().setColor(right); } else { Color left = super.getLeftEye().getColor(); super.getLeftEye().setColor(super.getRightEye().getColor()); super.getRightEye().setColor(left); } if (directionMoving > 0) super.getSmile().translate(-distanceToMoveSmile, 0); else super.getSmile().translate(distanceToMoveSmile, 0); } // hitSomething() returns true if the racer has hit either wall. // (Hint: use the two methods below.) private boolean hitSomething() { if (hitRightWall()||hitLeftWall()) { return true; } else { return false; } } // // // // // hitLeftWall() returns true if the racer has hit the left wall while moving to the left, false otherwise. (It's possible that the racer, when moving several pixels at a time, actually goes through the left wall when it reaches it (though this does not appear on screen). So, if the racer has already turned around -- is facing right -- it could hit the left

wall hit, edge.)

// again on its "way out." In this case, we don;t want to call it a left wall // as it is just an artifact of the racer heading right from beyond the left

private boolean hitLeftWall() { if((super.getLeftEdge() <= SmileyDisplay.LEFT_EDGE) && (directionMoving == LEFT)) { return true; } else { return false; }

} // // // // // hitRightWall() returns true if the racer has hit the right wall while moving to the right, false otherwise. (It's possible that the racer, when moving several pixels at a time, actually goes through the right wall when it reaches it (though this does not appear on screen). So, if the racer has already turned around -- is facing left -- it could hit the right

wall hit, edge.)

// again on its "way out." In this case, we don;t want to call it a right wall // as it is just an artifact of the racer heading left from beyond the right

private boolean hitRightWall() { if(super.getRightEdge() >= SmileyDisplay.RIGHT_EDGE && directionMoving == RIGHT) { return true; } else { return false; } } // Accessors public int getTicks() { return ticks; } public String getSmileyName() { return smileyName; } public Color getSmileyNameColor() { return smileyNameColor; } public int getLapsCompleted() { return lapsCompleted; }

// // // // // // // // //

SmileyAnimation.java ICS 21: Lab Assignment 3 Originally implemented by Norman Jacobson, October 2006 Minor modifications introduced by Alex Thornton, Summer 2009 Minor modifications for ICS21 Fall 2009 by Norman Jacobson, September 2009 Various updates to comments to clarify/expand upon requirements, by Norman Jacobson, December 2009

import java.awt.Color; import java.util.ArrayList; // A SmileyAnimation represents an animation in which a collection of // smiley faces race one another, each completing a set number of laps. public class SmileyAnimation { // The duration, in milliseconds, that the animation will pause // between animation frames. private static final int DELAY = 20; // The number of laps that each smiley will complete before the // race is over. public static final long LAPS_TO_RUN = 4; // A representation of the window in which the animation appears. private SmileyDisplay display; // The list of smileys that are competing in the race. private ArrayList<SmileyRacer> racers; // Information for the statistics area, shown after the race is // concluded. // Title of the statistics area. private String statisticsTitle; // The average time, in ticks, it took for a smiley to complete // the race. private double averageTicks; // The number of ticks that the fastest smiley took to complete // the race. private int fewestTicks; // The name of the fastest smiley. private String fastestSmileyName; // The number of ticks that the slowest smiley took to complete

// the race. private int mostTicks; // The name of the slowest smiley. private String slowestSmileyName; // This constructor initializes the race, performing a variety of set-up // tasks. // // Your program should work for anywhere from one up to tens of smileys. // Be sure to size the smileys so that they all fit on the screen and do // not overlap each other. // // All smiley faces must have the mouth set to the background color of // the SmileyDisplay and should initially be constructed so that they're // facing to the right (i.e., their mouth is on the right-hand side of // the face so it looks like an open mouth, with only the right eye visible). // // Remember, there are two ways to build a SmileyRacer: // // (1) Build a SmileyFace first -- including setting its attributes -// then "feed it" to the SmileyRacer constructor. // (2) Feed the SmileyRacer constructor an existing SmileyRacer. // // Remember, also, that SmileyRacers *are* SmileyFaces, so any method // you can call on a SmileyFace can also be called on a SmileyRacer. public SmileyAnimation(SmileyDisplay d) { display = d; racers = new ArrayList<SmileyRacer>(); SmileyFace racingSmiley = new SmileyFace(); racingSmiley.getFace().setAttributes(Color.YELLOW,100,60,100,100); racingSmiley.getLeftEye().setAttributes(Color.YELLOW,80,40,20,30); racingSmiley.getRightEye().setAttributes(Color.GREEN,120,40,20,30); ,20); racingSmiley.getSmile().setAttributes(SmileyDisplay.BACKGROUND_COLOR,130,90,30 SmileyRacer racer1 = new SmileyRacer(racingSmiley, "GOOD ", Color.RED); racers.add(racer1); SmileyRacer racer2 = new SmileyRacer(racingSmiley, "BAD", Color.BLUE); racers.add(racer2); racer2.translate(0,110); SmileyRacer racer3 = new SmileyRacer(racingSmiley, "MIDDLE", Color.MAGENTA); racers.add(racer3); racer3.translate(0,220); }

// animate() is called once, from SmileyFrame, to show the running race when // the GO! buton is pressed; your code should not call it. // // For each tick until all racers have completed all of their laps, animate() // moves the racers forward the distance they should go in that tick, // based on their current speeds. In more detail, animate() follows this // logic: // // Until all racers have finished the race... // Each time through the loop is one 'tick' of the race clock // { For each racer in the list of racers... // If the racer has not yet finished the race... // Move the racer forward one clock tick // Repaint the screen to show the movement made this tick // Pause to slow the animation to a visible speed // } // Race done! Compute the statistics // public void animate() { while (!allRacersFinished()) { for(int n = 0; n < racers.size(); n++) { if(!racers.get(n).finishedRace()) racers.get(n).raceForOneTick(); } display.draw(); pause(); } computeRaceStatistics(); } // computeRaceStatistics() computes the statistics for this race. If // there were no racers, the title should indicate that no race took // place and no statistics are computed. Otherwise, the title should // be an introduction to the statistics, then the various statistics // should be computed. private void computeRaceStatistics() { if (racers.size() == 0) { statisticsTitle = "There is no race."; System.out.println(statisticsTitle); } else { statisticsTitle = "Race Stats: "; } computeFastestRunner(); computeSlowestRunner(); computeAverageTime();

} // computeFastestSmiley() determines which racer was the fastest, // storing the number of ticks and the name of that racer into // the appropriate fields. If there is a tie, any one of the tied // racers can be named the fastest, private void computeFastestRunner() { fewestTicks = racers.get(0).getTicks(); fastestSmileyName = racers.get(0).getSmileyName(); for (int n = 0; n < racers.size(); n++) { if(racers.get(n).getTicks() < fewestTicks) { fewestTicks = racers.get(n).getTicks(); fastestSmileyName = racers.get(n).getSmileyName(); } } } // computeSlowestSmiley() determines which racer was the slowest, // storing the number of ticks and the name of that racer into // the appropriate fields. If there is a tie, any one of the tied // racers can be named the slowest private void computeSlowestRunner() { mostTicks = racers.get(0).getTicks(); slowestSmileyName = racers.get(0).getSmileyName(); for (int n = 0; n < racers.size(); n++) { if(racers.get(n).getTicks() > mostTicks) mostTicks = racers.get(n).getTicks(); slowestSmileyName = racers.get(n).getSmileyName(); } } // computeAverageTime() determines the average time, in ticks, each // racer spent completing the race. private void computeAverageTime() { int sum = 0; for(int n = 0; n < racers.size(); n++) { sum = sum + racers.get(n).getTicks(); } averageTicks = sum/racers.size(); }

// allRacersFinished() returns true if all of the racers have finished // the race, false otherwise. // // The algorithm for solving this kind of problem is: // // Assume all have finished // Go through the racers, looking for one that hasn't finished // If you find one that hasn't finished, return false // If you never find one, return true // private boolean allRacersFinished() { boolean tf = true; for(int n = 0; n < racers.size(); n++) { if(!racers.get(n).finishedRace()) { return false; } else tf = true; } return tf; } // pause() pauses the animation for the number of milliseconds given // by the DELAY constant declared above. private void pause() { try { Thread.sleep(DELAY); } catch (InterruptedException e) { } } // Accessors -- used by the graphics routine to obtain the information // that it needs to display // getRacers() returns all the racers (with their information). public ArrayList<SmileyRacer> getRacers() { return racers; } // getStatisticsTitle() returns the title that should be shown in the // statistics area of the window.

public String getStatisticsTitle() { return statisticsTitle; } // getAverageTicks() returns the average time, in ticks, that each // smiley spent completing the race. public double getAverageTicks() { return averageTicks; } // getFewestTicks() returns the number of ticks spent by the fastest // smiley in completing the race. public int getFewestTicks() { return fewestTicks; } // getMostTicks() returns the number of ticks spent by the slowest // smiley in completing the race. public int getMostTicks() { return mostTicks; } // getFastestSmileyName() returns the name of the fastest smiley. public String getFastestSmileyName() { return fastestSmileyName; } // getSlowestSmileyName() returns the name of the slowest smiley. public String getSlowestSmileyName() { return slowestSmileyName; }

Das könnte Ihnen auch gefallen