1
\$\begingroup\$

Battles in my game run fully automatically and return a combat log afterwards. My main game loop looks like this:

public BattleResult run() throws BattleException {
    BattleResult result = null;
    while((result = this.determineWinners()) == null) {
        // TODO: execute the turn an move on to the next character
        this.history.add(new BattleLog(this.currentState.copy()));
    }
    return result;
}

Basically, as long as the game isn't over determineWinners will return null and the main loop continues. Once a win condition is reached (usually all characters of either one or both teams have died), the method wraps the battle history together with the winners and returns them, causing the loop to break.

The important part is handling each individual turn, which right now consists of several phases:

  • turn start: set state.currentCharacter to state.nextCharacter and state.playedCard to null. If the current character is stunned, skip to the last phase
  • draw card: instruct the current characters deck to return the next card and store it in state.playedCard. If the deck is empty, null is returned, causing the character to die and skip to the last phase
  • play card: Retrieve the card from state and resolve its effects
  • (not implemented yet) apply on-turn-end effects
  • set state.nextCharacter to the next character in order or leave it as-is, if the current character gets to take another turn. Dead characters are skipped over

Right now, i'm implementing my turns like this:

public BattleResult run() throws BattleException {
    BattleResult result = null;
    while((result = this.determineWinners()) == null) {
        Phase phase = this.startingPhase;
        while(phase != null) {
            phase = phase.execute(this.currentState, this.effectFactory);
        }
        this.history.add(new BattleLog(this.currentState.copy()));
    }
    return result;
}

 

@FunctionalInterface
public interface Phase {
    public Phase execute(BattleState state, EffectFactory factory) throws BattleException;
}

 

public final class DefaultPhases {
    public static final Phase TURN_START = new TurnStart();
    public static final Phase DRAW_CARD = new DrawCard();
    public static final Phase PLAY_CARD = new PlayCard();
    // ...
    public static final Phase SET_NEXT = new SetNext();
}

 

public class TurnStart implements Phase {

    @Override
    public Phase execute(BattleState state, EffectFactory factory) throws BattleException {
        state.advanceCharacter();
        state.setPlayedCard(null);
        return DefaultPhases.DRAW_CARD;
    }
}

 

public class DrawCard implements Phase {

    @Override
    public Phase execute(BattleState state, EffectFactory factory) throws BattleException {
        CharacterState character = state.getCurrentCharacter();
        Card card = character.drawCard();
        if(card == null) {
            character.setLife(0);
            return DefaultPhases.SET_NEXT;
        }
        state.setPlayedCard(card);
        return DefaultPhases.PLAY_CARD;
    }
}

 

public class PlayCard implements Phase {

    @Override
    public Phase execute(BattleState state, EffectFactory factory) throws BattleException {
        factory.getEffect(state.getPlayedCard().getId()).resolve(state);
        return DefaultPhases.SET_NEXT;
    }
}

 

public class SetNext implements Phase {

    @Override
    public Phase execute(BattleState state, EffectFactory factory) throws BattleException {
        // some logic to determine the next character
        return null;
    }
}

So, every phase executes its logic (setting up the turn, drawing a card, playing it, etc) and returns the next one. Once a phase returns null, the turn ends, the current state is saved into history and the next turn begins (unless the game is over).

In general i like this system, as it allows me to dynamically skip or add phases, depending on whatever i need and i can also completely change the rules of a battle by setting startingPhase to something else than DefaultPhases.TURN_START.

But, since this is my first time designing a system like this, i would like to get some feedback about my design or if i should better use something different.

\$\endgroup\$
2
  • 2
    \$\begingroup\$ If you have code that works, and you just want input on coding style/architecture, the Code Review StackExchange might be a good place to ask. Here we're more specialized in answering specific questions and solving problems, which doesn't seem to be what you need. \$\endgroup\$
    – DMGregory
    Commented Mar 25, 2018 at 11:50
  • 1
    \$\begingroup\$ My feedback would be that you should stop being afraid of "not doing stuff the rigth way". There is no one right way to do things in software development. Just ways which work for you and ways which don't work for you. As long as you do not recognize any problems, you are on the way which works. \$\endgroup\$
    – Philipp
    Commented Mar 25, 2018 at 13:09

1 Answer 1

-1
\$\begingroup\$

i think you may read a little about "finite state machine" and how to implement that in a game, with that in mind i think you can make a better desing not only for what you want, but for others users as well.

\$\endgroup\$
3
  • \$\begingroup\$ while the idea of 'FSM' might lead to a solution you should be more precise on your answer - this general purpose answer does not provide an help on the question. \$\endgroup\$ Commented May 28, 2018 at 11:22
  • \$\begingroup\$ if you understand how to use FSM, you can do all you want, im beign precise if that is a broad topic im saying like, check this and apply what you need. if you are saying im not precise, then i invite you to make it precise. \$\endgroup\$ Commented May 28, 2018 at 18:28
  • \$\begingroup\$ please tell us how you would design such an FSM. Tell us, what states you would propose, tell us how you switch from one state to another, prtovide an uml diagramm. explain why you would set these states and no other states and how your design could be extended for future application... \$\endgroup\$ Commented May 29, 2018 at 4:21

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .