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

Bri*_*man 5 java multithreading interrupt

结束一个允许每回合一个动作的回合制游戏是相当简单的 - 你可以在满足各种赢或输条件时更新布尔值,并在每次循环转弯时检查布尔值,以确定何时游戏结束.

然而,我正在编写的游戏涉及更复杂的转弯,玩家每个角色采取多个动作,可能会导致胜利或失败的多个角色,以及在角色转弯之间发生的几次计算机运行更新,这可能导致丢失.显然,当达到胜利条件时,必须中断转弯.

我想到的选项:

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

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

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

  • 将游戏循环放在自己的线程中,只要达到胜利条件就终止.主要方法是在一个单独的循环中等待游戏状态的变化,并根据需要进行处理.这种方法的问题在于(在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();
    }
}
Run Code Online (Sandbox Code Playgroud)

我确信有一个众所周知的行业标准来做这种事情,但我没有发现它在任何地方拼写出来,我对它可能是什么感到茫然.

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

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(){
    }
}
Run Code Online (Sandbox Code Playgroud)

通过这种设置,我可以扩展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()));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Bal*_*der 1

如果我理解正确的话,您正在尝试为您的游戏实现某种状态模式。我建议将while(game.getGameState() == State.INCOMPLETE)游戏状态逻辑完全移出主循环,并使用一个抽象状态类,而不是在每个循环周期中调用:

public abstract class AbstractGameState{
    protected abstract void update(float delta);
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以为您的回合提供另一个抽象状态类,该类仅在游戏尚未获胜时执行更新。否则就会结束游戏。

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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