This site requires JavaScript, please enable it in your browser!
Greenfoot back
Recorsi
Recorsi wrote ...

2018/9/13

How can I save and read a highscore?

1
2
Recorsi Recorsi

2018/9/13

#
Hi, i implemented a very simple highscore into my game:
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)

/**
 * Write a description of class Highscore here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class Highscore extends Actor
{
    int highscore;
    public void act() 
    {
       drawText();
       setHighscore();
    }  
    private void drawText()
    {
       GreenfootImage img = new GreenfootImage(220, 100);
       img.setColor(new Color(0, 0, 0, 0));
       img.fill();
       img.setColor(Color.LIGHT_GRAY);
       img.setFont(new Font("Pixeled", false, false , 10));
       img.drawString("Highscore: "+highscore, 10, 90);
       setImage(img);
    }
    public void setHighscore()
    {
        if (HitCounter.hitscore > highscore)
        {
            highscore = HitCounter.hitscore;
        }
    }
}
The problem is, every time i restart the program the highscore resets. How can i create a text file(or something similar) which saves the integer and reads it again at the start of the game? (The game isn't intended to be uploaded here) Thanks :)
Super_Hippo Super_Hippo

2018/9/15

#
Take a look at the UserInfo class (https://www.greenfoot.org/files/javadoc/).
Recorsi Recorsi

2018/9/15

#
Super_Hippo wrote...
Take a look at the UserInfo class (https://www.greenfoot.org/files/javadoc/).
The description says "The UserInfo class can be used to store data permanently on a server, and to share this data between different users, when the scenario runs on the Greenfoot web site. Storage is only available when the current user is logged in on the Greenfoot site" Can this even be used if i don't upload the scenario?
danpost danpost

2018/9/16

#
Recorsi wrote...
Can this even be used if i don't upload the scenario?
Yes -- as long as you run it in the greenfoot environment (must enter a username in preferences). It will not work, however, if you create an executable jar file (through 'Share'ing it) out of it. As a stand-alone (executable jar file), you will need to create, open, read, write and close a file to store any values.
Recorsi Recorsi

2018/9/17

#
I hope im not bothering you too much, but i just can't get it to work with the UserInfo class. Here is my current code for the highscore:
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)

/**
 * Write a description of class Highscore here.
 * 
 * @author 
 * @version 
 */
public class Highscore extends Actor
{
    UserInfo userInfo;
    boolean loggedIn;
    int highscore;
    public void act() 
    {
       getUserInfo();
       drawText();
       setHighscore();
    }  
    private void drawText()
    {
       GreenfootImage img = new GreenfootImage(220, 100);
       img.setColor(new Color(0, 0, 0, 0));
       img.fill();
       img.setColor(Color.LIGHT_GRAY);
       img.setFont(new Font("Pixeled", false, false , 10));
       img.drawString("Highscore: "+highscore, 10, 90);
       setImage(img);
    }
    private void getUserInfo() //test
    {
        if (UserInfo.isStorageAvailable()) {
            userInfo = UserInfo.getMyInfo();
            loggedIn = true;
            //System.out.println("Logged in");
        } else {
            loggedIn = false;
            userInfo = null;
        }
    }
    public void setHighscore()
    {
        /*if (HitCounter.hitscore > highscore)
        {
            highscore = HitCounter.hitscore;
        }*/
        if (UserInfo.isStorageAvailable()) {
            UserInfo myInfo = UserInfo.getMyInfo();
            if (HitCounter.hitscore > myInfo.getScore()) {
                myInfo.setScore(highscore);
                myInfo.store();  // write back to server
            }
        }
    }
}
The current score you have is the hitscore. If the current score is higher than the highscore, it should save the score and show it again the next time you open the game.
danpost danpost

2018/9/17

#
There seems to be several issues with the given code. I cannot positively say that any are directly related to your current issue. (1) You should only need to get the UserInfo object once -- not every act cycle; and certainly not twice every act cycle, which is what appears to be what your current code does (act method first calls getUserInfo, then calls setHigscore, which also taps the server for the UserInfo object). Add a constructor to get the UserInfo object and throughout the rest of the class, just check to make sure it is not still null: If it is null, then you could have it try to access it again (in case server was temporarily unavailable). The loggedIn field is totally unnecessary. (2) You also only need to update the image when the high score is actually changed. Updating the image every act cycle is a waste on CPU time (not nearly as bad as tapping the UserInfo server twice an act cycle, which probably causes some lag on its one if uploaded to the site -- but still wasteful). Call the drawText method from the constructor for its initial image and then again in the setHighscore method during a new high score update. You may want to show the class code where you create and add the Highscore object into the world. It may have something to do with your current issue.
Recorsi Recorsi

2018/9/19

#
Thanks for the info i changed to highscore class a bit:
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)

/**
 * Write a description of class Highscore here.
 * 
 * @author 
 * @version 
 */
