为 Unity 构建一个简单的在线游戏服务器
Building a simple online game server for Unity
我正在尝试为我的 Tank 游戏 2D (Unity) 构建在线游戏服务器。在我的游戏中会有2-4个玩家控制他们的坦克并互相战斗。
我尝试过使用Unity网络,它不太适合我的游戏,因为我们必须选择房间中的一名玩家成为“服务器”,这不是真的对我未来的发展具有灵活性(例如,当“服务器”退出时,我必须做很多工作才能与其他玩家保持联系)。
然后我尝试使用 Nodejs là socket.io 构建自己的服务器以进行服务器-客户端通信。这很简单:从一个接收数据并将它们广播给其他。在物理部分出现之前,它似乎工作正常:当客户端说有东西被击中或爆炸时,服务器必须信任客户端,然后将其广播给其他客户端。更不用说被骗的客户端了,随着网络延迟的增加,客户端的物理模拟也会有所不同。例如,一辆坦克可能击中了这个客户端,但它应该被另一个客户端覆盖在墙后并保持活力,但由于延迟,他身后的坦克抓住了子弹并爆炸了。在这些情况下,服务器不知道该听哪一个。
更新
- 正如下面提到的@Catwood,Photon PUN 是我的另一个选择。我
以前听过他们的一个教程。 Photon 不像 Unity 网络那样需要播放器作为“服务器”。但是如何在服务器上实现我的游戏逻辑呢? (用于权威服务器目的)
- 显然 Smartfoxserver 是另一个不错(而且价格昂贵)的选择。我没有深入研究他们的 API 文档。我不知道我是否可以在此实现我的游戏逻辑和规则(他们的教程为了简单起见跳过这部分)。
总之,我需要一个关于我的游戏服务器的建议:
- 是权威服务器
- 可以处理游戏规则并决定会发生什么(也许应该有自己的物理引擎)
- 与 Unity2D 配合良好
- Java脚本,C#,Java是首选!
我的方向是否正确,因为某些游戏服务器服务(例如 Photon、Unity 网络)似乎并不关心如何在服务器上实现游戏逻辑。这是否使他们不是权威服务器?
我是这个领域的新手,我们将不胜感激!
资产商店中有一个名为 Photon 的资产,它是一个权威服务器。它对非移动设备也是免费的。这肯定会处理您问题的第一部分。
这个很棒的 Tutorial 会有所帮助。
我建议像使用 NodeJS 一样为您的游戏创建自己的服务器。我知道的大多数解决方案都很难使用,不能做你想做的一切。
例如,暴雪游戏的《炉石传说》客户端是基于Unity的,并且有一个定制的服务器端。
这里有一些关于如何创建游戏服务器的建议。
It seems to work fine until the physics part comes in: the server must trust the clients when they say there's something being hit or explode, then broadcasts it to the other clients.
在创建服务器时,您必须在服务器端而不是客户端做出每一个重要的决定。
开派对的是服务器,所以服务器必须有以下信息
- 地图的大小
- 玩家人数
- 每个玩家的数据(生命值、位置、体型、攻击速度...)
- 做出决定所需的任何其他信息
现在,客户端应该总是向服务器发送非常小的信号,如下所示
- 向左移动
- 加入队伍
- 射击
- 向右旋转
- 等...
根据用户的操作和用户的数据,服务器可以运行一个"simulation"的游戏。
- 检查是否允许该操作
- 如果允许,模拟动作。如果不是,将其放入队列
- 向用户发送有关正在发生的事情的信息(玩家一击、玩家二死、玩家四向左移动等等)
有了这个,服务器知道什么时候发生了什么事情并决定发生什么。您不依赖客户端信息,您只接收玩家所需的操作。
但是,正如您所说,由于延迟和其他网络因素,您的客户端不能过于依赖服务器。在现代游戏中,客户端与服务器拥有相同的玩家数据,并不总是依赖服务器在屏幕上显示正在发生的事情。
如果您玩过一些在线游戏,您可能已经注意到,当与服务器的连接断开时,您可以在一小段时间内继续玩游戏(移动、射击等),但什么都没有除了你。
这是因为即使没有服务器的信息,客户端也会根据您的操作继续"run"游戏。
但是,为了避免客户端向玩家显示的内容与服务器模拟中发生的内容之间存在巨大差异,客户端和服务器会定期 "synchronize"。
例如,如果您决定向左移动,客户端就会知道您的移动速度,因此它可以在不依赖服务器的情况下显示移动。
同步发生时,服务器向客户端发送关键信息,客户端用服务器发送的信息更改当前显示的任何信息。
以左边的移动为例,如果你的移动速度在服务器端和客户端不同,当客户端收到同步命令时,你会发现你的播放器会"teleported"从显示位置到另一个。如果某些数据包丢失或由于高延迟,也会发生这种情况。
在服务器端和客户端创建在线游戏时,处理延迟是一个巨大的挑战,这不是这个问题的主题。
总而言之,您的服务器应该
- 自制
- 仅接收来自客户的操作
- 模拟游戏
- 向客户发送有关正在发生的事情的信息
- 定期与客户端同步
希望对您有所帮助 =)
以下是有关如何在服务器中添加逻辑的一些说明。
之前的小免责声明,我从未使用过 NodeJS,所以我不知道使用 NodeJS 是否可以实现,我通常使用 C++。
现在对于您的游戏,我假设玩家只能使用动作 MOVE。
当用户连接到您的服务器时,您可以启动游戏。
因为你的用户可以移动,这意味着有一个 2D 地图,你的用户有一个大小、一个初始位置和一个速度。
所以你的服务器应该启动一个新的 "GameParty" 并初始化上面的数据。
例如,假设设置了以下默认值。
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
即可在服务器端获得您的新位置。如果这个位置在地图的边缘,你有两个选择,让用户出现在地图的另一边或者禁止这个动作。
每隔一段时间,您的服务器会向客户端发送玩家的当前位置。
我正在尝试为我的 Tank 游戏 2D (Unity) 构建在线游戏服务器。在我的游戏中会有2-4个玩家控制他们的坦克并互相战斗。
我尝试过使用Unity网络,它不太适合我的游戏,因为我们必须选择房间中的一名玩家成为“服务器”,这不是真的对我未来的发展具有灵活性(例如,当“服务器”退出时,我必须做很多工作才能与其他玩家保持联系)。
然后我尝试使用 Nodejs là socket.io 构建自己的服务器以进行服务器-客户端通信。这很简单:从一个接收数据并将它们广播给其他。在物理部分出现之前,它似乎工作正常:当客户端说有东西被击中或爆炸时,服务器必须信任客户端,然后将其广播给其他客户端。更不用说被骗的客户端了,随着网络延迟的增加,客户端的物理模拟也会有所不同。例如,一辆坦克可能击中了这个客户端,但它应该被另一个客户端覆盖在墙后并保持活力,但由于延迟,他身后的坦克抓住了子弹并爆炸了。在这些情况下,服务器不知道该听哪一个。
更新
- 正如下面提到的@Catwood,Photon PUN 是我的另一个选择。我 以前听过他们的一个教程。 Photon 不像 Unity 网络那样需要播放器作为“服务器”。但是如何在服务器上实现我的游戏逻辑呢? (用于权威服务器目的)
- 显然 Smartfoxserver 是另一个不错(而且价格昂贵)的选择。我没有深入研究他们的 API 文档。我不知道我是否可以在此实现我的游戏逻辑和规则(他们的教程为了简单起见跳过这部分)。
总之,我需要一个关于我的游戏服务器的建议:
- 是权威服务器
- 可以处理游戏规则并决定会发生什么(也许应该有自己的物理引擎)
- 与 Unity2D 配合良好
- Java脚本,C#,Java是首选!
我的方向是否正确,因为某些游戏服务器服务(例如 Photon、Unity 网络)似乎并不关心如何在服务器上实现游戏逻辑。这是否使他们不是权威服务器?
我是这个领域的新手,我们将不胜感激!
资产商店中有一个名为 Photon 的资产,它是一个权威服务器。它对非移动设备也是免费的。这肯定会处理您问题的第一部分。
这个很棒的 Tutorial 会有所帮助。
我建议像使用 NodeJS 一样为您的游戏创建自己的服务器。我知道的大多数解决方案都很难使用,不能做你想做的一切。
例如,暴雪游戏的《炉石传说》客户端是基于Unity的,并且有一个定制的服务器端。
这里有一些关于如何创建游戏服务器的建议。
It seems to work fine until the physics part comes in: the server must trust the clients when they say there's something being hit or explode, then broadcasts it to the other clients.
在创建服务器时,您必须在服务器端而不是客户端做出每一个重要的决定。 开派对的是服务器,所以服务器必须有以下信息
- 地图的大小
- 玩家人数
- 每个玩家的数据(生命值、位置、体型、攻击速度...)
- 做出决定所需的任何其他信息
现在,客户端应该总是向服务器发送非常小的信号,如下所示
- 向左移动
- 加入队伍
- 射击
- 向右旋转
- 等...
根据用户的操作和用户的数据,服务器可以运行一个"simulation"的游戏。
- 检查是否允许该操作
- 如果允许,模拟动作。如果不是,将其放入队列
- 向用户发送有关正在发生的事情的信息(玩家一击、玩家二死、玩家四向左移动等等)
有了这个,服务器知道什么时候发生了什么事情并决定发生什么。您不依赖客户端信息,您只接收玩家所需的操作。
但是,正如您所说,由于延迟和其他网络因素,您的客户端不能过于依赖服务器。在现代游戏中,客户端与服务器拥有相同的玩家数据,并不总是依赖服务器在屏幕上显示正在发生的事情。
如果您玩过一些在线游戏,您可能已经注意到,当与服务器的连接断开时,您可以在一小段时间内继续玩游戏(移动、射击等),但什么都没有除了你。 这是因为即使没有服务器的信息,客户端也会根据您的操作继续"run"游戏。
但是,为了避免客户端向玩家显示的内容与服务器模拟中发生的内容之间存在巨大差异,客户端和服务器会定期 "synchronize"。
例如,如果您决定向左移动,客户端就会知道您的移动速度,因此它可以在不依赖服务器的情况下显示移动。
同步发生时,服务器向客户端发送关键信息,客户端用服务器发送的信息更改当前显示的任何信息。
以左边的移动为例,如果你的移动速度在服务器端和客户端不同,当客户端收到同步命令时,你会发现你的播放器会"teleported"从显示位置到另一个。如果某些数据包丢失或由于高延迟,也会发生这种情况。
在服务器端和客户端创建在线游戏时,处理延迟是一个巨大的挑战,这不是这个问题的主题。
总而言之,您的服务器应该
- 自制
- 仅接收来自客户的操作
- 模拟游戏
- 向客户发送有关正在发生的事情的信息
- 定期与客户端同步
希望对您有所帮助 =)
以下是有关如何在服务器中添加逻辑的一些说明。 之前的小免责声明,我从未使用过 NodeJS,所以我不知道使用 NodeJS 是否可以实现,我通常使用 C++。
现在对于您的游戏,我假设玩家只能使用动作 MOVE。
当用户连接到您的服务器时,您可以启动游戏。 因为你的用户可以移动,这意味着有一个 2D 地图,你的用户有一个大小、一个初始位置和一个速度。 所以你的服务器应该启动一个新的 "GameParty" 并初始化上面的数据。 例如,假设设置了以下默认值。
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
即可在服务器端获得您的新位置。如果这个位置在地图的边缘,你有两个选择,让用户出现在地图的另一边或者禁止这个动作。
每隔一段时间,您的服务器会向客户端发送玩家的当前位置。