This is my first tutorial. I will try to explain how to make an easy high-score system that you can use for your own java based game!
You can use my code as much as you want, notifying me in this topic if you used it will be appreciated.
We will be making 4 classes:all this classes will be in the package "highscores"
- Main - for testing the code
- HighscoreManager - to manage the high-scores
- HighscoreComparator - I will explain this when we get there
- Score - also this I will explain later
The Score Class
This class makes us able to make an object (an arraylist in our case) of the type Score that contains the name and score of a player.Code:package highscores; import java.io.Serializable; public class Score implements Serializable { private int score; private String naam; public int getScore() { return score; } public String getNaam() { return naam; } public Score(String naam, int score) { this.score = score; this.naam = naam; } }
We implement serializable to be able to sort this type.
The ScoreComparator Class
This class is used to tell Java how it needs to compare 2 objects of the type score.Code:package highscores; import java.util.Comparator; public class ScoreComparator implements Comparator<Score> { public int compare(Score score1, Score score2) { int sc1 = score1.getScore(); int sc2 = score2.getScore(); if (sc1 > sc2){ return -1; }else if (sc1 < sc2){ return +1; }else{ return 0; } } }
-1 means the first score is greater than the 2nd one, +1 (or you can just put 1) means it's smaller and 0 means it's equal.
The HighscoreManager Class
First we will be making the HighscoreManager Class, this class will do the most important part of the high-score system.
We will be using this as our base for the class:
I have added comments to explain what's already in the class.Code:package highscores; import java.util.*; import java.io.*; public class HighscoreManager { // An arraylist of the type "score" we will use to work with the scores inside the class private ArrayList<Score> scores; // The name of the file where the highscores will be saved private static final String HIGHSCORE_FILE = "scores.dat"; //Initialising an in and outputStream for working with the file ObjectOutputStream outputStream = null; ObjectInputStream inputStream = null; public HighscoreManager() { //initialising the scores-arraylist scores = new ArrayList<Score>(); } }
We will be using a binary file to keep the high-scores in, this will avoid cheating.
To work with the scores we will use an arraylist. An arraylist is one of the great things that java has and it's much better to use in this case than a regular array.
Now we will add some methods and functions.
This is a function that will return an arraylist with the scores in it. It contains calls to the function loadScoreFile() and sort(), these functions will make sure you have the scores from your high-score file in a sorted order. We will be writing these functions later on.Code:public ArrayList<Score> getScores() { loadScoreFile(); sort(); return scores; }
This function will create a new object "comparator" from the class ScoreComparator.Code:private void sort() { ScoreComparator comparator = new ScoreComparator(); Collections.sort(scores, comparator); }
the Collections.sort() function is in the Java Collections Class (a part of java.util). It allows you to sort the arraylist "scores" with help of "comparator".
This method is to add scores to the scorefile.Code:public void addScore(String name, int score) { loadScoreFile(); scores.add(new Score(name, score)); updateScoreFile(); }
Parameters "name" and "score" are given, these are the name of the player and the score he had.
First the scores that are allready in the high-score file are loaded into the "scores"-arraylist.
Afther that the new scores are added to the arraylist and the high-score file is updated with it.
This function will load the arraylist that is in the high-score file and will put it in the "scores"-arraylist.Code:public void loadScoreFile() { try { inputStream = new ObjectInputStream(new FileInputStream(HIGHSCORE_FILE)); scores = (ArrayList<Score>) inputStream.readObject(); } catch (FileNotFoundException e) { System.out.println("[Laad] FNF Error: " + e.getMessage()); } catch (IOException e) { System.out.println("[Laad] IO Error: " + e.getMessage()); } catch (ClassNotFoundException e) { System.out.println("[Laad] CNF Error: " + e.getMessage()); } finally { try { if (outputStream != null) { outputStream.flush(); outputStream.close(); } } catch (IOException e) { System.out.println("[Laad] IO Error: " + e.getMessage()); } } }
The try-catch structure will avoid that your program crashes when there is something wrong while loading the file (like when the file is corrupted or doesn't exist).
This is about the same as loadScoreFile(), but instead of reading the file it will be writing the "score"-arraylist to the file.Code:public void updateScoreFile() { try { outputStream = new ObjectOutputStream(new FileOutputStream(HIGHSCORE_FILE)); outputStream.writeObject(scores); } catch (FileNotFoundException e) { System.out.println("[Update] FNF Error: " + e.getMessage() + ",the program will try and make a new file"); } catch (IOException e) { System.out.println("[Update] IO Error: " + e.getMessage()); } finally { try { if (outputStream != null) { outputStream.flush(); outputStream.close(); } } catch (IOException e) { System.out.println("[Update] Error: " + e.getMessage()); } } }
Depending on how you want to display your highscores this function can be either usefull or not usefull. But I have put it in here anyway.Code:public String getHighscoreString() { String highscoreString = ""; Static int max = 10; ArrayList<Score> scores; scores = getScores(); int i = 0; int x = scores.size(); if (x > max) { x = max; } while (i < x) { highscoreString += (i + 1) + ".\t" + scores.get(i).getNaam() + "\t\t" + scores.get(i).getScore() + "\n"; i++; } return highscoreString; }
It can be used for both console and GUI (in GUI you can put the high-score string into a label).
The function will only have the top 10 players but you can adjust the variable "max" to change that.
The Main Class
This class is just to test out the code and it shows you how you can implement it into your own game.
First you have to create an object from the HighscoreManager class, we will call it "hm" in here.Code:package highscores; public class Main { public static void main(String[] args) { HighscoreManager hm = new HighscoreManager(); hm.addScore("Bart",240); hm.addScore("Marge",300); hm.addScore("Maggie",220); hm.addScore("Homer",100); hm.addScore("Lisa",270); System.out.print(hm.getHighscoreString()); } }
Afther that you can add scores by using the .addScore() method. The first parameter has to be the name of your player and the 2nd one is the highscore (as an int).
You can print the getHighscoreString function to get the highscore in String-format and display them on the console with System.out.print()
Note: the first time you run you will get a "FNF Error", this means that the program hasn't found the highscore-file, this is logical because we haven't created that, but you don't have to worry, Java will create one itself, so afther the first time you won't have the error anymore.
Last edited by Shaddix; 10-02-2009 at 10:56 AM.
Very cool! +rep (if you want contest points, don't forget to PM me)
Cool. +rep
Why do you implement the Serializable interface?
You don't need to indicate that you are returning +1.Code:public int compare(Score score1, Score score2) { int sc1 = score1.getScore(); int sc2 = score2.getScore(); if (sc1 > sc2){ return -1; }else if (sc1 < sc2){ return +1; }else{ return 0; } }
You can just use return 1. Anyhow I didn't know that the Comparator was a generic class, that makes things much easier.
Perhaps, you should check if the file doesn't exist and then create it? Maybe populate it with some default values so you don't get an error?the first time you run you will get a "FNF Error", this means that the program hasn't found the highscore-file, this is logical because we haven't created that, but you don't have to worry, Java will create one itself, so afther the first time you won't have the error anymore.
On that, is it more efficient to sort the array every time you add a new score or just insert the score into the array into the correct position (so it always is sorted)?
What does your program do if you try to add a score that doesn't belong in the array? Like say I get a score that doesn't belong in the top 10, do you add it anyways? Then don't bother displaying it.
If that is how your code works, why sort the array just to find that the score doesn't belong in the array?
I'm not shure what the technical explenation is, but I know that if you don't do that you get this error:
Yes I know the "+" isn't necessary but I did that for myself, I also stated in the explanation that you don't have to put it thereCode:[Laad] IO Error: highscores.Score; highscores.Score; class invalid for deserialization [Update] IO Error: highscores.Score [Laad] IO Error: writing aborted; java.io.NotSerializableException: highscores.Score [Update] IO Error: highscores.Score [Laad] IO Error: writing aborted; java.io.NotSerializableException: highscores.Score [Update] IO Error: highscores.Score [Laad] IO Error: writing aborted; java.io.NotSerializableException: highscores.Score [Update] IO Error: highscores.Score [Laad] IO Error: writing aborted; java.io.NotSerializableException: highscores.Score [Update] IO Error: highscores.Score [Laad] IO Error: writing aborted; java.io.NotSerializableException: highscores.Score
yes, you could do that, but Java automatic creates the file if it isn't there, the error message that you get also says Java will attempt to create the file
if the score doesn't belong in the top 10 it adds it, that's because I got this code from a school project I did, and the project allowed the user to define how many scores it wanted to show in the highscores
if you always wanted to show only 10, it would be better to make sure you have only 10 in the arraylist, you are right about that
about the sorting, it might be more efficient, I didn't have a good thought about it to be honnest, you can just change the location you sort if you like
thanks, it help me for making high score for my final project. Thanks
Hi, nice tutorial.
Few things i noticed: You made separate Comparator class for scores, i think there's better way to do it, like implement Comparable directly in the Score class and override the Object's compareTo method.
Also, if you override the comparison method, there's no need to implement it for integer comparison manually, as the wrapper Integer already knows how to compare Integers, so i rewrote it like that:
Code:class Score implements Serializable, Comparable<Score>{ private static final long serialVersionUID = 1L; private int score; private String naam; public int getScore() { return score; } public String getNaam() { return naam; } public Score(String naam, int score) { this.score = score; this.naam = naam; } @Override public int compareTo(Score score1) { return ((Integer)(score1.getScore())).compareTo(getScore()); } }
hm, does anyone know how to solve this problem (based from the last conversation):
What does your program do if you try to add a score that doesn't belong in the array? Like say I get a score that doesn't belong in the top 10, do you add it anyways? Then don't bother displaying it.
You could add the score to the array but don't display it. You could also check if the score doesn't belong in the array at all.
Like if my game only has 10 scores, I will only output the first 10 scores. I don't save any additional scores to a text file beyond the first ten.
The serializable interface doesn't add any functionality to your class. It however is required to write the object to a file. It's basicly there to make the programmer think before just writing something.
There are currently 3 users browsing this thread. (0 members and 3 guests)
Bookmarks