Games For Fun - Weapons and Combat for an RPG like - Part 2

Games for fun here!

This article is the second part of a series covering my experience building a simple combat system for a runner/beat'n'up/rpg/rogue-like game on Unity3D. Just for fun.

Please check part 1 before reading this, otherwise you may become confused.


I have ended part 1 with a hook to upgrading the combat system so it can handle more dynamic weapons, effects, attacks, etc.

Let's remeber IAttack and ICombatTarget:

public interface ICombatTarget
{
    //something is attacking me so I must defend
    void Defend(int attack);
}

public interface IAttacker
{
    //The attacker returns its damage
    int Attack();
    //and must have a target
    ICombatTarget GetTarget();
}

And a simply implementation of Attack() on the player would be like this:

public int Attack()
{
    int attacks = 0;
    //the player base attack, calculated using STR attribute or something. 
    attacks += this.GetPlayerBaseAttack();
    //the current equiped weapon on the player
    attacks += this.GetPlayerWeapon().GetAttack();
    return attacks;
}

And from part 1:

"The player is leveling up, geting gold and buying new weapons with special effects. Can you imagine what would happen if the player weilded weapons on both hands, or if the player used some weapons with elemental effects or with double hit?"

If the only issue was to increment the attack value based on specific calculatioins owned by weapons, a nice solution would be to use something like a simple decorator pattern to decorate the IAttacker.Attack() result. Situation example: Player hits with a flaming sword that hits twice on a single attack for 10 damage each hit

  1. Player hits with 10 fire damage * 2 = 20 fire damage once
  2. Enemy is resistent to fire and damage is reduced to 10 fire damage once
  3. Enemy has 1 base defense plus 1 armor defense, with total defense of 2
  4. The remaining 5 fire damage once, is reduced from the enemy total defense: 10 - 2 = 7 fire damage once.
  5. Enemy loses 7 health points from 7 fire damage once.

Works good, right? Huuuum, not yet. If the mechanics go further and consider special effects, double hits, etc, Attack() cannot simply return and int value because defenders may defend each kind of attack differently. Let's see the same case again, but defending each attack individualy:

  1. Player hits with 10 fire damage twice
  2. Enemy is resistent to fire and damage is reduced to 5 fire damage twice
  3. Enemy has 1 base defense plus 1 armor defense, with total defense of 2
  4. The remaining 5 fire damage twice, is reduced from the enemy total defense: 5 - 2 = 3 fire damage twice.
  5. Enemy loses 3 + 3 health points from 3 fire damage twice.

So by handling each attack individualy, the monster take a total of 6 damage against 7 damage if the attack was just summed. Can you figure out other variations of the case above? Try that on your head for summing the attacks and defending each individualy:

  • player hits 10 fire damage twice on an enemy with no fire defense
  • player hits 10 fire damage twice on an enemy vulnerable to fire
  • player hits 10 normal damage twice on an enemy that always ignore odd attacks on an entire combat

The examples goes far away as much as you want to imagine.

Now, down to business. The next step is transforming the attack from an integer value to an interface. But note here that I will leave attack types for part 3:

IAttack

public interface IAttack
{
    //get the total damage 
    int GetDamage();
    //adds more damage
    void AddDamage(int damage);
}

And a simple implementation of a concrete attack (or abstract If I want to extend it in the future) would be like this:

class BasicAttack : IAttack
{

    protected int damage = 0;
    
    public BasicAttack(int damage = 0) 
    {
        SetDamage(damage);
    }

    public int GetDamage()
    {
        return damage;
    }
    
    public void AddDamage(int damage)
    {
        this.damage += damage;
    }
}

And now that the project has an interface for attacks, IAttacker.Attack() should return a list of IAttack objects and ICombatTarget.Defend() should accept a list of IAttack as well:

public interface IAttacker
{
    //The attacker returns its damage
    List<IAttack> Attack();
    //and must have a target
    ICombatTarget GetTarget();
}

public interface ICombatTarget
{
    //something is attacking me so I must defend
    void Defend(List<IAttack> attack);
}

Now I am missing a definition for weapons. Thinking about the attack interface I just defined above, the weapon implementation should use it. Let's have a look at it:

public interface IWeapon
{
    //get the IAttacks of a weapon
    List<IAttack> Attack();
    //and add IAttacks to a weapon of course
    void AddAttack(IAttack attack);
}

This post is getting longer and full of detail, but stay with me, we are getting there.

Let's check the player action manager again with the new interfaces:

Player Actions Manager

public class PlayerActions : MonoBehaviour, IAttacker, ICombatTarget 
{ 

    //a lot of attributes goes here
    ...
    //a lot of other methos goes here
    ...
	
    public List<IAttack> WeaponAttacks()
    {
        /*
        here the method could iterate over the weapons and their 
        IAttacks every time an Attack() happens, or the player could have an attribute 
        with a list that is populated every time it changes the equiped 
        weapons and return it here.
        Personally, I would go for the second option, but for the sake of the example:
        */
	List<IAttack> attacks = new List<IAttack>();
	foreach(IWeapon weapon in this.GetEquipedWeapons())
        {
	    attacks.AddRange(weapon.Attack());
        }
        return attacks;
		
    }