public class Highscore extends Actor
{
    UserInfo userInfo;
    boolean loggedIn;
    int highscore;
    boolean storageAvailable = false;
    public Highscore()
    {
        drawText();
        
        if (UserInfo.isStorageAvailable())
        {
            storageAvailable = true;
        } else {
            userInfo = null;
        }
    }
    public void act() 
    {
       //getUserInfo();
       if (storageAvailable) setHighscore();
    }  
    private void drawText()
    {
       GreenfootImage img = new GreenfootImage(220, 100);
       img.setColor(new Color(0, 0, 0, 0));
       img.fill();
       img.setColor(Color.LIGHT_GRAY);
       img.setFont(new Font("Pixeled", false, false , 10));
       img.drawString("Highscore: "+highscore, 10, 90);
       setImage(img);
    }
    private void getUserInfo() //not called
    {
        if (UserInfo.isStorageAvailable()) {
            userInfo = UserInfo.getMyInfo();
            loggedIn = true;
        } else {
            loggedIn = false;
            userInfo = null;
        }
    }
    public void setHighscore()
    {
        /*if (HitCounter.hitscore > highscore)
        {
            highscore = HitCounter.hitscore;
        }*/
        UserInfo myInfo = UserInfo.getMyInfo();
        if (HitCounter.hitscore > myInfo.getScore()) {
            myInfo.setScore(highscore);
            drawText();
            myInfo.store();  // write back to server
        }
    }
}
I hops this is what you meant. The highscore objects gets created in the constructor of the world class:
addObject(highscore, 760, 45);
The Hitcounter gets created separately also in the constructor, like this:
private void prepareHitCounter()
    {
       addObject(hitcounter, 579, 83); 
    }
(My game looks like this:) Here is the hitcounter code:
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
//import java.awt.Color;
/**
 * Gives you points for killing Entities
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class HitCounter extends Actor
{
    static int hitscore = 0;
    public void act() 
    {
       drawImage();
       centerScore();
    }
    private void drawImage()
    {
       GreenfootImage img = new GreenfootImage(500, 100);
       img.setColor(new Color(0, 0, 0, 0));
       img.fill();
       img.setColor(Color.WHITE);
       img.setFont(new Font("Edit Undo Line BRK", false, false , 95));
       img.drawString(""+hitscore, 10, 90);
       img.scale(300, 75);
       setImage(img);
    }
    public void centerScore()
    {
        if (hitscore > 9 && hitscore < 20)
        {
            setLocation(562, getY());
        }
        if (hitscore >= 20 && hitscore < 100)
        {
            setLocation(562, getY());
        }
        if (hitscore >= 110 && hitscore < 120)
        {
            setLocation(573, getY());
        }
        if (hitscore >= 120 && hitscore < 200)
        {
            setLocation(565, getY());
        }
        if (hitscore > 200)
        {
            setLocation(546, getY());
        }
    }
    public void addhitScore()
    {
        hitscore++;
    }
    public void add2hitScore()
    {
        hitscore += 2;
    }
    public void add50hitScore()
    {
        hitscore += 50;
    }
}
My problem is using the counter as a highscore and saving that number.
Super_Hippo Super_Hippo

2018/9/19

#
Generally, the way of doing it is this: When the game is over, check if the score is better than the best score of the person (the score which is saved somewhere in the UserInfo object, for example as the score-field). If so, overwrite this field by the new best score. So you should not get the the UserInfo object every act-cycle, but before you do so, you have to check if storage is available if you ever want to upload it here. Reason for this is that the scenario shouldn't crash when the server is temporarily not available or the internet connection of the user was lost in the middle of the game or whatever. Checking it once when the scenario is created is basically the same as asking if the Greenfoot user has a name in the preferences which isn't empty.
Recorsi Recorsi

2018/9/19

#
Super_Hippo wrote...
Generally, the way of doing it is this: When the game is over, check if the score is better than the best score of the person
So i dont have to check this in the highscore class then but rather in the class which ends the game, right? Edit: I just noticed i have a method in my world class that checks if you are alive or not (=Game over). Can i do something with this?
    
public void checkSpaceship()
    {
        if (getObjects(Spaceship.class).isEmpty())
        {
            resetTimer--;
            if (resetTimer <= 0)
            {
                HitCounter.hitscore = 0;
                Greenfoot.setWorld(new Space());
            }
        }
    }
Super_Hippo Super_Hippo

2018/9/19

#
Is there a reason for the static keyword for the 'hitscore' variable? You could do the check if the Highscore should be updated before you reset it.
Recorsi Recorsi

2018/9/19

#
I've added the Static keyword while testing, because otherwise it wouldn't let me access the variable from an other class And I couldn't find a way to access the drawText method, it always says "non-static method cannot be referenced from a static context"
Super_Hippo wrote...
You could do the check if the Highscore should be updated before you reset it.
I will try that
Super_Hippo Super_Hippo

2018/9/19

#
You need a reference to the Highscore object. Then you can call non-static methods on it. 'static context' means that you are trying to access a variable/method of a class. It's the same thing when you want an object to add another object to the world.
MyWorld.addObject(…
doesn't work. You can not add an object to the class MyWorld, but you can add an object to an instance of the MyWorld class
getWorld().addObject(…
Recorsi Recorsi

2018/9/20

#
Shouldn't I be able to do this then?
Highscore.drawText();
(At least this worked with other methods) But i still get the same error
danpost danpost

2018/9/20

#
You should only use "static" in a class if all objects of the class make use of the same member (method or field). Since each world will draw its own text, "static" cannot be used with regard to the drawText method. You can call the method with code like the following from an Actor subclass:
((MyWorld)getWorld()).drawText();
Super_Hippo Super_Hippo

2018/9/20

#
Highscore is an Actor subclass, not a World subclass.
There are more replies on the next page.
1
2