立即以复杂的转弯结束比赛

时间:2014-03-26 07:55:26

标签: java multithreading interrupt

结束一个允许每回合一个动作的回合制游戏是相当微不足道的 - 你可以在满足各种输赢条件时更新布尔值,并在每次循环转弯时检查布尔值当比赛结束时出局。

然而,我正在编写的游戏涉及更复杂的转弯,玩家会为每个角色执行多个操作,其中包含可能导致胜利或失败的多个角色,以及可能导致角色转弯之间发生的多次计算机运行更新在亏损。显然,当达到胜利条件时必须中断转弯。

我想到的选项:

  • 每个循环只需继续检查一次完成。这个选项并没有真正起作用 - 即使你已经赢了(甚至可能不可能),你也必须完成转弯的所有动作,并且你必须包括特殊的处理程序以确保一个完成条件不会被另一个人在同一回合中覆盖。

  • 在堆栈中抛出异常,直到你回到main方法,然后捕获异常,解析它,并提供输/输消息。令人难以置信的是实施,而不是真正的例外。

  • 使用 observer / listener 模型或事件处理程序将另一个方法调用抛到堆栈上,而不是从游戏循环中优雅地提取自己的程序。似乎更多的是插入一些快速代码或将消息发送到其他线程,而不是结束当前的游戏循环。

  • 将游戏循环置于其自己的主题中,只要达到胜利条件就会终止。主要方法是在一个单独的循环中等待游戏状态的变化,并根据需要进行处理。这种方法的问题在于(在Java中,无论如何)实现Runnable实际上不允许从其他地方停止正在运行的线程(你必须从run()方法返回),甚至扩展Thread(无论如何都不应该这样做)并且在满足条件时调用this.interrupt()实际上并不会阻止游戏代码继续运行。虽然你可以轮询线程的中断标志来驱动逻辑,但这只会给我们带来同样的问题而不是真正作为中断工作。

一些代码:

public static void main(String[] args) {        
    Game game = new Game(2, Difficulty.NOVICE);
    game.run();

    while(game.getGameState() == State.INCOMPLETE){
        //Hold while waiting for game to complete.
    }
}

public class Game extends Thread{

    public void checkState(){
    //Let's presume a win condition was thrown:
        state = State.WON;
        this.interrupt();
    }

    public void randomMethod(){
        //This method might contain some code that triggers a win condition, so we immediately call checkState()
        checkState();
    }

    @Override
    public void run() {
        //Lots of different methods called in a single turn, including for example:
        randomMethod();
    }
}

我确信有一个众所周知的行业标准来做这种事情,但我没有发现它在任何地方拼写出来,而我却不知道它可能是什么。

解决方案Balder引用的状态模型似乎只是故障单。这个主要的要点是跟踪给定转弯的状态,并让游戏循环执行一个动作,可以根据游戏当前所处的状态改变动态变化的游戏。有很多方法可以做到这一点 - 按照他的回答中的链接演示了其中的一些。这是我最终使用的实现:

while(gameState_ == GameState.INCOMPLETE){
    turnState_.update();
    checkWin();
}

public void changeTurnState(TurnState state){
    turnState_.exit();
    turnState_ = state;
    turnState_.enter();
}

public abstract class TurnState{
    private Game game;

    public TurnState(Game game){
        this.game = game;
    }

    public void enter(){
    }

    public void exit(){
    }

    public Game getGame(){
         return game;
    }

    public void update(){
    }
}

通过这种设置,我可以扩展TurnState以产生我希望的任何状态,以及在该状态的单个动作期间发生的任何需要。例如,考虑用于泛滥板上的一个或多个区域的状态。请记住,我们需要对游戏的每次更改单独进行,以便我们可以检查两者之间的胜利条件 - 所以这个特定的状态会跟踪我们留下多少个区域以进行泛滥,并在最后一个必要区域进入后移动到下一个状态水淹没。

public class FloodState extends TurnState {

    private int remainingFloods;

    /**
     * @param game
     */
    public FloodState(Game game) {
        super(game);
        remainingFloods = getGame().getFloodRate();
        ForbiddenIsland.logger.info("Flooding {} tiles", remainingFloods);
    }

    public void update(){
        //Draw and resolve a flood card, then decrement remainingFloods
        getGame().flood();
        remainingFloods--;

        //If no more floods remaining, jump to next state
        if(remainingFloods == 0){
            getGame().changeTurnState(new ActionState(getGame()));
        }
    }
}

2 个答案:

答案 0 :(得分:1)

