Q&A
Q:有没有一种 Java 硬编码方式可以在战斗中获得对任何飞船的控制权?效果就像开发模式中的 Ctrl + LMB。
A:CombatEngineAPI.setPlayerShipExternal(ShipAPI ship) should do it, I think?
Q:使用 CombatEngineAPI.addPlugin 方法为战斗添加多个 BaseEveryFrameCombatPlugin 子类时,所有 advance() 的执行是单线程还是多线程?如何确定所有 advance() 的执行顺序?还是无法确定 advancce() 的执行顺序?
如果我有一个 TestPlugin 对象(BaseEveryFrameCombatPlugin 的子类),并在战斗的第 n 帧调用 addPlugin(TestPlugin),那么 TestPlugin 的 advance() 是在第 n 帧开始执行,还是在第 n + 1 帧开始执行?如果我在战斗的第 m 帧删除插件(TestPlugin),TestPlugin 的 advance() 是否仍会在第 m 帧执行?
A:It's all single-threaded.
The order of the advance() calls will generally be in the order the the plugins were added, but your code should probably not rely on that.
It depends on when you call addPlugin(). If you call it from advance(), it'll start executing on the next frame. If you remove the plugin from another plugin's advance() method, it may still execute during the current frame, iirc.
Q:这是否意味着,如果我想严格按照一定顺序执行代码,就必须将代码放在相同的 advance() 中?
A:That seems broadly correct.
Q:我的理解是否正确,假设存在动态流水线,那么该帧应该执行什么任务,该帧有什么状态,这些都是在该帧开始时确定的(深度拷贝),而且这个拷贝是不可变的。
例如,本帧 addPlugin(TestPlugin) 将 TestPlugin.advance() 添加到动态流水线,在下一帧开始之前,它会读取流水线并创建其副本,它要执行的任务包括 TestPlugin.advance()。反之,removePlugin(TestPlugin) 将删除管道中的 TestPlugin.advance()。显然,在下一帧开始前读取管道时,会创建一个副本,它将执行的任务中不会包含 TestPlugin.progress()。
我为什么会做出这样的假设?因为当我在同一帧中对同一个 ShipAPI 对象调用 giveCommand(ShipCommand.SELECT_GROUP, null, index),然后调用 getSelectedGroupAPI() 时,我发现得到的 WeaponGroupAPI 并不是索引武器组。获得索引武器组的唯一方法是在下一帧中调用 getSelectedGroupAPI()。因此我假设 giveCommand(ShipCommand.SELECT_GROUP, null, index) 改变的是动态管道的状态,而不是本帧的状态。getSelectedGroupAPI() 所获取的 WeaponGroupAPI 并不是动态流水线的全局状态,而是本帧开始前确定的 WeaponGroupAPI 的深度副本。
A:No, that's not how it works. For plugins, the iteration where their .advance() method is called happens over a copy of the list of plugins, but that's not a copy of the entire state. This is done fairly often to enable deletion from the list that's being iterated over. (There are also other ways to do this, of course.)
For ship commands, a command given to the ship will be carried out in the ship's advance() method, so until that runs, you wouldn't see the effect of the command, but the command is queued up immediately.
Edit: it's worth noting that a ship's AI runs before the ship's advance() method, so any commands the AI gives will be executed on the same frame. But plugins run after all the entities have run their advance().
Q:当我调用 addPlugin 添加一个 TestPlugin 对象,然后调用 removePlugin 时,removePlugin 的参数是否需要是同一个 TestPlugin 对象,还是需要创建一个 TestPlugin 对象?
换一种说法,CombatEngineAPI 是否允许存在多个同类插件对象,或者 addPlugin 和 removePlugin 是否类似于单例(可能使用 instanceof 来确保只有一个同类插件对象)?
A:yeah, multiple plugins of the same type can be attached to the combat engine; removePlugin takes the specific plugin object that you want to remove as its param
Q:在同一帧内处理命令的顺序:
1. 接收玩家下达的命令
2. 接收 AIPlugin 下达的命令
3. 玩家的飞船在 advance() 处理来自 step 1 的命令
4. 所有实体在各自的 advance() 中处理来自 step 2 和 step 5 的命令
5. 接收 BaseEveryFrameCombatPlugin 的子类下达的命令
可以在当前帧看到 setp 1 和 step 2 命令的效果,不能在当前帧立刻看到插件给出的命令的效果,但命令会立刻排队等候
这顺序是否有错误?我是否遗漏了什么重要的步骤?或者有更细分的步骤?
A:This sounds right, though I have to be honest, I did not dig into it and it's not something that's permanently at the top of my mind - usually it's not something I need to think about because things "just work", if that makes sense.
One thing that throws a wrench into this is fast-time - when non-player ships have their time sped up (e.g. phase cloak), steps 2 and 4 will happen multiple times per frame for those ships.
Q:与时间流速相关的系统:Phase Cloak 和 Temporal Shell,它们的工作原理是一样的吗?
非玩家的飞船使用系统时,是在一帧内执行更多命令,达到加速时间的功能,相当于玩家飞船在一帧时间内只有一个回合行动,而非玩家的飞船能在一帧时间内有多个回合行动
那玩家的飞船呢?
玩家使用系统时,玩家飞船的时间流速是不变的,而外界的所有实体的时间流速都变慢了。底层原理是什么?
我猜测,玩家飞船在一帧时间内,以行动多个回合(假设玩家飞船一帧行动两回合),此时玩家飞船是两倍速,但这还不够,因为玩家会难以适应加速操作。此时将战斗引擎以反比例来降低时间流速(战斗引擎将以0.5倍速进行),这样能使玩家以一倍速来进行战斗,同时外界的时间是0.5倍速。这样就等价于玩家变快了两倍速
A:Phase Cloak and Temporal Shell work the same way.
I don't remember all the details for how it works with the player ship. You can test a lot of this fairly easily by providing an AI plugin implementation for the player's autopilot.
One thing to keep in mind is that you can only get one set of inputs per frame from the player, so those commands persist through all of the fast-time frames, except for a few which are toggles (and which would undo each other if repeated multiple times, such as raising shields or turning the cloak on and off).
Q:在 step 3 / step 4,当游戏检测到暂停(isPause() 返回 true),是不是只接收指令,但不执行(丢弃每帧接收的指令),直到 isPause() 返回 false。
A:It'll process some commands like toggling autofire while paused, which is something you could test. Other commands, IIRC just won't get queued up at all while the game is paused. I'm curious, what are you doing that all this stuff actually matters?
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战