3
\$\begingroup\$

I'm working on an RPG game for my coursework project. Everything is going fine but I've reached a stage where I do think that my project's code is not the most efficient.

Here I have a constructor of my class AbstractMob

public AbstractMob (String name, int hp, int attack, int defense, int magicAttack,
                        int magicDefense, int expBound, int goldBound, String folder, String idleAtlas, String attackAtlas) {

        abilities = new ArrayList<>();
        //setting variables
        this.attack = attack; //and so on

        idleAnimation = new Animation<>(
                0.070f, new TextureAtlas(Gdx.files.internal(
                        "sprites\\mobs\\" + folder)).findRegions(idleAtlas),
                Animation.PlayMode.LOOP);

        attackAnimation = new Animation<>(
                0.070f, new TextureAtlas(Gdx.files.internal(
                        "sprites\\mobs\\"+ folder)).findRegions(attackAtlas),
                Animation.PlayMode.LOOP);
    }

And here is an example of a class that inherits AbstractMob

public class FireElemental extends AbstractMob {
    public FireElemental() {
        super("Fire Elemental",
                400,
                12,
                10,
                18,
                15,
                50,
                20,
                "fireElemental\\fire.atlas",
                "firesprite",
                "firesprite"
        );
        //from AbstrctMob, declares any abilities the mob has
        abilities.add(new Fire()); //same design pattern as these mob creations,
        //I have a separate class for Abilities, and subclasses such as Fire 
        //that inherit from Abilities


        setAbilities(abilities);
    }
}

Now, my question is - does it make sense to create a multitude of separate classes (i.e make more classes like FireElemental for different mobs) for each entity (whether that be abilities or mobs) for this game? How about utilising files/scripts to load them?

Thank you so much!

\$\endgroup\$
  • \$\begingroup\$ It looks like all that's different between your mobs is the data assigned to their variables. Is that accurate? \$\endgroup\$ – DMGregory Nov 6 '19 at 11:20
  • \$\begingroup\$ @DMGregory yes that's it, hence why I don't think this is the best way of approaching the problem :') \$\endgroup\$ – thesameritan Nov 6 '19 at 11:29
3
\$\begingroup\$

Typically for a pure data change like this, we would not use separate classes.

Instead, you could make your class non-abstract (say "BasicMob" to leave room if you need more complex mob classes in future) and give it one or several Factory Methods that populate the data of your mob to make a specific variant. eg..

public static BasicMob CreateFireElemental() {

    BasicMob mob = new BasicMob(
         "Fire Elemental",
          400,
          12,
          10,
          18,
          15,
          50,
          20, 
          "fireElemental\\fire.atlas", 
          "firesprite", 
          "firesprite"
      );

       mob.abilities.add(new Fire());
       mob.setAbilities(mob.abilities);

      return mob;
}

If many of these properties are constant for all instances of a given "kind" of mob, then you could abstract them out to a Type Object, then construct a mob from a type object.

// For brevity I'll make this all public.
// In practice you'll likely want these parameters to be immutable.
public class MobType {
    public int maxHP;
    public int attack;
    public int defense;
    public Ability[] abilities;
    // You probably don't want to look up
    // sprites by name every time — do that once.
    public SpriteSet sprites;
}

public BasicMob(MobType typeToCreate) {
    mobType = typeToCreate;
    currentHP = mobType.maxHP;
}

Now each new mob type needs no new class or method at all. You can just keep a library of type objects to pass when you want to spawn a mob.

Once you've separated your "type" of mob into its own object, you can even deserialize it from a human-readable text file like JSON. Then you can just have a folder of mob definitions like "fireElemental.json" "earthElemental.json" that you read on start-up or on demand whenever a new mob ID is requested in your level.

The advantage of doing it this way is if you have non-technical team members, like game designers and level designers who don't write code. If they can experiment with new combinations of stats & abilities for mobs just by editing text files, even adding new mob types to the game with no dependency on coders and no need to even recompile, then your team's iteration speed gets a massive boost.

It also opens the door to a player modding community, if you choose to make this serialized format user-editable in the released version.

\$\endgroup\$
  • 1
    \$\begingroup\$ As for mob AI, you can use scripts (eg. Lua), or write a class for each type of AI, whichever suits you best. This way you'll be able to create the same mob with aggresive and passive AI, different ways of fighting, etc. \$\endgroup\$ – crueltear Nov 7 '19 at 12:26

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.