我对游戏开发的经验很少。因此,将此答案视为新手观点。也许这有助于找到合适的方法。主要思想是模型由一个类转变为复杂的角色。游戏循环不关心简单或复杂的转弯。因此,在循环的每个步骤中,它调用processTurn()来转发游戏。方法processTurn()参考跟踪复杂转弯状态的CharacterState并将其转发一步。如果复杂的转弯完成,它会返回true以表示没有任何事情要做。游戏循环继续评估新游戏状态,结果为GameState。然后它渲染游戏世界重新翻译角色。如果游戏结束,游戏循环将检查每个步骤,如果,则终止。

public class Game implements Runnable {

    private GameWorld gameWorld;
    private CharacterState characterState;

    public Game(int value, Difficulty novice) {}

    @Override public void run() {
        while (gameWorld.getGameState() != GameState.COMPLETE) {
            Turn turn = processTurn();
            turn.apply(gameWorld);
            renderGame();
        }
    }

    /**
     * Processes the next step of a complex turn
     */
    private Turn processTurn() {
        Turn turn = characterState.processTurn();
        if (characterState.isDone()) {
            characterState = nextCharactersTurn();
        }
        return turn;
    }

    /**
     * Computes which character has to go next and returns its turn state beginning with the first
     * step of the complex turn.
     * 
     * @return the next characters complex turn
     */
    private CharacterState nextCharactersTurn() {
        throw new UnsupportedOperationException("not yet implemented");
    }

    /**
     * Renders the game world
     */
    private void renderGame() {
        throw new UnsupportedOperationException("not yet implemented");
    }
}

class GameWorld {

    /**
     * Returns the state of the game derived from the state of the world.
     * 
     * @return
     *      the game state
     */
    public GameState getGameState() {
        throw new UnsupportedOperationException("not yet implemented");
    }
}

/**
 * Tracks the complex state of each character turn
 */
class CharacterState {

    /**
     * Processes one step of a complex turn
     * 
     * @return the next turn
     */
    public Turn processTurn() {
        throw new UnsupportedOperationException("not yet implemented");
    }

    /**
     * @return true, if no more turn ar possible for this complex turn, otherwise false.
     */
    public boolean isDone() {
        throw new UnsupportedOperationException("not yet implemented");
    };
}

/**
 * An sequence of commands to be executed atomically.
 * 
 * Each sequence has to be composed of a minimal set of commands representing a transition from one
 * consistent game state to another consistent game state.
 */
class Turn {

    /**
     * Applies all changes encapsulated by this turn to the game world.
     * 
     * Applying the changes may change the game state as a side effect
     * 
     * @param world
     *      to apply the changes at
     */
    public void apply(GameWorld world) {}
}

答案 1 :(得分:1)

如果我理解正确,那么您正试图为您的游戏实施某种State Pattern。我建议不要在每个循环周期中调用while(game.getGameState() == State.INCOMPLETE),而是将游戏状态逻辑完全从主循环中移开并改为使用抽象状态类:

public abstract class AbstractGameState{
    protected abstract void update(float delta);
}

然后你可以为你的转弯设置另一个抽象状态类,如果游戏尚未获胜,则只执行更新。否则它将结束游戏。

public abstract class TurnGameState extends AbstractGameState{
    protected final void updateState(float delta){
        if (isWinConditionSatisfied()) {
            // end the game by setting the final state
            TurnBasedGame.currentState = new EndGameState();
        } else{
            update(delta);
        }
    }
    protected abstract void update(float delta);
    private boolean isWinConditionSatisfied() {
        // somehow check if the game is won
        return false;
    }
}

回合制逻辑的每个部分都可以代表一个TurnGameState,它将从主游戏循环中更新,并且您还有一个EndGameState,一旦赢得游戏就会输入:

public class EndGameState extends AbstractGameState{
    @Override
    protected void updateState(float delta) {
        // this simple implementation just ends the game loop
        TurnBasedGame.gameIsRunning = false;
    }
}

这是一个非常简化的游戏循环,它使用了这个概念:

public class TurnBasedGame {

    private static boolean gameIsRunning;
    private static AbstractGameState currentState;

    public static void main(String[] args) {
        while (gameIsRunning) {
            // very simplified game loop...

            // somehow handle the delta for the game loop...
            float delta;

            // update the game logic
            doGameUpdates(delta);

            // render game graphics here...
            render();
        }
    }

    private static void doGameUpdates(float delta) {
        currentState.update(delta);
    }
}

当然,我发布的所有代码都非常简单,只是试图说明一般概念。例如。你可能想要一个GameStateManager类来处理添加和删除状态,你当然会有更复杂的主游戏循环等。

有关所涉及概念的概述,请查看以下资源: