在使用浮点运算的多人 RTS 游戏中保持同步
我正在用 C# 编写 2D 太空 RTS 游戏。单人游戏有效。现在我想添加一些多人游戏功能。我在谷歌上搜索了它,似乎只有一种方法可以在没有强大网络连接的情况下让数千个单位连续移动:仅通过网络发送命令,同时在每个玩家上运行相同的模拟。
现在有一个问题,整个引擎到处都使用双精度数。浮点计算在很大程度上取决于编译器优化和 CPU 架构,因此很难保持同步。 它根本不是基于网格的,并且有一个简单的物理引擎来移动太空飞船(太空飞船具有冲量和角动量......)。因此,重新编码整个内容以使用定点将非常麻烦(但可能是唯一的解决方案)。
所以到目前为止我有 2 个选择:
- 告别当前代码并使用整数从头开始重新启动
- 游戏 LAN 仅在有足够带宽容纳 8 个拥有数千个单位的玩家的地方,并在(几乎)每个时间发送位置和方向等框架...
所以我寻找更好的意见,(甚至是关于将代码迁移到定点而不弄乱一切的技巧...)
I'm writing a 2D space RTS game in C#. Single player works. Now I want to add some multiplayer functionality. I googled for it and it seems there is only one way to have thousands of units continuously moving without a powerful net connection: send only the commands through the network while running the same simulation at every player.
And now there is a problem the entire engine uses doubles everywhere. And floating point calculations are depends heavily on compiler optimalizations and cpu architecture so it is very hard to keep things syncronized.
And it is not grid based at all, and have a simple phisics engine to move the space-ships (space ships have impulse and angular-momentum...). So recoding the entire stuff to use fixed point would be quite cumbersome (but probably the only solution).
So I have 2 options so far:
- Say bye to the current code and restart from scratch using integers
- Make the game LAN only where there is enough bandwidth to have 8 players with thousands of units and sending the positions and orientation etc in (almost) every frame...
So I looking for better opinions, (or even tips on migrating the code to fixed-point without messing everything up...)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
当然,您的所有客户端都将使用相同的二进制文件,因此编译器优化对同步问题没有影响。
另外,如果您只计划针对一种架构(或者至少只允许人们在同一架构上相互对战),那么这也没关系。
我在 C# 中使用浮点为 iPhone 和桌面开发游戏,做了完全相同的事情,它们都给出了相同的结果,即使 iPhone 是 ARM 而桌面是 x86。
只要确保游戏执行完全相同相同的计算就可以了。
如果所有其他方法都失败,只需将游戏中的所有
float
实例替换为标准定点算术类。这样,您就可以 100% 确定您的计算在各个架构中都是确定性的,尽管定点算术的性质可能会对您的游戏产生不利影响。Surely all your client will be using the same binary, so compiler optimisations have no effect on synchronisation issues.
Also, if you are only planning on targeting one architecture (or are at least only allowing people to play against each other if they are on the same architecture) then that doesn't matter either.
I've done exactly the same thing using floating points in C# developing games for the iPhone and desktop, and they both give the same results, even though the iPhone is ARM and desktop is x86.
Just make sure the game does exactly the same calculations and you will be fine.
If all else fails, just replace all instances of
float
in your game to a standard fixed-point arithmetic class. That way you can be 100% sure that your calculations are deterministic across architectures, although the nature of fixed-point arithmetic may adversely effect your game.我对此的回应有点晚了,但从游戏安全的角度来看,模拟应该只在服务器/主机上运行(即:不要信任客户端,他们可能会作弊):
客户端应该只将他们的动作/命令发送到服务器(服务器会丢弃错误的输入或将它们限制在游戏限制内,因此客户端说“我以 10,000m/s 运行”会被服务器限制为 10m/s)。客户
服务器/主机只告诉客户端在他们的视野内发生的事情(即:坐标为 0,0 的玩家不会被告知两个 AI 在 200,0 处互相战斗,如果他只能看到)他/她周围 50 个单位的半径)。
第二部分节省了带宽——服务器/主机上的模拟可能有数千个对象需要管理,但客户端只需要了解自己视野内的大约 100 或 200 个对象。
这种情况唯一的问题是动态射击(子弹、导弹等),其射程可能大于客户的视野半径。服务器/主机告诉客户端他们的起源和初始轨迹/目标对象,然后客户端根据相同的规则模拟他们的路径,但杀戮仅在服务器/主机上的模拟中有效。
序列化特定于客户端的世界状态并在传输之前对其进行压缩也可能是一个巨大的胜利,特别是如果您的类属性仅在需要时是公共的。 (我通常会避免使用 XML,但我们通过序列化为 XML 并压缩它,而不是序列化为二进制格式并压缩它,显着提高了一个应用程序的压缩率。我怀疑所使用的 ASCII 字符的有限范围对此有影响,YMMV。)
I'm a little late responding to this, but from a Game Security point of view the simulation should only be running on the server/host (i.e.: don't trust the clients, they could be cheating):
The clients should only be sending their movements/commands to the server (which discards bad inputs or clamps them within game limits, so a client saying "I'm running at 10,000m/s" gets clamped by the server to say 10m/s).
The server/host only tells clients about things happening within their field of view (i.e.: a player at co-ordinates 0,0 doesn't get told about two AIs fighting each other at 200,0 if he can only see a radius of 50 units around him/herself).
It's the second part that saves the bandwidth - the simulation on the server/host may have thousands of objects to manage but the clients only need to know about 100 or 200 things within their own field of view.
The only wrinkle in the situation is things like dynamic fire (bullets, missiles, etc) whose range may be greater than a client's view radius. The server/host tells the clients their origin and initial trajectory/target object, the clients then simulate their path according to the same rules, but the kills are only valid in the simulation on the server/host.
Serializing the client-specific world state and compressing it before transmission can also be a huge win, especially if your class properties are only Public where needed. (I normally avoid XML, but we significantly improved compression ratios in one application by serializing to XML and compressing it versus serializing to a binary format and compressing that. I suspect the limited range of ASCII characters used had a hand in it, YMMV.)
一种常见的技术是让所有客户端定期向其他客户端描述其当前状态。
当两台计算机对某个对象的状态不一致时(可能是由于浮点错误),游戏会使用一些规则来确定哪个是正确的,并且所有客户端都会进行调整以匹配它。
A common technique is to have all clients describe their current state to the other clients, periodically.
When two computers disagree about the state of an object, presumably due to floating point error, the game has some rule to determine which is correct, and all clients adjust to match it.
您使用双打的具体用途是什么?你能用十进制代替吗?
一般来说,服务器会存储所有玩家单位的状态(位置/方向/类型)。
当玩家 1 移动一个单位时
要么...移动指令被发送到服务器
或者...更新后的状态被发送到服务器
当玩家客户端需要渲染场景时,服务器会发回有关请求范围内所有单元位置的状态信息。
What are you using doubles for specifically? Could you use decimal instead?
Generaly the server would store the state(position/oriantaion/type) of all players units.
When player1 moves a unit
either... the instuction to move is sent to the server
or... the updated state is sent to the server
When the player client needs to render the scene the server sends back state info on the location of all the units within a requested scope.