Skip to content

Making multiplayer games with GDevelop

危险

GDevelop多人游戏正在进行测试阶段。请在本页面底部查看已知缺失功能。

概览

GDevelop提供了内置的解决方案用于实时多人游戏。无论您制作简单的多人游戏还是更复杂的游戏,从合作游戏到竞争游戏,都可以使用GDevelop的多人游戏功能来构建您的游戏。多人游戏与玩家验证功能搭配使用效果更好。

这一解决方案易于使用,对每一位玩家提供良好的体验。

一些可用的功能包括:

  • 游戏的大厅和用户界面,允许玩家开始新游戏,
  • 用于玩家创建帐号并登录游戏的内置身份验证
  • 游戏主机的自动选择,
  • 根据负责每个对象的玩家的不同,自动同步玩家,
  • 游戏其余游戏状态的自动同步,包括游戏对象、变量等。

提示

从零开始开发多人游戏通常具有挑战性,并容易出错。大多数可用解决方案(包括与GDevelop兼容的解决方案)通常需要一些编程和网络知识。

然而,GDevelop的多人游戏功能简化了这个过程。使用GDevelop,您不需要管理服务器、发送自定义消息、处理连接、管理大厅、处理数据包丢失、预测移动或处理插值。

要使用多人游戏功能,只需在对象上使用Multiplayer行为,并在GDevelop的**“多人游戏”**类别中使用相关的动作/条件。它会自动在您的游戏中可用,并可以立即使用。本页将解释如何使用该行为制作多人游戏以及开始和结束游戏的动作/条件。

注意

GDevelop的多人游戏基础设施可以从非常小的游戏到拥有数千名并发玩家的游戏进行扩展。如果您是游戏工作室或机构有特定需求(例如,向数万人的观众展示推广游戏),请随时发送电子邮件至[email protected]讨论您的具体用例。

未定义分钟示例:从静态游戏到2人平台游戏

以下是一个快速示例,展示如何在平台游戏中添加大厅和两名玩家。

请阅读本页面的其余部分,了解有关大厅的更多信息以及如何设置游戏对象。

大厅系统:开始和结束游戏

多人游戏扩展提供了大厅,使玩家可以一起加入游戏并开始游戏。这是一个关键功能,可以让玩家一起玩游戏,定义他们的玩家编号,并在所有玩家准备好后开始游戏。每个大厅支持最多8名玩家。

Note

将在未来提供自定义大厅界面的方法。

配置大厅

游戏会自动创建大厅。如果您想自定义大厅,例如开始游戏所需的玩家数量或最大玩家数量,请前往编辑器中的游戏仪表板。

在游戏仪表板中配置大厅

让玩家加入新游戏

使用动作 打开游戏大厅。此动作将向玩家显示大厅,以便他们可以加入游戏。

默认的大厅界面

关于大厅基础设施的更多信息

大厅由GDevelop多人游戏基础设施完全处理:

  • 玩家加入大厅时,他们会自动被分配一个玩家编号,并自动定义游戏的主机(玩家undefined)。

  • 当所有玩家准备好时,游戏的主机undefined可以开始游戏。

  • 游戏开始后,大厅窗口自动关闭,玩家会自动相互连接。

多人游戏概述

关于玩家认证的更多信息

玩家需要登录到他们的GDevelop或gd.games帐户才能加入大厅。这是由系统自动处理的,因此调用此动作将自动打开认证窗口(如果需要)。如果您想要自行处理此过程,或者允许玩家更改他们的帐户,您可以使用玩家认证扩展提供的动作和条件。

如果需要,您可以使用条件大厅窗口打开来检查大厅是否已打开,并防止某些操作在场景中发生。通常,当用户在菜单中按下按钮时,可以使用此动作。

游戏开始后,条件大厅游戏刚刚开始将变为真,因此您可以开始游戏。通常,您可以使用此条件来开始在游戏中移动物体,或切换到另一个场景,在该场景中将发生游戏。

在游戏期间访问有关大厅的更多信息

可用表达式让您访问有关大厅的信息:

  • 表达式大厅中的玩家数量:使用此表达式来了解大厅中有多少玩家。这对于知道游戏中有多少玩家,并根据玩家数量调整游戏(例如删除得分、敌人、玩家等)很有用。

  • 条件和表达式玩家编号。使用此表达式或条件来检索和比较大厅中玩家的玩家编号。编号为undefined,2,3等。这在游戏进行中非常有用,因此您可以根据玩家编号分配权限和职责。

  • 条件玩家已离开:使用此条件来了解玩家是否离开了大厅。这对于在玩家离开游戏时适应游戏(无论是结束游戏还是调整游戏的难度)非常有用。

当开发游戏时,您可以打开多个预览窗口,并使用相同的帐户加入相同的大厅。这样,您就可以在不需要多个设备的情况下测试多人游戏功能。

打开多个预览窗口来测试多人游戏

结束游戏

当您想要结束游戏时,使用动作结束游戏

当调用该动作时,条件大厅游戏刚刚结束将对所有玩家返回true,因此您可以结束游戏。通常,您可以使用此条件停止游戏中的事物移动,或切换到另一个场景,在该场景中重新打开大厅。

您还可以使用动作打开游戏大厅自动重新打开大厅,以便玩家可以加入新的大厅并开始新游戏。

游戏过程中:设置同步对象及其所有者


在多人游戏中,最重要的任务之一是使游戏中的所有对象(玩家、投射物、门、触发器、障碍物等)在玩家之间同步,以便所有玩家看到的东西都像他们在同一个房间里一样。

多人游戏扩展提供了一种在玩家之间同步对象的行为。默认情况下,如果未在任何地方使用此行为,则在玩游戏时不会在玩家之间同步任何对象。

多人游戏对象行为

要创建多人游戏,您需要确定以下内容:

  • 必须在玩家之间同步的对象(通常是大多数移动对象)
  • 在主机或特定玩家之间“拥有”的对象-见下文。

对于每个同步对象,有一个对象的所有者的概念。所有者是负责对象实例的玩家:他们可以移动它,更改其属性等。其他玩家将简单地在自己的游戏中复制此行为。

默认情况下,当您使用多人游戏行为时,对象的所有者是主机(在大厅中被定义为Playerundefined)。

  • 如果您的对象不是由特定玩家拥有,但每个人都需要获取正确位置上的对象,则可以保持不变,主机将是对象的所有者。
  • 如果您的对象仅由特定玩家拥有(例如字符),则可以将对象的所有者更改为该玩家编号。
  • 如果您的对象在游戏过程中需要更改所有者(例如,任何玩家都可以捡起的奖励,或者玩家或其他玩家可以射击的箭头),则将所有者保持为“主机”,并使用动作更改玩家对象所有权在游戏过程中更改谁拥有此对象。所有者由玩家编号(1、2、3、4...)或0(当对象由主机拥有时)指定。

即使playerundefined是主机,主机拥有的对象和playerundefined拥有的对象之间存在差异。例如,如果主机拥有的物体(如“无人拥有”)允许另一个玩家抓取物体,而playerundefined则不允许。目前,playerundefined是默认主机,但将来我们可能允许其他玩家成为主机。You can also remove the ownership of an object by using the action 移除对象所有权。当使用此操作时,对象将再次归主机所有。

什么对象上使用多人游戏行为?

通常,您会希望避免在过多的对象上使用行为多人游戏对象,以避免网络和游戏的过载。您可以在对游戏非常重要且您希望所有人以相同方式看到的对象上使用它。例如:

  • 玩家角色。每个玩家将拥有自己的角色,并将其位置发送到服务器,服务器将同步给其他玩家。
  • 玩家投掷的抛射物/炸弹/物品。每个玩家将拥有自己创建的对象,并将其位置发送到服务器,服务器将同步给其他玩家。
  • 玩家可以与之进行交互的对象(门、按钮、旗帜、奖励等)。通常,服务器将拥有这些对象。当玩家与其交互时,使用一个操作让玩家拥有该对象。

网络上同步的内容是什么?

当一个对象具有该行为并被一个玩家或服务器拥有时,它会与其他玩家“同步”(我们也说“复制”)。这包括对象实例的全部状态:

  • 对象的位置、角度、缩放、不透明度,
  • 对象施加的当前力和运动,可以实现移动平台、旋转物体等的同步,
  • 对象的变量,可以实现敌人的健康状况、玩家的分数、门的状态等的同步,
  • 对象的动画(适用于精灵或3D模型),可以同步角色的动画、按钮的状态等,
  • 对象应用的特效,
  • 对象的计时器,可以同步法术冷却时间、炸弹爆炸前剩余时间等,
  • 对象的行为。例如,如果对象具有“平台动作角色”行为,则将同步角色的移动以及角色的状态(跳跃、下落等)。如果使用物理行为或其他影响对象的行为也是如此。

所有这些信息都由GDevelop自动发送,因此您不需要担心。了解这一点仍然是有用的,因为它表明对象越复杂,它将消耗带宽和网络资源越多。

当一个对象销毁时,该行为还会确保在其他玩家游戏中删除它。

