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

2014/10/30

Using the built in ScoreBoard + UserInfo to track top scores

Gish Gish

2014/10/30

#
Hello Greenfoot community, I've been lurking for some time now, but have yet to post. However, I am stumped and could use some pointers. I'm finishing up my first game (that's not a school assignment), and am wanting to track and display the top 5 (or so) high scores at the end of the game. I found some posts already discussing this, and have been able to implement the code for the most part, however after the game ends, it only displays the single highest score (this is through the Greenfoot client on my PC, not the website) and then my Greenfoot memory usage skyrockets and I get Java Heap Space errors (that's for a different post). Is this perhaps because it is recognizing that I am the only one playing, so it is just replacing my scores as they get higher? Here is what I've done so far
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
import java.awt.Color;
import java.util.List;
 
/**
 * An actor class that can display a scoreboard, using Greenfoot's
 * UserInfo class. 
 *
 * You typically use this by including some code into the world for when your game ends:
 *
 * <pre>
 *   addObject(new ScoreBoard(800, 600), getWidth() / 2, getHeight() / 2);
 * </pre>
 *
 * Where 800 by 600 should be replaced by the desired size of the score board.
 *
 * @author Neil Brown
 * @version 1.0
 */
public class ScoreBoard extends Actor
{
    // The vertical gap between user images in the scoreboard:
    private static final int GAP = 10;
    // The height of the "All Players"/"Near Me" text at the top:
    private static final int HEADER_TEXT_HEIGHT = 25;
    // The main text color:
    private static final Color MAIN_COLOR = new Color(0x60, 0x60, 0x60); // dark grey
    // The score color:
    private static final Color SCORE_COLOR = new Color(0xB0, 0x40, 0x40); // orange-y
    // The background colors:
    private static final Color BACKGROUND_COLOR = new Color(0xFF, 0xFF, 0xFF, 0xB0);
    private static final Color BACKGROUND_HIGHLIGHT_COLOR = new Color(180, 230, 255, 0xB0);
 
    /**
     * Constructor for objects of class ScoreBoard.
     * <p>
     * You can specify the width and height that the score board should be, but
     * a minimum width of 600 will be enforced.
     */
    public ScoreBoard(int width, int height)
    {   
        setImage(new GreenfootImage(Math.max(600, width), height));
        drawScores();
        leaderBoard();
    }
 
    private void drawString(String text, int x, int y, Color color, int height)
    {
        getImage().drawImage(new GreenfootImage(text, height, color, new Color (0, true)), x, y);
    }
 
    private void drawScores()
    {
        // 50 pixels is the max height of the user image
        final int pixelsPerUser = 50 + 2*GAP;
        // Calculate how many users we have room for:
        final int numUsers = ((getImage().getHeight() - (HEADER_TEXT_HEIGHT + 10)) / pixelsPerUser);
        final int topSpace = (getImage().getHeight() - (numUsers * pixelsPerUser) - GAP);
 
        getImage().setColor(BACKGROUND_COLOR);
        getImage().fill();
 
        drawString("All Players", 100, topSpace - HEADER_TEXT_HEIGHT - 5, MAIN_COLOR, HEADER_TEXT_HEIGHT);
        drawString("Near You", 100 + getImage().getWidth() / 2, topSpace - HEADER_TEXT_HEIGHT - 5, MAIN_COLOR, HEADER_TEXT_HEIGHT);       
 
        drawUserPanel(GAP, topSpace, (getImage().getWidth() / 2) - GAP, topSpace + numUsers * pixelsPerUser, UserInfo.getTop(numUsers));
        drawUserPanel(GAP + getImage().getWidth() / 2, topSpace, getImage().getWidth() - GAP, topSpace + numUsers * pixelsPerUser, UserInfo.getNearby(numUsers));
    }
 
    private void drawUserPanel(int left, int top, int right, int bottom, List users)
    {
        getImage().setColor(MAIN_COLOR);
        getImage().drawRect(left, top, right - left, bottom - top);
 
        if (users == null)
            return;
 
        UserInfo me = UserInfo.getMyInfo();
        int y = top + GAP;
        for (Object obj : users)
        {
            UserInfo playerData = (UserInfo)obj;           
            Color c;
 
            if (me != null && playerData.getUserName().equals(me.getUserName()))
            {
                // Highlight our row in a sky blue colour:
                c = BACKGROUND_HIGHLIGHT_COLOR;
            }
            else
            {
                c = BACKGROUND_COLOR;
            }
            getImage().setColor(c);
            getImage().fillRect(left + 5, y - GAP + 1, right - left - 10, 50 + 2*GAP - 1);
 
            int x = left + 10;
            drawString("#" + Integer.toString(playerData.getRank()), x, y+18, MAIN_COLOR, 14);
            x += 50;
            drawString(Integer.toString(playerData.getScore()), x, y+18, SCORE_COLOR, 14);
            x += 80;
            getImage().drawImage(playerData.getUserImage(), x, y);
            x += 55;
            drawString(playerData.getUserName(), x, y + 18, MAIN_COLOR, 14);
            y += 50 + 2*GAP;
        }
    }
 
    public void leaderBoard()
    {
        if (UserInfo.isStorageAvailable())
        
            UserInfo myInfo = UserInfo.getMyInfo(); 
            if (ScoreText.score > myInfo.getScore())
            
                myInfo.setScore(ScoreText.score); 
                myInfo.store();  // write back to server 
            
 
        }
    }
}
I also have this line of code calling the ScoreBoard in a different class
1
2
3
4
if(health == 0)
{           
getWorld().addObject(new ScoreBoard(600, 400), getWorld().getWidth() / 2, getWorld().getHeight() / 2);
}
Thanks in advance for any pointers :)
danpost danpost

2014/10/31

#
Try this for line 1:
1
if(health == 0 && getWorld().getObjects(ScoreBoard.class).isEmpty())
Without the second part and without having the actor created from the class this particular code is in removed from the world, the code will produce scoreboard upon scoreboard (that is, the health will continue to be constantly checked and a scoreboard object will be produced each act cycle as long as the value of health remains at zero). This is what causes the memory usage to skyrocket and produce the Java heap space error. If you have not been changing the username, then that would explain why only one high score is shown. You can, from the menubar, select 'Edit>Preferences' and under the Miscellaneous tab change the username (or remove it to simulate user not being logged in).
Gish Gish

2014/10/31

#
I'm not sure how you do it, danpost, but you always seem to be able to help. I don't know why I overlooked that conditional statement for adding the scoreboard only once. I also tried this with a new user name, and it all seems to be working perfectly. Just a few more tweeks and Ill be ready to submit. Thanks again.
You need to login to post a reply.