Click here to Skip to main content
11,634,815 members (70,348 online)
Click here to Skip to main content

Tracking High Scores on Windows Phone 7

, 12 Mar 2011 CPOL 8K 124 3
Rate this:
Please Sign up or sign in to vote.
How to implements local high scores in Windows Phone 7.

Another frequent question I come across in user forums is related to how to implement local high scores. The question has come up frequently enough for me to conclude that it is to the benefit of the community to have an implementation available that can be used in Silverlight or XNA that is ready to be used with very little setup.

So I've made a solution for others to use. By default, the component will keep track of up to 10 high scores and will take care of loading and saving itself. If you add a score, the component will take care of ensuring the score is in its proper place and removing scores that are no longer one of the top. For persisting score information, I've made use of the DataSaver<T> code from a previous blog post. I hope others will find the solution easy to use.

To get started with using the component, add a reference to my component to your project. You'll want to instantiate HighScoreList passing an optional file name that it will use to save score information. It's possible to keep track of more than one high score list as long as your instances have different file names. Youe might want to do this if they keep track of scores in different modes separately from each other (e.g.: a score list for Difficult mode, a score list for Easy mode, and so on).

HighScoreList _highScoreList = new HighScoreList("MyScores"); 

Upon instantiation, the component will take care of loading any previous high scores without you doing anything more.

To add a score, create a new instance of ScoreInfo and populate its PlayerName and Score fields. (There is also a ScoreDate field that automatically gets populated with the current date and time). Then use the AddScore(ScoreInfo) method on the HighScoreList instance to add it to the score list.

ScoreInfo scoreInfo = new ScoreInfo(){PlayerName = "Jack", Score = 1048576};
_highScoreList.AddScore(scoreInfo);

And that's it, there's nothing more for you to do. When you make that call, the score gets added to the high score list, scores that are no longer in the top 10 (or whatever you set the limit to be) will fall off the list, and the list will automatically be persisted back to IsolatedStorage so that it is available the next time your game runs. Easy, right?

As a test project, I've created a Silverlight application that allows you to enter new scores and see the behaviour of the component.

image.png

The main bits of the source code are below. First, the ScoreInfo class which is nothing more than a serializable collection of three properties:

/// <span class="code-SummaryComment"><summary>
</span>

And then the HighScoreList class, which is a collection class:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.Serialization;


namespace J2i.Net.ScoreKeeper
{
    public class HighScoreList : ObservableCollection<ScoreInfo>, 
                                 INotifyPropertyChanged    
    {
        static DataSaver<HighScoreList> MyDataSaver = 
               new DataSaver<HighScoreList>();

        public HighScoreList()
        {
            
        }

        public HighScoreList(string fileName):this()
        {
            this.ScoreFileName = fileName;
            HighScoreList temp = MyDataSaver.LoadMyData(fileName);
            if(temp!=null)
            {
                foreach(var item in temp)
                {
                    Add(item);
                }
            }
        }
                
        // MaxScoreCount - generated from ObservableField snippet - Joel Ivory Johnson
        private int _maxScoreCount = 10;
        [DataMember]
        public int MaxScoreCount
        {
            get { return _maxScoreCount; }
            set
            {
                if (_maxScoreCount != value)
                {
                    _maxScoreCount = value;
                    OnPropertyChanged("MaxScoreCount");
                }
            }
        }
        //-----

                
        // ScoreFileName - generated from ObservableField snippet - Joel Ivory Johnson
        private string _scoreFileName = "DefaultScores";
        [DataMember]
        public string ScoreFileName
        {
            get { return _scoreFileName; }        
            set
            {
                if (_scoreFileName != value)
                {
                    _scoreFileName = value;
                    OnPropertyChanged("ScoreFileName");
                }
            }
        }
        //-----

                
        // AutoSave - generated from ObservableField snippet - Joel Ivory Johnson
        private bool _autoSave = true;
        [DataMember]
        public bool AutoSave
        {        
            get { return _autoSave; }
            set
            {
                if (_autoSave != value)
                {
                    _autoSave = value;
                    OnPropertyChanged("AutoSave");
                }
            }
        }
        //-----

        static int ScoreComparer(ScoreInfo a, ScoreInfo b)
        {
            return b.Score - a.Score;
        }

        public void SortAndDrop()
        {
            List<ScoreInfo> temp = new List<ScoreInfo>(this.Count);
            foreach(var item in this)
            {
                temp.Add(item);
            }

            if (temp.Count > MaxScoreCount)
            {
                temp.RemoveRange(MaxScoreCount - 1, (temp.Count) - (MaxScoreCount));
            }

            temp.Sort(ScoreComparer);
            this.Clear();

            temp.ForEach((o)=>Add(o));


        }

        public void Save()
        {
            if(String.IsNullOrEmpty(ScoreFileName))
                throw new ArgumentException("A file name wasn't provided");
            MyDataSaver.SaveMyData(this, ScoreFileName);
        }

        public void AddScore(ScoreInfo score)
        {
            this.Add(score);
            SortAndDrop();
            if(AutoSave)
                Save();
        }
        
        protected void OnPropertyChanged(String propertyName)
        {
            if(PropertyChanged!=null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Joel Ivory Johnson
Software Developer Razorfish
United States United States
I attended Southern Polytechnic State University and earned a Bachelors of Science in Computer Science and later returned to earn a Masters of Science in Software Engineering.

For the past few years I've been providing solutions to clients using Microsoft technologies for web and Windows applications.

While most of my CodeProject.com articles are centered around Windows Phone it is only one of the areas in which I work and one of my interests. I also have interest in mobile development on Android and iPhone. Professionally I work with several Microsoft technologies including SQL Server technologies, Silverlight/WPF, ASP.Net and others. My recreational development interest are centered around Artificial Inteligence especially in the area of machine vision.

Twitter:@J2iNet

You may also be interested in...

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.150728.1 | Last Updated 12 Mar 2011
Article Copyright 2011 by Joel Ivory Johnson
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid