Nested if/else, switches or something more efficient for RPG combat?

768 views Asked by At

I'm developing a turn based RPG in java for android phones and I'm currently trying to figure out how to handle attacks that have extra variables beyond damage. For example, I would like to have fire attacks do an extra 10% damage when the target has a burn effect. I'm a bit unsure how to go about doing this in an efficient way and one that allows for future additions to my status/attack system.

So here are my thoughts on how I can do this:

  1. A series of if/else statements or switch's

    switch (status) {
    case burned:
        if (type == fire) {
            damage = damage * 1.1;
        }
        break;
    case frozen:
        if (type == ice) {
            damage = damage * 2;
        }
        break;
    }
    

    I could also use nested switches if I have many possible results for each status.

  2. Use an two dimensional array with the x values being statuses and the y values being attacks or types. When you check the [x][y] it returns a numerical value for the change that will occur in attack.

          Burned   Frozen
    
    Fire  [1.1]    [1]
    
    Ice   [1]      [2]
    

While both of these seem fine for now, I'm unsure if it will work for the future. Right now, I can certainly use combinations that change the damage amount, but what about attacks that have non-numerical effects where I can't simply return a value and multiply my damage by that value?

Would it be possible to generate some sort of code that represents a situation like:

burned = 1 in first position, frozen = 2
fire attack = f in 2nd position, ice = i
damage mod is in the 3rd position

so a fire attack on a burned enemy would be 1-f-1.1.

3

There are 3 answers

0
AntoineG On BEST ANSWER

You should try to use polymorphism.

For the switches/if-elses

Create an interface that represents attacks, and let it declare a single method:

public interface Attack {
    double doAttack(double baseDamage);
}

Then create classes that implement this interface:

public class FireAttack implements Attack {
    double doAttack(double baseDamage){
        return 1.1 * baseDamage;
    }
}

public class IceAttack implements Attack {
    double doAttack(double baseDamage){
        return 2 * baseDamage;
    }
}

Then instead of using switch statements in your code, do something like this:

public class Player {
    private Attack mAttack;

    // Somewhere in your code, you setup something like
    void setFireWeapon(){
        mAttack = new FireAttack();
    }

    // This is where the attack is taken care of
    double inflictDamage() {
        return mAttack.doAttack();
    }
}

What this allows you to do is to implement any new type of attack you may wish in the future, and simply assign Attack mAttack with this new implementation of interface Attack. This is a trivial exemple, you could do some stuff much more powerfull than baseDamage * aDouble if you wish.

For the status (burned/frozen)

There are many ways you could implement states like frozen. First you could use the same pattern I explained above.

On top of having a Attack mAttack member, you could also add similar logic with a HealthStatus mHealthStatus or whatever name you prefer. Then the call to inflictDamage() would redirect the mAttack object to the mHealthStatus object.

Then the HealthStatus class would again be an interface,

public interface HealthStatus {
    double considerAttack(Attack anAttack);
}

which would have implementations of various states:

public class NormalStatus implements HealthStatus{
    double considerAttack(Attack anAttack){
        return anAttack.doAttack(); // No change here
    }
}

public class FrozenStatus implements HealthStatus{
    double considerAttack(Attack anAttack){
        return 0; // Can't attack when froxen
    }
}

public class BurnedStatus implements HealthStatus{
    double considerAttack(Attack anAttack){
        return anAttack.doAttack() * 2.0; // Get berserk when on fire!
    }
}

You could also use the other patterns. I recommend you look at Design Patterns, which solve problems like the one you are facing.

Just to name a few.

0
Akos Cz On

AntonieG is on the right track. The general solution to this problem is to use the Strategy Design pattern.

Strategy

Motivation

There are common situations when classes differ only in their behavior. For this cases is a good idea to isolate the algorithms in separate classes in order to have the ability to select different algorithms at runtime.

Intent

Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

Implementation

Strategy Pattern Impl http://www.oodesign.com/strategy-pattern.html

Also take a look at the following links.

http://en.wikipedia.org/wiki/Strategy_pattern

http://blogs.microsoft.co.il/blogs/gilf/archive/2009/11/22/applying-strategy-pattern-instead-of-using-switch-statements.aspx

1
BenN On

Your thinking seems too linear. Use Object Oriented principles to design your game. Create classes for your attacks that extend the generic attack.

public abstract class Attack{
    protected String attackName;
    protected Double damage;

    public Attack(){
        attackName = "Standard";
        damage = 1.0;
    }

    public Double getDamage(){
        return damage;
    }

    public String getAttackName(){
        return attackName;
    }
}

Then extend:

public class FireStorm extends Attack{
    public FireStorm(String attackName, Double damage){
        this.attackName = attackName;
        this.damage = damage;
    }

    @Override
    public Double getDamage(Enemy target){
        if(target.hasBurnEffect()){
            damage *= 2.0;
        } else {
            damage = super.getDamage();
        }

        return damage;
    }
}

I don't really know much about the scope of things in your game, so I can't make it too much more descriptive. But if you're wanting to make your game flexible and extendable as you suggest, then you will want to use inheritance and other principles of object oriented programming.