为Unity构建一个简单的在线游戏服务器

8
我正在尝试为我的坦克2D游戏(Unity)构建在线游戏服务器。在我的游戏中,会有2-4个玩家控制他们的坦克并互相对抗。
我已经尝试过使用Unity网络功能,但它并不适合我的游戏,因为我们必须选择房间中的一个玩家成为“服务器”,这对于我的未来开发并不够灵活(例如,当“服务器”退出时,我必须做很多工作来保持其他玩家之间的连接)。
然后,我尝试使用Nodejs加socket.io构建自己的服务器进行服务器-客户端通信。这非常简单:从一个客户端接收数据并广播到其他客户端。看起来一切都很正常,直到物理部分出现问题:当客户端报告某些东西被击中或爆炸时,服务器必须信任客户端,并将其广播给其他客户端。更不用说那些作弊的客户端了,由于网络延迟,客户端的物理模拟将有所不同。例如,坦克在一个客户端上可能被击中,但在另一个客户端上却找了个墙角躲了起来,还活着,但在它身后的坦克却被子弹打中并爆炸了,这是由于延迟引起的。在这种情况下,服务器不知道应该听谁的。
更新:
正如@Catwood在下面提到的,Photon PUN对我来说是另一个选择。我之前已经按照他们的教程进行了一些尝试。Photon不需要像Unity网络那样选择一个玩家作为“服务器”。但是,我该如何在服务器上实现我的游戏逻辑?(用于权威服务器)
显然,Smartfoxserver是另一个好的(而且价格高昂的)选择。我还没有深入研究过它们的API文档。我不知道我是否可以在上面实现我的游戏逻辑和规则(他们的教程为简单起见跳过了这个部分)。
总之,我需要建议我的游戏服务器:
- 是权威服务器 - 可以处理游戏规则并决定会发生什么(也许它应该有自己的物理引擎) - 与Unity2D良好兼容 - 最好使用Javascript,C#,Java!
我是否走在正确的方向上,因为似乎某些游戏服务器服务(例如Photon、Unity网络)并不关心如何在服务器上实现游戏逻辑?这是否使它们不成为权威服务器?
我对这个领域非常陌生,任何建议都将不胜感激!
2个回答

23
我建议您像使用NodeJS一样为游戏创建自己的服务器。我知道的大多数解决方案都相当难以使用,并且不能实现您想要的所有功能。 例如,暴雪公司的炉石传说是基于Unity客户端和自定义服务器端制作的。
以下是有关如何创建游戏服务器的建议:
似乎在物理部分开始时它能正常工作:当客户端表示有东西被击中或爆炸时,服务器必须信任客户端,然后将其广播给其他客户端。 在创建服务器时,您必须在服务器端而不是客户端做出所有重要决策。 服务器启动派对,因此服务器必须具有以下信息:
地图大小 玩家数量 每个玩家的数据(血量、位置、大小、攻击速度等) 进行决策所需的任何其他信息
现在,客户端应始终向服务器发送非常小的信号,例如:
左移 加入派对 射击 向右旋转 等等...
基于用户的操作和用户数据,服务器可以运行游戏的“模拟”。
检查操作是否允许 如果允许,则模拟操作。如果不允许,则将其放入队列中 向用户发送有关正在发生的事情的信息(玩家一击中、玩家二死亡、玩家四向左移动等)
通过这种方式,服务器知道何时发生某事并决定发生什么。您不依赖于客户端信息,您只接收玩家的所需操作。
但是,由于延迟和其他网络因素,您的客户端不能过于依赖服务器。在现代游戏中,客户端具有与服务器相同的有关玩家的数据,并且不总是依赖服务器来显示屏幕上正在发生的事情。
如果您玩过一些在线游戏,您可能已经注意到当与服务器的连接丢失时,有一个小的时间段,您可以继续玩(移动、射击等),但除您外没有任何移动。 这是因为客户端即使没有服务器的信息,也会根据您的操作“运行”游戏。
但是,为了避免客户端向玩家显示的内容与服务器模拟的内容之间存在巨大差异,客户端和服务器定期进行“同步”。
例如,如果您决定向左移动,则客户端知道您的移动速度,因此可以显示移动而无需依赖服务器。
当同步发生时,服务器向客户端发送关键信息,客户端使用服务器发送的任何当前显示信息进行更改。
使用左移示例,如果服务器和客户端上的移动速度不同,则当客户端接收到同步命令时,您将注意到您的玩家从显示位置“传送”到另一个位置。如果某些数据包丢失或由于延迟过高而发生,也可能发生这种情况。
在创建在线游戏时,处理延迟是一个巨大的挑战,无论在服务器端还是在客户端。但这不是本问题的主题。
总之,您的服务器应该:
自制 仅接收来自客户端的操作 模拟游戏 向客户端发送有关正在发生的内容的信息 定期与客户端进行同步
希望这可以帮助=)
以下是有关如何在服务器内添加逻辑的说明。 先说一个小免责声明,我从未使用过NodeJS,因此不知道是否可以使用NodeJS实现此操作,我通常使用C++。
现在针对您的游
map_width = 512;
map_height = 512;
user_width = 2;
user_height = 2;
user_speed = 1;
user_posx = 20;  
user_posy = 20;

