jeudi 8 décembre 2022

How to implement an "unlock" system in a game

I'm currently implementing an 'unlock' system which will cause certain features (menu options, stats) to become visible and functional when some conditions are met.

I have a working solution and am wondering if another way of doing things might be better when it comes to saving/loading the game state.

Currently, the way I'm doing it is to have an 'unlocked' bool and an unlock() function associated with each Stat or Option instance.

class Option:
    def __init__(self, text, keyCode, func, unlocked = True, unlock=""):
        self.text = text
        self.keyCode = keyCode
        self.func = func
        self.unlocked = unlocked
        self.unlock = unlock

Then in the main program loop, when programmatically displaying all of the user's stats or the options contained in the current menu, a check is done against the 'unlocked' bool for each option or stat and then if it's False, a check against the unlock() function associated with that object.

for i in current.options:
    #short-circuit so no unlock() call on options that lack unlock functions
    if (i.unlocked or i.unlock(i)):
        print(Style.BRIGHT + Fore.WHITE + " " + i.text + Style.RESET_ALL)

This function then updates the value of the 'unlocked' bool if the conditions are met.

e.g.:

def unlockShop(i):
    global energy
    if (energy >= 5):
        i.unlocked = True 
        return True

This works fine and dandy but I was thinking about a redesign for the purpose of simplifying serialization. I haven't implemented save/load mechanics yet but I've tried to engineer things toward that end and I feel like this unlock scheme isn't very amenable to that.

An alternative approach I'm considering is to have a single object responsible for managing all unlocks. This object would contain a hashmap or something that maps a given option/stat to a tuple containing the 'unlocked' bool and unlock() function associated with said option/stat.

The key in the hashmap would be some handle that would itself be an attribute of the option/stat class. But the 'unlocked' bool and unlock() function would no longer be members of the option/stat classes but contained (in the case of the bool) or pointed to (in the case of the function) in/by the tuple in the hashmap.

This seems like a better solution for serialization because when saving or loading, we only need to iterate through this single object to rebuild the state of unlocks in the game, rather than looping through all instances of the option/stat classes and saving reading/writing their 'unlocked' bools.

I may be over or under-engineering this. Or there may be an entirely better more logical way to approach this.

Aucun commentaire:

Enregistrer un commentaire