Achievement System

Hey guys, I just wanted to share with you an achievement system I quickly knocked up. I guess I’m looking at ways of improving my code or if you can see anything that would cause issues later.

using UnityEngine;
using System.Collections;

public class AchievementManager : BMBSingleton<AchievementManager>
{
    public Achievements[] achivements;

    public void SetProgress(string key, float progress)
    {
        foreach(Achievements ach in achivements)
        {
            if(ach.key == key)
            {
                if(ach.progress < ach.goal)
                {
                    ach.progress += progress;
                    if(ach.progress >= ach.goal)
                    {
                        UnlockAchievement(ach);
                    }
                    else
                        Debug.Log ("We've added to the achievement " + ach.name);
                }
                else
                    Debug.Log ("You've already unlocked achievement " + ach.name);
            }
            else
                Debug.Log ("There isn't an achievement of the key " + key);
        }
    }

    private void UnlockAchievement(Achievements ach)
    {
        ach.unlocked = true;
        ach.currentDisplayedTexture = ach.unlockedTexture;
    }

    private void LockAchievement(Achievements ach)
    {
        ach.unlocked = false;
        ach.currentDisplayedTexture = ach.lockedTexture;
    }

    public void UnlockAllAchivements()
    {
        foreach(Achievements ach in achivements)
        {
            ach.unlocked = true;
            ach.currentDisplayedTexture = ach.unlockedTexture;
        }
    }

    public void LockAllAchievements()
    {
        foreach(Achievements ach in achivements)
        {
            ach.unlocked = false;
            ach.currentDisplayedTexture = ach.lockedTexture;
        }
    }

    public void SaveAllAchivements()
    {
        foreach(Achievements ach in achivements)
        {
            PlayerPrefs.SetFloat(ach.key, ach.progress);
        }
    }

    public void LoadAllAchivements()
    {
        float progress;
        foreach(Achievements ach in achivements)
        {
            progress = PlayerPrefs.GetFloat(ach.key);
            if(progress >= ach.goal)
            {
                ach.unlocked = true;
                ach.currentDisplayedTexture = ach.unlockedTexture;
            }
            else
            {
                ach.unlocked = false;
                ach.currentDisplayedTexture = ach.lockedTexture;
            }
        }
    }
}



[System.Serializable]
public class Achievements
{
    public string key;
    public string name;
    public string description;

    public bool unlocked;

    public float progress;
    public float goal;

    public Texture2D lockedTexture;
    public Texture2D unlockedTexture;

    public Texture2D currentDisplayedTexture;

}

So now anywhere in any script I can simply call

AchievementManager.I.SetProgress("KeyNameOffAchivement", 1);

And Ideally it should handle itself, any improvements are welcome,

Thanks.

1 Like

Thanks for sharing this, I think I might use it. Just one item that might help you in the future, you have a lot of nested if statements in the SetProgress function. It might make things easier if you ever had to debug the function to keep all the if statements un-nested and flat. Here is an article in Dr Dobbs by a really smart guy named Michael Feathers that talks more about the benefits.

if (a && b) {
    X;
}

if (a && b && c && d) {
    Y;
}

if (a && b && !(c && d)) {
     Z;
}
2 Likes

I quite liked that article.

One other minor coding-style quibble: I would expect your SetProgress method to set the progress, but what it actually appears to do is add progress. Adding and setting are two different things.

1 Like

Thank you for the feedback guys, I will check out the article. Any other feedback is greatly welcome.