-1

I'm creating an RPG game where a player has a set of skills, each of which he can level up to improve its effect. Here are two example skills:

  • health: increase player's maximum health
  • regeneration: slowly regenerate player's lost health back

Skills have many similar attributes, like name, description, maximum_level, and some event callbacks which tell what the skill should do, so I figured I should maybe create a class and these would be instances of it:

class Skill:
    def __init__(self, name, description, max_level, level=0):
        self.name = name
        self.description = description
        self.max_level = max_level
        self.level = level
        self.event_callbacks = {}

    def register_callback(self, event_name):
        def decorator(f):
             self.event_callbacks[event_name] = f
             return f
        return decorator

health_skill = Skill('health', 'increase player\'s maximum health', 8)

@health_skill.register_callback('player_spawn')
def on_player_spawn(skill, player):
    player.maximum_health += skill.level * 5

regeneration_skill = Skill('regeneration', 'regenerate player\'s lost health back', 8)

@regeneration_skill.register_callback('time_tick_second')
def on_second_tick(skill, player):
    if player.health < player.maximum_health:
        player.health = max(player.health + skill.level, player.maximum_health)

player.skills.extend([health_skill, regeneration_skill])

And this system works fine, but here's the problem: my game can have multiple players in it, and each of them needs its own instance of each skill. Now I need to somehow figure out a good structure where I can

  1. create skills easily
  2. create multiple instances of each skill easily

Any ideas of a good structure? Metaclasses? Subclassing? How do games usually do this?

Edit: This similar structure is used in many popular games like League of Legends, Dota 2, Hearthstone, etc... Another good example of this issue is heroes/champions in such games: each hero is similar and they obviously have a common base, yet each hero needs a lot of custom instance attributes like current health, mana, level, etc.

  • 1
    Once instance of per ability per player. Whats the issue? – marstato Sep 22 '16 at 13:07
  • How do I structure this? @marstato I basically need instances of instances. I'd also prefer not to have 20x memory used by storing the name, description, and max_level into every instance of a skill instance since they're always the same for the same kind of skills – Markus Meskanen Sep 22 '16 at 13:13
0

Creating only one skill class is, and then registering the callbacks with a decoration is an awkward pattern IMO. Just create a class for each skill. Each skill class directly adds the callbacks it needs. You can then give each player a set of skill objects instantiated from these classes.

0

Sadly, i do not know the language you are using but i'll try using Java:

I'd create an interface Skill that you use outside of the skill-internal code. Then you can have an abstract class DefaultSkill that defines your common properties. You can then create a new skill class subclassing either Skill or DefaultSkill to implement special behaviour:

interface Skill {
    public String getName();
    public int getCurrentLevel();
    public int getMaximumLevel();

    public void onPlayerSpawn();
    public void onTick();
}

abstract class DefaultSkill implements Skill {
    private int currentLevel;
    private Player owningPlayer;

    public DefaultSkill(int startLevel, Player owningPlayer) {
        // .. assign to instance variables
    }
}

class HealthSkill extends DefaultSkill {

    public HealthSkill(Player player) {
        super(100, player);
    }

    public String getName() {
        return "Health";
    }

    public int getCurrentLevel() {
        return this.currentLevel;
    }

    public int getMaximumLevel() {
        return 100;
    }

    // implement onPlayerSpawn()
    // implement onTick()
}

Skill health = new HealthSkill(player);

You can take it one step further and separate skills and their development for each player:

interface Skill {
    public String getName();
    public int getMinimumLevel();
    public int getMaximumLevel();

    public void onPlayerSpawn(SkillDevelopment development, Player player);
    public void onTick(SkillDevelopment development, Player player);
}

interface SkillDevelopment {
    public Skill getSkill();
    public Player getPlayer();
    public int getCurrentLevel();
    public void setCurrentLevel(int level);

    public void onPlayerSpawn();
    public void onTick();
}

class DefaultSkillDevelopment implements SkillDevelopment {
    private int level;
    private Skill skill;
    private Player player;

    public DefaultSkillDevelopment(Skill skill, Player player, int startLevel) {
        // ...
    }

    public int getCurrentLevel() {
        return level;
    }

    public void setCurrentLevel(int level) {
        if (level < skill.getMinimumLevel() || level > skill.getMaximumLevel())
            throw new IllegalArgumentException();

        this.level = level;
    }

    public void onPlayerSpawn() {
        skill.onPlayerSpawn(this, player);
    }

    public void onTick() {
        skill.onTick(this, player);
    }
}

class HealthSkill implements Skill {

    private static final HealthSkill INSTANCE = new HealthSkill();

    public static HealthSkill getInstance() {
        return INSTANCE;
    }

    public String getName() {
        return "Health";
    }

    public int getMinimumLevel() {
        return 0;
    }

    public int getMaximumLevel() {
        return 100;
    }

    // implement onPlayerSpawn()
    // implement onTick()
}

SkillDevelopment health = new DefaultSkillDevelopment(HealthSkill.getInstance(), player);
  • Python doesn't have interfaces. The Python equivalent of an interface is nothing: you "implement an interface" by just implementing some methods, and you "accept an object implementing an interface" by accepting any object and assuming that it implements the relevant methods. – Tanner Swett Sep 22 '16 at 14:00
  • @TannerSwett too sad, didnt know that – marstato Sep 22 '16 at 14:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.