    public List<IAttack> Attack()
    {
        List<IAttack> attacks = new List<IAttack>();
        //the player base attack, calculated using STR attribute or something. 
	int baseAttack = this.GetPlayerBaseAttack();
		
        //and for every weapon, get its IAttacks
	foreach(IAttack attack in this.WeaponAttacks())
        {
            //weapons damage must be added with the player base attack.
            //A decorator could be used here of course.
	    attack.AddDamage(baseAttack);
	    attacks.add(attack);
	}
        return attacks;
    }

    public ICombatTarget GetTarget()
    {
        //this one doesn't change
        return this.GetClosestFocusedEnemy();
    }

    //a fight method used by a combat manager or something like this...
    public void Fight(){
        // this doesn't change, however, Defend() is now getting a 
        //list of IAttack as seem above for the player implementation
        this.GetTarget().Defend(this.Attack());
    }

    public void Defend(List<IAttack> attacks)
    {
        
        int damage = 0;
        int armor = this.GetArmor();
        foreach(IAttack attack in attacks)
        {
	    damage = attack.GetDamage() - armor;
	    /*
	    An option here would be to sum the damage and take all at once. 
            It depends on your project.
	    */
            if(damage > 0)
	    {
	        this.TakeDamage(damage);
	    }
        }
    }
}

Finally for the enemy classes the implementation is almost the same, so I 'll leave it to you.

With this design, now every combatent game object will be able to wield weapons and fight each other. Another hidden bonus feature here, is that by using IWeapon and IAttack, the game will be able to define its weapons and attack styles on text file or any other outer source, being able to change it on runtime.

On part 3 I will try to show you the special effects and attributes for weapons. And probably by part 4, a better armor design similar to weapons will be there too.

That's all for now and see you next time.

Games For Fun - Weapons and Combat for an RPG like - Part 1

First Games for Fun here. Let`s go.

My wife and a friend started developing a mobile game using Unity3D to build up their portifolio and I am playing with them just for fun. Really, just for fun, I am no game developer or expert in any ways.

We are having fun with sort of a runner/beat'n'up/rpg/rogue-like. Yeah, that's a lot of labels. So I wanted to share some of the stuff Iam doing.

On this game, our guy goes running and fighting monsters invading a town and there is an important feature with equipaments, weapons and etc. So let us go down to business and get dirty with some code.


Approaching the combat in the game, basically the player engages monsters and they hit each other. Immediatly this elements pops some interfaces on my head: one for attackers and one for defenders/targets.

ICombatTarget

public interface ICombatTarget
{
    //something is attacking me so I must defend
    void Defend(int attack);
}

IAttacker

public interface IAttacker
{
    //The attacker returns its damage
    int Attack();
    //and must have a target
    ICombatTarget GetTarget();
}

If we wish the player to attack a monster we simply implement IAttacker on the player and ICombatTarget on the monster. Something like this:

Player Actions Manager

public class PlayerActions : MonoBehaviour, IAttacker {

    //a lot of attributes goes here
    ...
    //a lot of other methos goes here
    ...
    
    public int Attack()
    {
        int attacks = 0;
        //the player base attack, calculated using STR attribute or something. 
        attacks += this.GetPlayerBaseAttack();
        //the current equiped weapon on the player
        attacks += this.GetPlayerWeapon().GetAttack();
        return attacks;
    }

    public ICombatTarget GetTarget()
    {
        //get the closest enemy for example
        return this.GetClosestFocusedEnemy();
    }

    //a fight method used by a combat manager or something like this...
    public void Fight(){
        // here I get the engaged target and delegate the player attack for it to defend itself.
        this.GetTarget().Defend(Attack());
    }
    
}

Cool. Now the player can attack whatever object implementing ICombatTarget. In other words, any object that can be targeted during combat, will know how to defend itself, and of course, it is not a responsability of the attacker to know how the target will defend itself. Feels like a SOLID game implementation already =)

Let's check the monster: Monster Actions Manager

public class EnemyActions : MonoBehaviour, ICombatTarget{

    //a lot of attributes goes here
    ...
    //a lot of other methos goes here
    ...
    
    public void Defend(int attack)
    {
        //this one is very simple.
        //first calculate damage based on armor or something:
        int damage = attack - this.GetArmor();
        // then take damage
        if(damage > 0){
            this.TakeDamage(damage);
        }
    }

    //quick example of TakeDamage
    public void TakeDamage(int damage)
    {
        this.health -= damage;
        //so check if this enemy is dead or something. 
    }

}

Any game object implementing ICombatTarget should be able to be target of an attack.

You may be thinking: so, doesn't the enemy hit back at the player?. Yeah, you are right and probably you have already guessed how to achieve that: implement IAttacker on the enemy and ICombatTarget on the player.

The player is leveling up, geting gold and buying new weapons with special effects. Can you imagine what would happen if the player weilded weapon on both hands, of if the player used some weapons with elemental effects or with double hit? Well, attackers and targets/defenders should be opened to extension but closed for modification.

Does it means this strategy for this problem is wrong? Not at all. If it is a simple game with simple attack and defense attributes, thats ok. But on our runner/beat'n'up/rpg/rogue-like, the hero goes crazy about new weapons, so on part 2, I will explain my strategy to handle this.

Thanks, see you next time.

GitHub – fkupper

Fernando K├╝pper Cardoso