在大多数情况下,您只需要将多人游戏对象行为添加到您希望同步的对象上,定义谁负责该对象,GDevelop将处理其余的事情。

设置对象的所有权

您在游戏中将使用的主要操作是更改玩家对象所有权。此操作允许您更改对象的所有者,以便适当的玩家可以负责该对象。It's often used:

  • 在游戏开始时,用于定义游戏中已有对象的所有者,如果在行为中还没有定义它们的所有者。通常情况下,你会根据场景开始时玩家的编号在玩家角色上使用此操作。不需要在由主机创建的对象上使用此操作,因为默认情况下主机是对象的所有者(例如门、按钮、奖励等)。

设置对象所有权的示例

  • 当玩家创建对象时,用于定义对象的所有者。例如,当玩家扔出炸弹时,炸弹将被玩家拥有,因此可以使用带有“玩家编号”表达式的此操作。

  • 当玩家与对象进行交互时,用于更改对象的所有者。例如,当玩家拿起奖励或武器时,这些物品将被玩家所拥有。如果您在不同的玩家间使用相同的对象,还应使用条件来检查实例是否由当前玩家拥有(否则,所有玩家都将尝试拥有该对象)。例如:

拥有对象的示例

或者,您可以使用表达式MultiplayerObject::PlayerObjectOwnership()来获取拥有对象的玩家编号:

应用带有表达式的所有权的示例

变量和游戏的其余部分的同步

在游戏过程中,主机将自动同步:

  • 当前正在播放的场景
  • 全局变量的值
  • 场景变量的值 这对于拥有游戏状态的单一真实来源以及避免手动同步一切非常有用。

而每个玩家将自动同步:

  • 他们拥有的对象,如上所述,并且这些对象的状态(位置、对象变量、行为等)

如果您想确保每个人对游戏状态拥有相同的信息,则可以使用全局和场景变量:分数乘数、难度级别等...

注意

这意味着如果玩家尝试通过修改全局变量或由于网络问题而错误地更改变量来作弊,服务器将自动向玩家重新发送正确的值。

常见模式和要注意的问题

处理同步对象之间的碰撞和交互

一个特别棘手的情况是,当你拥有被不同玩家所拥有的对象,并且你需要处理这些对象之间的碰撞或交互时。如果处理不正确,可能会在不同玩家的游戏中看到不同的行为,这会给玩家带来不好的体验。The most common case is when you delete an object as soon as they collide with another. There is a risk that one player sees the collision happen, but the other player doesn't (as they have not received the information about the latest position of the object).

The rule of thumb is as follows: if the collision, or the interaction in general, is important for the game, then you should handle it only on one player's game (or the server), and then synchronize the result to other players.

For instance, when an arrow shot by a player hits another character or an enemy, you should handle the collision either by the player who owns the arrow or by the player who owns the character or enemy:

  • If you handle the collision on the player who owns the arrow, ensure you use the condition Player object ownership to check if the current player owns the arrow. Once it happens, you can delete your arrow, and save the information about the collision in a variable of an object owned by the player. For instance a variable LastHit can be set to Player 2 if the arrow hits player 2, and player 2 can react accordingly when they see this variable being set (change their animation, decrease their health, etc.)
  • If you handle the collision on the player who owns the character or enemy, ensure you use the condition Player object ownership to check if the current player owns the character. Once it happens, you can save the information about the collision in a variable of an object owned by the player. For instance a variable LastHitBy can be set to Playerundefined if the arrow belonged to playerundefined, and playerundefined can react accordingly when they see this variable being set (and delete the arrow on their side, for instance).

Note

You can also use the action Send a custom message to other players in this case. This action sends a message to other players. For instance a message Arrow hit player 2 can be sent to all players, so that they can handle the collision on their side, using the condition to read the custom message.

Can I still do procedural generation of objects in a multiplayer game?

Yes: first, add the multiplayer behavior to the objects that will be generated. Then you just need a condition to check that the 'Player is host' before generating the objects.

What if a player leaves during a game? What if the host player does this?

If a player is disconnected or close the game, other players will be notified (there is a condition to check this in the events). You can choose to interrupt the game or continue. You can notably choose in the Multiplayer Object behavior properties what happens with the objects of the player.

If the host quits the game, the lobby game will be ended for all players. Note that each player's scene will keep running unless you use the condition to check for lobby game ending (usually, to redirect to a menu or back to the lobbies).

Known missing features or limitations

Missing features or limitations:The lobby UI is not customizable yet.

Joining a lobby during the game is not yet possible, but will be introduced as a configurable option later. This will allow games to continue playing with players joining or leaving as long as the host continues playing.