Heroes of Might and Magic 3 Battle Mechanics Replica

I’m gonna implement battle mechanics of heroes of might and magic 3, basically it is just a standard turn based game where each unit has its own specific skills, like one might have lifesteal when attacks, one can charge and attack and gain hit bonus based on tile he moved before attacking, one might have something in defense and uses it when he takes damage etc.

So the main problem is code architecture, I have BattleController class where I want to send signal to this unit, attack to this other unit. I also have Unit class which represents units, and because of the unit variety I also have a scriptableobject called UnitConfig class where I can store unit specific information on derived classes like

public abstract class UnitConfig : ScriptableObject
{
  // bunch of parameters
  int attackPower, defensePower, hitPoints;

  // every unit shares the same logic which is taking damage, attacking, and if available defensing with skills
  public virtual Attack(Unit attacker, Unit attacked)
  {
    atacked.TakeDamage(attacker.attackPower);
  }
  public virtual TakeDamage(Unit attacker, Unit attacked)
  {
    // bla bla bla
  }
  
  // bunch of other codes
}

public class GuardianUnit : UnitConfig
{
  public override Attack()
  {
    // this unit has special attack ability
    // override standard attack method and instead use special attack
  }
}

So there is some issues, first UnitConfig does a lot of things which I don’t like to, instead what it should do is just store info about specific unit’s special ability, then I can use it whenever it is possible to use, in Unit class, not in the UnitConfig file,

I have something like this in my mind:

BattleController sends Attack Command which stores info about attacker and attacked unit
Then before Units apply that command, they look for any special ability in any point (maybe it is just a defense ability or attacking one), then apply with that special ability.

For visualization: BattleController —> Attack Command (which also contains attacker and attacked unit) —> Units (which involved in command) —> UnitConfig (To see which special ability do units have for that command)

How can I develop a flexible architecture based on this problem, what would be your suggestions?

It’s hard to craft all this stuff in advance, and it kinda feels like you’ve done a reasonable amount of architecture design already, at least enough to get you moving in the right reasonable direction.

Personally I like to get about as far as you have so far, then start using it, fleshing it out.

It’s only then that you’ll see how suitable it all is. And the important part is to make only enough stuff to prove out what you’ve done: don’t make 256 different enemies, then realize something has to change!

The main reason for this thinking is that even if you THINK you know all the types of attacks you want to do right now, someone is going to say “Oh you should implement X attacks because they would be a great combination with the Y attacks you already have!” and you will realize changes are necessary.

1 Like

The main reason why I’m thinking in the early stages is that I am pretty sure someone or even I will say that “can we add X attack type to the game”, so because of that I’m trying to develop the most flexible solution. And lol I really had fun when I see 256 different enemies, you really are a programmer! :slight_smile:

1 Like

You could extract the Attack method to it’s own abstract ScriptableObject for example UnitAttack then your UnitConfig could just have a field of one (or even a list if you want) UnitAttack(s) that you can drag&drop in the editor (or even create a custom inspector if you want to do the setup directly inside the UnitConfig inspector).

You you either move the TakeDamage there too or create yet an other ScriptableObject for it, for example UnitDefense

Also one more tip, instead of passing the attacker and target to these methods I would put them into a struct for example “AttackInfo” or “DamageInfo” that makes it easier to add additional properties later, otherwise you have to refactor everytime you want to add a new parameters.

A few days ago I had a similar case, I had a TakeDamage method with attacker, defender, int dmg and wanted to add the damage source (which ability caused the damage) and had to change all my method signatures, I said screw that and just turned it into a struct instead.

1 Like

This approach has allure but I assure you, it is a Sisyphean task.

Here’s some trivial examples that will likely give fits to any combat system except ones adapted to handle it:

  • an effect that lets me take control of an enemy and use it as my own unit

  • an effect that lets me combine specific units of my players into an “uber” unit with new special features.

  • bonus: I take one of your creatures and combine it with two of my creatures to make something.

I did change the attacker and damage into the struct, actually I passed an attack command which stores attacker, target unit, damage etc. inside.

For making attack and defense standalone class it would also cause some problem, like first thing is when I plug these in inside a unit, I need to check whether it has these fields plugged in or not in every different action, I would rather just code them in their respective unique class. That way I don’t need to check fields, because if I don’t override, it will use the default behaviour.

Oh that bonus is my favorite! I will definitely consider this and try to find a way to implement that. :slight_smile: