Jump to content

Making a simple high-score system

* * * * * 1 votes

  • Please log in to reply
20 replies to this topic

#1
Shaddix

Shaddix

    Programmer

  • Members
  • PipPipPipPip
  • 102 posts
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:
  • 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
all this classes will be in the package "highscores"

The Score Class

   
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;
    }
}
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.
We implement serializable to be able to sort this type.

The ScoreComparator Class

  
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;
            }
        }
}

This class is used to tell Java how it needs to compare 2 objects of the type score.
-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:
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>();
    }
}
I have added comments to explain what's already in the class.

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.

    
public ArrayList<Score> getScores() {
        loadScoreFile();
        sort();
        return scores;
    }
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.

   
private void sort() {
        ScoreComparator comparator = new ScoreComparator();
        Collections.sort(scores, comparator);
}
This function will create a new object "comparator" from the class ScoreComparator.
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".

 
public void addScore(String name, int score) {
        loadScoreFile();
        scores.add(new Score(name, score));
        updateScoreFile();
}
This method is to add scores to the scorefile.
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.

 
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());
            }
        }
}
This function will load the arraylist that is in the high-score file and will put it in the "scores"-arraylist.
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).

 
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());
            }
        }
}
This is about the same as loadScoreFile(), but instead of reading the file it will be writing the "score"-arraylist to the file.

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;
}
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.
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.

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());
    }
}
First you have to create an object from the HighscoreManager class, we will call it "hm" in here.
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.

Edited by Shaddix, 02 October 2009 - 09:56 AM.


#2
Guest_Jordan_*

Guest_Jordan_*
  • Guests
Very cool! +rep (if you want contest points, don't forget to PM me)

#3
WingedPanther

WingedPanther

    A spammer's worst nightmare

  • Moderators
  • 16,831 posts
  • Location:Upstate, South Carolina
  • Programming Language:C, C++, PL/SQL, Delphi/Object Pascal, Pascal, Transact-SQL, Others
  • Learning:Java, C#, PHP, JavaScript, Lisp, Fortran, Haskell, Others
Cool. +rep
Programming is a branch of mathematics.
My CodeCall Blog | My Personal Blog

#4
chili5

chili5

    Writes binary right handed and hex left handed

  • Members
  • PipPipPipPipPipPipPipPipPip
  • 7,247 posts
  • Programming Language:Java, C#, PHP
  • Learning:C, C++, C#, PHP, Transact-SQL, Assembly, Scheme
Why do you implement the Serializable interface?

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 don't need to indicate that you are returning +1.

You can just use return 1. Anyhow I didn't know that the Comparator was a generic class, that makes things much easier.

Quote

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.

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?

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?

#5
Shaddix

Shaddix

    Programmer

  • Members
  • PipPipPipPip
  • 102 posts

chili5 said:

Why do you implement the Serializable interface?

I'm not shure what the technical explenation is, but I know that if you don't do that you get this error:

[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

chili5 said:

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 don't need to indicate that you are returning +1.

You can just use return 1. Anyhow I didn't know that the Comparator was a generic class, that makes things much easier.
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 there


chili5 said:

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?
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

chili5 said:

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?

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

#6
alchemist19

alchemist19

    Newbie

  • Members
  • Pip
  • 2 posts
thanks, it help me for making high score for my final project. Thanks

#7
Sinipull

Sinipull

    Programming Expert

  • Members
  • PipPipPipPipPipPip
  • 386 posts
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:
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());
    }
}


#8
alchemist19

alchemist19

    Newbie

  • Members
  • Pip
  • 2 posts
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.

#9
chili5

chili5

    Writes binary right handed and hex left handed

  • Members
  • PipPipPipPipPipPipPipPipPip
  • 7,247 posts
  • Programming Language:Java, C#, PHP
  • Learning:C, C++, C#, PHP, Transact-SQL, Assembly, Scheme
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.

#10
wim DC

wim DC

    Writes binary right handed and hex left handed

  • Members
  • PipPipPipPipPipPipPipPipPip
  • 2,084 posts
  • Programming Language:Java, JavaScript, PL/SQL
  • Learning:Java
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.

#11
GMVResources

GMVResources

    Learning Programmer

  • Members
  • PipPipPip
  • 72 posts
gj! +rep

#12
krome

krome

    Newbie

  • Members
  • Pip
  • 3 posts
i've been trying to make a similar way to write highscores to a text file when i stumbled across this thread from google. hoping to see if i would get the results i was after, i followed this tutorial and it worked, however when it prints to the file i get a garbled mess of characters:

¬í sr java.util.ArrayListxÒ™Ça I sizexp   w   

sr Scoreòê06_³ I scoreL namet Ljava/lang/String;xp   t dylanx

although it did successfully print my name at the end of the last line, it didn't print the score, only a bunch of java references to the ArrayList class and some other characters that didn't come out right

does anyone know why i get this? i'm pretty new to file IO so..

EDIT: ok i fixed this problem by using PrintWriter instead of ObjectOutputStream and writing a for loop to print each score individually from the array instead of the array itself. however, now i'm trying to figure out why it only writes one score to the file. for example if no file exists and i run my program, it will print the high score to the file, but if i run it again with the previous score in the file already, it won't print anything new to the file.

Edited by krome, 09 December 2010 - 01:07 PM.





3 user(s) are reading this topic

0 members, 3 guests, 0 anonymous users