游戏中 Undo/Redo 功能的堆栈实现

Stack implementation for Undo/Redo functionality in game

我正在开发一款游戏,其中玩家可以在 board/grid 周围移动。它具有 moveLeft()、moveRight()、moveUp() 和 moveDown() 方法,可让玩家在棋盘上一次移动 1 space。

我正在尝试规划我的方法来实现玩家移动所需的 Undo/Redo 功能(例如,如果玩家向左移动了一个 space,并且调用了撤消,玩家将移动一个space 向右)。我是一名学生,正在研究 Stacks。

但是,在编程之前在纸上计划逻辑时(我发现这对我做作业有帮助),我不知道基于以下问题是否 Stacks 合适....

当调用每个移动方法时,字符串 'Up'、'Down'、'Left'、'Right' 被添加到堆栈 1,具体取决于调用的方法。这会跟踪玩家在棋盘上的移动。

如果调用 undo(),堆栈 1 顶部的字符串将被删除,并添加到新堆栈 'Stack 2'。这用于跟踪 'undone' 移动,以便 redo() 有路径可循。

如果调用 redo(),Stack 2 上的字符串将被删除,并返回添加到 Stack 1。

这非常有效,但前提是您调用 Redo() 的次数与 Undo() 的次数完全相同,并且紧随其后。

例如:

  1. 玩家进行 4 次移动:(第 1 叠现在有 4 根弦)
  2. Undo() 被调用一次:(堆栈 1 现在有 3 个字符串,堆栈 2 有 1 个字符串)
  3. 玩家再走 4 步:(第 1 叠现在有 7 根弦,第 2 叠仍然有 1 根弦)
  4. Undo() 被调用一次:(堆栈 1 现在有 6 个字符串,堆栈 2 有 2 个字符串)
  5. Redo() 被调用:(这里是问题所在)这可以被调用两次,因为 Stack 2 有 2 个字符串,但实际上棋盘上的 Player 应该只能调用 Redo() 一次。

在过去的 4 小时里,我一直在努力研究这背后的逻辑!任何建议表示赞赏。即 - 基于以上所述,是否仍然可以使用 Stacks 执行我需要执行的操作,并且我需要找到解决该问题的方法?还是我应该放弃,因为这是不可能的。

这样想.. 撤消和重做的整个想法都围绕着您的应用程序(程序)的状态。撤消意味着您想要立即进入应用程序的前一个状态; Redo 也是如此。是的,堆栈是保存以前状态的最佳解决方案。对于撤消,您执行弹出操作并将其推送到另一个堆栈。使用另一个堆栈进行重做操作。 您可能想要设置撤消和重做的限制。 您如何保存应用程序的状态取决于您。

在第 3 步中

Player makes 4 more moves: (Stack 1 now has 7 strings, Stack 2 still has 1 string) 

你必须清空第二个堆栈。

修复起来很简单。基本上,仅当前一个动作是撤消时,重做才有效。

一个解决方案是:当玩家移动时清空堆栈 2(撤消堆栈,用于重做)。

其他解决方案:推迟堆栈 2 清除。维护一个布尔标志,用于跟踪先前的操作是否为撤消(比如 boolean isRecentActionUndo),如果每次调用撤消( ) 并在每次调用 Move() 时将其设置为 false。在 Redo() 中检查此标志。

if(isRecentActionUndo) { // perform redo } else { // clear stack 2 }

可能有其他更好的解决方案来实现相同的效果,以执行有效的 Redo()。

如果您不想使用 Stacks 因为您不确定何时清除撤消 Stack,您可以使用 List 来完成此操作。然后,您的逻辑可以以类似的方式维护:

  • 保留您所走棋步的索引(从 0 开始,每走一步递增 1)
  • 如果撤消已完成,则递减索引(除非您位于列表的开头)
  • 如果重做完成,增加索引(除非你在列表的末尾)
  • 如果执行新的移动,增加索引并清除所有大于或等于索引的移动(从而清除您的 undo/redo 移动)

那么,你的例子是:

  1. 玩家进行了 4 次移动(索引为 3,列表有 4 个项目)
  2. Undo() 被调用一次(索引为 2,列表有 4 个项目)
  3. 玩家再移动 4 步(索引为 6,列表有 7 个项目,所有 undo/redo 个项目已清除)
  4. Undo() 被调用一次(索引为 5,列表有 7 个项目)
  5. 重做被调用一次(索引为 6,列表有 7 个项目)
  6. 再次调用重做(因为没有可用的重做操作而被拒绝)