scg/ch13/highscore/HighScoreLevel

From FANG

Jump to: navigation, search

001 package scg.ch13.highscore;
002 
003 import java.io.File;
004 import java.io.FileNotFoundException;
005 import java.io.PrintWriter;
006 import java.util.ArrayList;
007 import java.util.Collections;
008 import java.util.Scanner;
009 
010 import scg.ch13.core.BlockDrop;
011 
012 import fang2.core.Game;
013 import fang2.sprites.InputStringField;
014 import fang2.sprites.StringSprite;
015 
016 /**
017  * This is the "attract" mode of {@link BlockDrop}. It reads in the high
018  * score file and displays the ten high score cyclically.
019  */
020 @SuppressWarnings("serial")
021 public class HighScoreLevel
022   extends Game {
023   /** the default score file */
024   private static final String DEFAULT_SCORE_FILENAME =
025     "highScoreFile.txt";
026 
027   /** maximum number of high scores to store */
028   private static final int MAX_HIGHSCORE_COUNT = 10;
029 
030   /** the score with which the previous {@link BlockDrop} ended */
031   private final int currentScore;
032 
033   /** the high score file name */
034   private final String fname;
035 
036   /** string input for user to provide their name */
037   private InputStringField getUserName;
038 
039   /** the list of HighScore objects */
040   private final ArrayList<HighScore> highScores;
041 
042   /** game state variable: are we waiting for user to enter name? */
043   private boolean needHighScoreName;
044 
045   /** scrolling message box containing high scores */
046   private ScrollingMessageBox showScores;
047 
048   /**
049    * Construct a new {@link HighScoreLevel} game level using default
050    * high score file name and a negative score.
051    */
052   public HighScoreLevel() {
053     this(-1);
054   }
055 
056   /**
057    * Construct a new {@link HighScoreLevel} game level using default
058    * high score file name and the given score
059    *
060    @param  currentScore  the score of the current game; a negative
061    *                       number indicates there is no high score
062    */
063   public HighScoreLevel(int currentScore{
064     this(currentScore, DEFAULT_SCORE_FILENAME);
065   }
066 
067   /**
068    * Construct the {@link HighScoreLevel} game level. The level reads a
069    * named high score file for displaying scores.
070    *
071    @param  currentScore  the score of the current game; a negative
072    *                       number indicates there is no high score
073    @param  fname         name of the high score file
074    */
075   public HighScoreLevel(int currentScore, String fname{
076     this.fname = fname;
077     this.currentScore = currentScore;
078     highScores = loadHighScores(fname);
079     while (highScores.size() < MAX_HIGHSCORE_COUNT{
080       highScores.add(new HighScore(0""));
081     }
082     Collections.sort(highScores, Collections.reverseOrder());
083   }
084 
085   /**
086    * Dispatch advance call depending on game state.
087    *
088    @param  dT  time, in seconds, since last advance call
089    */
090   @Override
091   public void advance(double dT{
092     if (needHighScoreName{
093       advanceGetHighScoreName(dT);
094     } else {
095       advanceScrollingScores(dT);
096     }
097   }
098 
099   /**
100    * Setup the sprites for the level.
101    */
102   @Override
103   public void setup() {
104     showScores = makeShowScoresSprite();
105     addSprite(showScores);
106 
107     StringSprite title = new StringSprite();// level title
108     title.setText("BlockDrop High Scores");
109     title.setLineHeight(0.1);
110     title.setLocation(0.50.1);
111     title.setColor(getColor("red"));
112     addSprite(title);
113 
114     StringSprite instruction = new StringSprite();// prompt user
115     instruction.setText("<Space> or Level (1-9) to Start");
116     instruction.setLineHeight(0.05);
117     instruction.setLocation(0.50.20);
118     instruction.setColor(getColor("red").darker());
119     addSprite(instruction);
120 
121     getUserName = null;
122     if (isAHighScore(currentScore)) {
123       needHighScoreName = true;
124       getUserName = new InputStringField(1.00.2);
125       getUserName.setLocation(0.50.4);
126       getUserName.setLabelText("Your Name");
127       addSprite(getUserName);
128       showScores.hide();
129     }
130   }
131 
132   /**
133    * Advance one frame while the player is typing in their name.
134    *
135    @param  dT  seconds since last call to advance
136    */
137   private void advanceGetHighScoreName(double dT{
138     if (getUserName.hasEnteredText()) {
139       String currentName = getUserName.getEnteredText();
140       insertScore(currentScore, currentName);
141 
142       removeSprite(getUserName);
143       getUserName = null;
144 
145       showScores.show();
146       needHighScoreName = false;
147     }
148   }
149 
150   /**
151    * Pump (call advance on) the scrolling high scores. Check if player
152    * has started the real game. Real game starts on pressing <space> or
153    * the number of the level on which you want to start.
154    *
155    @param  dT  seconds since last call to advance
156    */
157   private void advanceScrollingScores(double dT{
158     showScores.advance(dT);
159     if (keyPressed()) {
160       char key = getKeyPressed();
161       if ((key == ' '|| (('1' <= key&& (key <= '9'))) {
162         int level = 1;
163         if (('2' <= key&& (key <= '9')) {
164           level = key - '0';
165         }
166         addGame(new BlockDrop(level));
167         finishGame();
168       }
169     }
170   }
171 
172   /**
173    * Add the given high score and resort the list. The list is sorted in
174    * reverse order (using {@link Collections} class static methods)
175    *
176    @param  score  score to add
177    @param  name   name associated with the score
178    */
179   private void insertScore(int score, String name{
180     highScores.set(highScores.size() 1new HighScore(score, name));
181     Collections.sort(highScores, Collections.reverseOrder());
182     saveHighScores();
183     if (showScores != null{
184       removeSprite(showScores);
185     }
186     showScores = makeShowScoresSprite();
187     addSprite(showScores);
188   }
189 
190   /**
191    * Is the given score a high score? Since the list of scores is
192    * sorted, a high score is any one that is bigger than the last score
193    * in the list.
194    *
195    @param   score  score to check
196    *
197    @return  true if the given score belongs on the list; false
198    *          otherwise
199    */
200   private boolean isAHighScore(int score{
201     int lowestScoreIndex = highScores.size() 1;
202     return (score > highScores.get(lowestScoreIndex).getScore());
203   }
204 
205   /**
206    * Load the given high score file. Lines in the high score file are
207    * score, space, name. Uses {@link Scanner} version of the {@link
208    * HighScore} constructor.
209    *
210    @param   fname  name of the file to load.
211    *
212    @return  new {@link ArrayList} of {@link HighScore} values.
213    */
214   private ArrayList<HighScore> loadHighScores(String fname{
215     ArrayList<HighScore> hs = new ArrayList<HighScore>();
216     File highScoreFile = new File(fname);
217     try {
218       Scanner highScoreInput = new Scanner(highScoreFile);
219       while (highScoreInput.hasNextInt()) {
220         hs.add(new HighScore(highScoreInput));
221       }
222       highScoreInput.close();
223     } catch (FileNotFoundException e{
224       // It is okay if there is no such file; we will just ignore this
225     }
226     return hs;
227   }
228 
229   /**
230    * Make a new {@link ScrollingMessageBox} containing the list of high
231    * scores. ALL positioning and stuff should go here so that {@link
232    * #insertScore(intString)} can build a proper replacement after a
233    new high score is added.
234    *
235    @return  new {@link ScrollingMessageBox} with high scores
236    */
237   private ScrollingMessageBox makeShowScoresSprite() {
238     ScrollingMessageBox ss = new ScrollingMessageBox();
239     for (int = 0; i != highScores.size()++i{
240       int displayIndex = i + 1;
241       ss.add(highScores.get(i).toDisplayString(displayIndex));
242     }
243 
244     // position the score showing sprite where we want it
245     ss.setColor(getColor("pink"));
246     ss.setScale(0.67);
247     ss.setLocation(0.50.67);
248 
249     return ss;
250   }
251 
252   /**
253    * Save the current high score values to the file from which the high
254    * scores were loaded.
255    */
256   private void saveHighScores() {
257     File saveFile = new File(fname);
258     PrintWriter saveFileWriter;
259     try {
260       saveFileWriter = new PrintWriter(saveFile);
261       for (int = 0; i != highScores.size()++i{
262         if (!highScores.get(i).isEmpty()) {
263           saveFileWriter.println(highScores.get(i));
264         }
265       }
266       saveFileWriter.close();
267     } catch (FileNotFoundException e{
268       System.err.println("Unable to open " + fname +
269         " for output; high score file not saved");
270     }
271   }
272   // ----- NESTED PRIVATE CLASSES -----
273 
274   /**
275    * Nested private class. A class which is private to just this class.
276    * No other class in the game need know anything about it. This game
277    * level displays a scrolling list of high scores. This class keeps
278    * the name, the score, and a {@link StringSprite} grouped together.
279    * The class extends {@link StringSprite} (so it can be added to the
280    * game and displayed directly). It also implements the {@link
281    Comparable} interfacethis interface lets us use a built-in Java
282    * sort rather than having to write our own again.
283    */
284   private class HighScore
285     implements Comparable<HighScore> {
286     /** number of characters used in the full-width name */
287     private static final int SIGNIFICANT_CHARACTERS = 10;
288 
289     /** padding string, appended to name and then name is chopped */
290     private static final String SIGNIFICANT_PADDING =
291       " ................";
292 
293     /** the name associated with this score */
294     private final String name;
295 
296     /** the score */
297     private final int score;
298 
299     /**
300      * Create a new {@link HighScore} object with the given values.
301      *
302      @param  score  the new high score's score
303      @param  name   the name of the player with the high score
304      */
305     public HighScore(int score, String name{
306       this.score = score;
307       this.name = name;
308     }
309 
310     /**
311      * Create a new {@link HighScore} by reading field values from the
312      * given {@link Scanner}{@link HighScore} formatting is a single
313      * line with the score, a space, and the name: <score> <name> The
314      * name finishes out the line so it can contain spaces.
315      *
316      @param  highScoreInput  the {@link Scanner} open on a high score
317      *                         file
318      */
319     public HighScore(Scanner highScoreInput{
320       this.score = highScoreInput.nextInt();
321       highScoreInput.skip(" ");// skip over one space
322       this.name = highScoreInput.nextLine();
323     }
324 
325     /**
326      * Required by the {@link Comparable} interface. As defined for
327      {@link String}{@link #compareTo(HighScore)} returns a negative
328      * number if this < rhs; 0 if this == rhs; and positive number if
329      this > rhs (rhs = right-hand side).
330      *
331      @param   rhs  the {@link HighScore} to which this object is
332      *               compared
333      *
334      @return  negative if this < rhs; 0 if this == rhs; positive
335      *          otherwise
336      */
337     public int compareTo(HighScore rhs{
338       if (rhs.name.length() == 0{
339         return 1;
340       }
341       if (name.length() == 0{
342         return -1;
343       }
344       if (score == rhs.score{
345         return name.compareTo(rhs.name);
346       }
347       return score - rhs.score;
348     }
349 
350     /**
351      * Get the score for this high score.
352      *
353      @return  the score value
354      */
355     public int getScore() {
356       return score;
357     }
358 
359     /**
360      * Is the name empty?
361      *
362      @return  true if the name is empty; false otherwise
363      */
364     public boolean isEmpty() {
365       return name.length() == 0;
366     }
367 
368     /**
369      * Get a display version of the string. Used to fill an array of
370      * strings for displaying in a scrolling message sprite
371      *
372      @param   index  the number to put in the front of the whole
373      *                 thing.
374      *
375      @return  string padded with index, name, and score
376      */
377     public String toDisplayString(int index{
378       String paddedName = Integer.toString(index+ ": " +
379         (name + SIGNIFICANT_PADDING).substring(0,
380           SIGNIFICANT_CHARACTERS);
381       return paddedName + " " + score;
382     }
383 
384     /**
385      * Return a {@link String} representation of this high score. The
386      * string representation is the same format as a high score file.
387      *
388      @return  {@link String} representation <score> <name>
389      */
390     @Override
391     public String toString() {
392       return "" + score + " " + name;
393     }
394   }
395 }
396 
397 //Uploaded on Mon Mar 29 21:39:01 EDT 2010


Download/View scg/ch13/highscore/HighScoreLevel.java





Views
Personal tools
Add to 
del.icio.usAdd to 
diggAdd to 
FacebookAdd to 
favoritesAdd to 
GoogleAdd to 
MySpaceAdd to 
PrintAdd to 
SlashdotAdd to 
StumbleUponAdd to 
Twitter

Games
Games