当客户端想要移动时,他会向服务器发送一个包,表明他想要移动。你可以使用任何你想要的客户端<->服务器通信协议,我使用二进制协议,但是假设你使用Json。

{action: move; value: left};

这样,你的服务器将会知道用户想要向左移动。因此,你只需要在服务器端将user_posx 减去 user_speed 的值,就可以得到新的位置。如果这个位置位于地图边缘,你有两种选择,一是让用户出现在地图的另一侧,二是禁止这个操作。

定期地,你的服务器将向客户端发送玩家当前的位置。


1
@FlySoFast 嗯,这并不难,但主要取决于你的游戏在做什么。我会编辑我的答案,以添加一些精确信息。 - Gary Olsson
1
@FlySoFast,你的服务器内部不一定需要物理引擎。因为你不需要让服务器完美模拟游戏。"弹开"很简单,因为它只是一个与射击方向相反的移动。现在对于"反弹",如果你不想计算它,那就不要计算。让客户端在反弹后将其位置发送给你。你的服务器只需要检查它是否在某个反弹限制范围内。如果是,服务器接受客户端的新位置。你不需要对游戏的每个方面都有完全的控制权。 - Gary Olsson
我正在我的服务器上实现ODE(一个开源物理引擎)。我认为,如果它们具有相同的输入,所有物理引擎都会以相同的方式运行,因为它们共享相同的物理定律,对吧? - FlySoFast
1
在理想的世界中是这样,但实际上并非如此。每个物理引擎都试图模拟“真实物理”,但由于它太耗费CPU,每个物理引擎都包含自己的近似值。有些比其他的好。这里有一个例子http://media.giphy.com/media/o9awDl6tjqBvG/giphy.gif。然而,由于2D物理比3D物理更简单,你应该得到类似的结果。以防万一,你应该包括一个误差范围。 - Gary Olsson
1
@DavidDimalanta 这要看你的游戏以及客户端和服务器通信的重要性。通常来说,最好让服务器24/7在线。然而,如果你的服务器仅用于排行榜或其他非必要功能,则可以定期关闭而不会对玩家产生影响。确保你的客户端在停机期间表现“正常”。频繁显示像“连接超时”这样的错误会让人感到非常烦恼。 - Gary Olsson
显示剩余5条评论

3

在资产商店上有一个名为Photon的资产,它是一种权威服务器。对于非移动设备,它也是免费的。这将确保处理您问题的第一部分。

这个很棒的教程会对您有所帮助。


1
请记住,Photon有20个并发用户的限制。 目前还有ulink,但需要购买许可证,但相比Photon,它的教程更容易。然后还有Dark Rift,它也是免费的,但它有与Photon相同的20个并发用户限制。ulink:http://developer.muchdifferent.com/unitypark/Downloadsdark rift:https://www.assetstore.unity3d.com/en/#!/content/16711 - killer_mech
1
是的,但Ulink没有它,你可以使用它进行测试,因为它是评估副本,但在发布之前,你需要获得许可。实际上,我还没有找到任何真正免费的多人游戏插件;虽然Dark Rift提供了50美元的插件Dark Rift Pro,适用于200个并发用户。 Dark Rift Pro:https://www.assetstore.unity3d.com/en/#!/content/16712 然后他们有一个650美元的版本,适用于无限并发用户。 - killer_mech
@killer_mech "请记住,Photon有20个并发用户的限制" - 这取决于您选择的版本。免费版是20个; 它们还有100个,500个和1000个CCU版本。 - user585968
@Catwood 你有使用它的经验吗?我已经更新了我的答案,提供更多信息。 - FlySoFast
@FlySoFast 我会一点,但没有做过大型项目。我发现它很容易上手,跟使用 Unity 网络编程没什么区别。 - Catwood
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接