- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在 Java 平台上开发一个实时战略游戏克隆,我有一些概念性的问题关于放置在哪里以及如何管理游戏状态。游戏使用Swing/Java2D作为渲染。在目前的开发阶段,没有模拟,也没有人工智能,只有用户可以改变游戏的状态(例如, build /拆除建筑物、增减生产线、组装车队和设备)。因此,游戏状态操作可以在事件分派(dispatch)线程中执行,无需任何渲染查找。游戏状态还用于向用户显示各种聚合信息。
但是,由于我需要引入模拟(例如,建筑进度、人口变化、舰队移动、制造过程等),在 Timer 和 EDT 中更改游戏状态肯定会减慢渲染速度。
假设模拟/AI 操作每 500 毫秒执行一次,我使用 SwingWorker 进行大约 250 毫秒的计算。我如何确保在模拟和可能的用户交互之间没有关于游戏状态读取的竞争条件?
我知道模拟的结果(少量数据)可以通过 SwingUtilities.invokeLater() 调用有效地移回 EDT。
游戏状态模型似乎过于复杂以至于无法在所有地方使用不可变值类。
是否有相对正确的方法来消除这种读取竞争条件?也许在每个计时器滴答上进行完整/部分游戏状态克隆,或者将游戏状态的生存空间从 EDT 更改为其他线程?
更新:(来 self 给出的评论)该游戏由 13 名 AI 控制的玩家、1 名人类玩家运营,拥有约 10000 个游戏对象(行星、建筑物、设备、研究等)。例如,游戏对象具有以下属性:
World (Planets, Players, Fleets, ...)Planet (location, owner, population, type, map, buildings, taxation, allocation, ...)Building (location, enabled, energy, worker, health, ...)
In a scenario, the user builds a new building onto this planet. This is performed in EDT as the map and buildings collection needs to be changed. Parallel to this, a simulation is run on every 500ms to compute the energy allocation to the buildings on all game planets, which needs to traverse the buildings collection for statistics gathering. If the allocation is computed, it is submitted to the EDT and each building's energy field gets assigned.
Only human player interactions have this property, because the results of the AI computation are applied to the structures in EDT anyway.
In general, 75% of the object attributes are static and used only for rendering. The rest of it is changeable either via user interaction or simulation/AI decision. It is also ensured, that no new simulation/AI step is started until the previous one has written back all changes.
My objectives are:
Options:
All of these have advantages, disadvantages and causes to the model and the game.
Update 2: I'm talking about this game. My clone is here. The screenshots might help to imagine the rendering and data model interactions.
Update 3:
I'll try to give a small code sample for clarify my problem as it seems from the comments it is misunderstood:
List<GameObject> largeListOfGameObjects = ...
List<Building> preFilteredListOfBuildings = ...
// In EDT
public void onAddBuildingClicked() {
Building b = new Building(100 /* kW */);
largeListOfGameObjects.add(b);
preFilteredListOfBuildings.add(b);
}
// In EDT
public void paint(Graphics g) {
int y = 0;
for (Building b : preFilteredListOfBuildings) {
g.drawString(Integer.toString(b.powerAssigned), 0, y);
y += 20;
}
}
// In EDT
public void assignPowerTo(Building b, int amount) {
b.powerAssigned = amount;
}
// In simulation thread
public void distributePower() {
int sum = 0;
for (Building b : preFilteredListOfBuildings) {
sum += b.powerRequired;
}
final int alloc = sum / (preFilteredListOfBuildings.size() + 1);
for (final Building b : preFilteredListOfBuildings) {
SwingUtilities.invokeLater(=> assignPowerTo(b, alloc));
}
}
所以重叠是在 onAddBuildingClicked() 和 distributePower() 之间。现在想象一下,游戏模型的各个部分之间有 50 个这样的重叠。
最佳答案
这听起来像是可以从客户端/服务器方法中获益:
播放器是客户端 - 交互和渲染发生在这一端。所以玩家按下一个按钮,请求就会发送到服务器。服务器回复回来,玩家状态更新。在这些事情发生之间的任何时候,屏幕都可以重新绘制,它反射(reflect)了客户端当前知道的游戏状态。
人工智能同样是一个客户端——它相当于一个机器人。
模拟就是服务器。它在不同时间从其客户端获取更新并更新世界状态,然后适本地将这些更新发送给每个人。这是它与您的情况相关的地方:模拟/AI 需要一个静态世界,许多事情同时发生。服务器可以简单地排队更改请求并在将更新发送回客户端之前应用它们。因此,就服务器而言,游戏世界实际上并没有实时变化,它会在服务器决定实时变化时发生变化。
最后,在客户端,您可以通过进行一些快速的近似计算并显示结果(满足即时需求),然后在按下按钮时显示更正确的结果,从而避免按下按钮和看到结果之间的延迟服务器开始与您交谈。
请注意,这实际上不必以互联网上的 TCP/IP 方式实现,只是有助于从这些方面考虑它。
或者,您可以将在模拟期间保持数据一致性的责任放在数据库上,因为它们在构建时已经考虑到了锁定和一致性。 sqlite 之类的东西可以作为非联网解决方案的一部分。
关于java - 面对 EDT 如何管理游戏状态?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/981920/
只是想一想我的一些重复代码: Runnable run = new Runnable() { @Override public void run() { // Some EDT cod
我在 Java 库中使用一个 API,它从事件分派(dispatch)线程调用并要求我返回一个完全初始化的 UI 组件。它看起来像这样: public JDialog createDialog()
我有一个在 EDT 上运行的方法,我想让它在一个新的(非 EDT)线程上执行一些事情。我当前的代码如下: @Override public void actionPerformed(Actio
我有以下测试方法: @Test public void f3KeystrokeShowsHotkeysDialog() throws AWTException{ App app = new A
我正在开发一个项目,该项目需要进行一些密集的数学计算(矩阵、 vector 数组等),因此我很自然地将工作分成多个作业,并将它们提交给 CompletionService 以并行执行工作. 每个作业对
所以我对 MVC 结构还很陌生。我真的很困惑何时何地在 EDT 上添加我的 Gui 部分。这是我真正困惑的地方: public class ECPS_MVC { //edt? Ecps
如果从 EDT 线程调用某些方法出现未经检查的异常,会发生什么情况?它能保持 GUI 的响应能力还是什么?谢谢您 最佳答案 Before restarting, does the EDT shutdo
我对了解 Swing 乐和 EDT 的追求再次继续...... 由于 EDT 是唯一的 EDT,所以我现在想知道哪些方法、构造函数和任何其他内容应该在 EDT 中完成。我知道一般规则,几乎所有创建 S
该示例不断绘制各种颜色的方 block 。方 block 的数量取决于 JFrame 的大小。 在执行示例时,使用鼠标放大或缩小尺寸框,将会增加或减少可见闪烁方 block 的数量。 该帧的时间栏显示
我按照别人告诉我的方式处理我的游戏循环,添加了 Swing 计时器等(除了重写paintComponent,因为它在这种情况下不适用),但我的游戏循环拒绝调用事件调度线程。因此,JFrame 不会关闭
正如我在 earlier post 上与 Inerdia 讨论的那样, 事情仍然很奇怪当我在一些 JPanel 中(肯定是 EDT - 我用方法检查进行了检查)然后我调用一些动画线程(线程扩展线程)来
我想创建新线程(用于服务器)。我有 textArea 来放置日志,我创建了一个新的类状态来处理它。我为对象“服务器”运行新线程,尝试将状态对象“传递”到服务器,并且执行 status.setStatu
我正在用 Java 编写 Sugarscape 模拟,需要一个工作的 GUI。 Sugarscape 是一种空间景观,由(糖的)瓷砖和移动和消耗糖的代理组成。为简单起见,我只有一个代理,没有糖——我只
如何知道 EDT 被阻塞(不是直观地而是通过检查线程本身)?有办法吗? 我正在完成最后的大学毕业任务,其中有一堆图表,但对 Swing EDT(通常是 Java)知之甚少。 看看这篇文章: Swin
我一直在问很多关于我最近正在进行的项目的问题。这是我所处的场景,任何帮助或指出正确方向都会有很大帮助...... 这是一个由一个服务器和多个客户端构建的网络程序。每个客户端都有一个 GUI,它必须根据
我有一个在 EDT 内执行的方法。事情是这样的: myMethod() { System.out.prinln(SwingUtilities.isEventDispatchThread());
我正在尝试学习 Swing 的复杂性,并且已经阅读了大量有关事件调度线程的内容。我明白这是为了什么,但是我正在为以下概念而苦苦挣扎: 我有一个以正常方式调用的 JFrame: public cla
我想知道 Java 中的事件调度线程何时启动。 它是主线程,还是在Window/Frame构造函数中启动? 如果检测到 AWT/Swing 的使用,是否由 JVM 启动? 最佳答案 主线程不是 EDT
我认为提出问题的最简单方法是逐步解决问题。我对 EDT 的某些工作原理有些困惑。 是否有任何对象是从在 EDT 上创建的 Swing 组件创建的? 要扩展这个问题,如果我创建一个 JFrame,并在其
嗨,我想在 EDT 之外完成一项任务: new Thread(new Runnable(){ @Override public void
我是一名优秀的程序员,十分优秀!