【问题标题】:Java Flow Control ProblemJava 流控制问题
【发布时间】:2011-03-04 16:16:49
【问题描述】:

我正在编写一个简单的 2d 游戏引擎。我已经决定了我希望引擎如何运行:它将由包含“事件”的对象组成,我的主游戏循环将在适当的时候触发。

关于结构的更多信息: 每个GameObject 都有一个updateEvent 方法。 objectList 是所有将接收更新事件的对象的列表。只有此列表中的对象具有被游戏循环调用的 updateEvent 方法。

我正在尝试在 GameObject 类中实现这个方法(这个规范是我喜欢要实现的方法):

/**
* This method removes a GameObject from objectList.  The GameObject 
* should immediately stop executing code, that is, absolutely no more
* code inside update events will be executed for the removed game object.
* If necessary, control should transfer to the game loop.
* @param go The GameObject to be removed
*/
public void remove(GameObject go)

因此,如果一个对象试图在更新事件中移除自己,控制权应该转移回游戏引擎:

public void updateEvent() {
    //object's update event
    remove(this);
    System.out.println("Should never reach here!");
}

这是我目前所拥有的。它有效,但我越了解使用异常进行流控制,我就越不喜欢它,所以我想看看是否有替代方案。

删除方法

public void remove(GameObject go) {
    //add to removedList
    //flag as removed
    //throw an exception if removing self from inside an updateEvent
}

游戏循环

for(GameObject go : objectList) {
    try {
        if (!go.removed) {
            go.updateEvent();
        } else {
            //object is scheduled to be removed, do nothing
        }
    } catch(ObjectRemovedException e) {
        //control has been transferred back to the game loop
        //no need to do anything here
    }
}
// now remove the objects that are in removedList from objectList

2 个问题:

  1. 我是否正确假设实现上述删除方法的立即停止部分的唯一方法是抛出自定义异常并在游戏循环中捕获它? (我知道,使用异常进行流控制就像 goto,这很糟糕。我只是想不出另一种方法来做我想做的事!)

  2. 对于从列表本身中删除,一个对象可以删除列表中更靠后的对象。目前我在执行任何代码之前检查一个已删除的标志,并在每次传递结束时删除对象以避免并发修改。有没有更好的、最好是即时/非轮询的方式来做到这一点?

[编辑] 阅读您的答案后,我想我会更改方法规格。即时删除行为是我已经习惯在不同的引擎中使用的东西,但你是对的,它并不真正适合 Java 的工作方式。是时候尝试用一种稍微不同的思维方式来思考了!

【问题讨论】:

    标签: java exception iterator control-flow conceptual


    【解决方案1】:

    我同意异常方法是根据您的规范实现 remove 方法的最佳方法。

    但是,也许您应该重新考虑规范。我会将 updateEvent 何时终止的决定留给实施者。使用 remove() 调用终止是令人困惑的,并且需要使用异常来进行流控制。我相信对 remove() 的调用应该只改变标志状态。而且我认为循环遍历所有对象并检查每个对象的已删除标志没有真正的问题。

    【讨论】:

    • 我也在想同样的事情。要求立即停止有异味的执行,而不是使用异常来完成。此外,即使有例外情况,您仍然受到客户的摆布。 updateEvent 实现可以轻松捕获异常而不重新抛出它,允许它们继续执行(如果他们选择)。
    【解决方案2】:

    @jball 的回答很棒——+1。

    我使用的另一种效果很好并且可能更简洁的方法是让您的 updateEvent() 方法返回一个布尔值。每当从 updateEvent 返回 True 时,您都会删除()该对象。

    这使您的事件循环可以更好地控制循环本身的执行方式,并消除类之间一些不必要的绑定。

    【讨论】:

      【解决方案3】:

      你为什么不干脆:

      • 在运行循环的对象中维护objectList
      • 不要让 GameObjects 访问列表(他们为什么要这样做?)
      • 让 updateEvent 函数返回一个布尔值。如果返回值为 false,则父对象从事件列表中删除该对象。 return 语句还用于终止事件函数的执行。

      【讨论】:

      • 我在运行循环的对象中维护对象列表,而 GameObjects 无法直接访问它。你的第三点听起来不错。我想我会这样做并使用迭代器的 remove 方法立即删除它们。比将它们全部存储在列表中并在最后修改它们更干净。
      【解决方案4】:

      为什么不简单地返回,即,

      public void updateEvent() { 
          //object's update event 
          remove(this); 
          return;   
          //obviously unreachable 
          System.out.println("Should never reach here!");     }
      

      【讨论】:

        猜你喜欢
        • 2016-03-29
        • 1970-01-01
        • 1970-01-01
        • 2011-12-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-01-12
        相关资源
        最近更新 更多