如何将此实体系统联网?


33

我已经为FPS设计了一个实体系统。它基本上是这样的:

我们有一个“世界”对象,称为GameWorld。它包含一个GameObject数组以及一个ComponentManager数组。

GameObject拥有一个Component数组。它还提供了一个非常简单的事件机制。组件本身可以向实体发送事件,该事件将广播到所有组件。

Component基本上是赋予GameObject某些属性的东西,并且由于GameObject实际上只是它们的容器,因此与游戏对象有关的所有事情都发生在Components中。示例包括ViewComponent,PhysicsComponent和LogicComponent。如果需要它们之间的通信,可以通过使用事件来完成。

ComponentManager只是一个类似于Component的接口,对于每个Component类,通常应该有一个ComponentManager类。这些组件管理器负责创建组件,并使用从XML文件之类读取的属性来初始化它们。

ComponentManager还负责组件的大量更新,例如P​​hysicsComponent,我将在其中使用外部库(该库一次执行世界上的所有操作)。

为了实现可配置性,我将为实体使用一个工厂,该实体将读取XML文件或脚本,创建文件中指定的组件(这还将在正确的组件管理器中添加对它的引用以进行批量更新),以及然后将它们注入GameObject对象。

现在出现了我的问题:我将尝试将其用于多人游戏。我不知道该如何处理。

首先:客户从一开始就应该拥有哪些实体?我首先要说明单人引擎如何确定要创建的实体。

在关卡编辑器中,您可以创建“画笔”和“实体”。刷子用于墙壁,地板和天花板等事物,基本上是简单的形状。实体是我告诉过您的GameObject。在关卡编辑器中创建实体时,可以为其每个组件指定属性。这些属性直接传递给实体脚本中的类似构造函数的对象。

保存要加载的引擎的级别时,它会分解为实体及其关联属性的列表。画笔将转换为“ worldspawn”实体。

当您加载该级别时,它只是实例化所有实体。听起来很简单,是吗?

现在,对于实体的联网,我遇到了许多问题。首先,从一开始就应该在客户端上存在哪些实体?假设服务器和客户端都具有关卡文件,则客户端可能会实例化该关卡中的所有实体,即使它们只是出于服务器上的游戏规则而存在。

另一种可能性是,客户端在服务器发送有关实体的信息后立即实例化该实体,这意味着客户端将仅具有其所需的实体。

另一个问题是如何发送信息。我认为服务器可以使用增量压缩,这意味着它仅在发生变化时才发送新信息,而不是在每帧都向客户端发送快照。尽管这意味着服务器必须跟踪每个客户端当前所知道的信息。

最后,应该如何将网络注入引擎?我在考虑一个组件NetworkComponent,它被注入到每个应该联网的实体中。但应该如何在网络组件知道什么变量网络,以及如何访问这些,最后如何在客户端上相应的网络组件应该知道如何改变网络变量?

我在处理此问题时遇到了很大的麻烦。如果您能帮助我,我将不胜感激。我也欢迎有关如何改进组件系统设计的提示,因此不要害怕提出建议。

Answers:


13

这是一个该死的神怪(赦免),其中有许多细节+1。绝对足以帮助偶然发现它的人们。

我只是想补充我的2美分,关于不发送物理数据!老实说,我不能太强调这一点。即使您已经对其进行了优化,实际上您也可以发送40个球体,这些球体会因微碰撞而反弹,并且它在震动室中可以达到全速,甚至不会降低帧速率。我指的是执行您讨论的“增量压缩/编码”,也称为数据差分。这与我要提出的内容非常相似。

航位推算VS数据差分:它们足够不同,实际上并没有采用相同的方法,这意味着您可以同时实现这两种方法以进一步优化!注意:我没有同时使用它们,但是两者都使用过。

增量编码或数据差异:服务器根据客户端知道的内容携带数据,并且仅将旧数据与应更改内容之间的差异发送给客户端。例如,pseudo->在一个示例中,当数据已经为“ 310 435 210 4000 40”时,您可能会发送数据“ 315 435 222 3546 33”!而是发送(以增量形式)“ 5 0 12 -454 -7”,它要短得多。

更好的示例可能会发生一些变化,例如,现在我有一个包含45个链接对象的链接列表。我想杀死其中的30个,所以我这样做了,然后向所有人发送新的数据包数据,如果尚未为执行此类操作而构建服务器,则会减慢服务器的速度,并且发生这种情况是因为它正在尝试例如纠正自己。在增量编码中,您只需放入(伪)“ list.kill 30 at 5”,它将在第5个对象之后从列表中删除30个对象,然后对数据进行身份验证,但在每个客户端而不是在服务器上。

优点:(现在只能想到其中之一)

  1. 速度:显然,在我描述的最后一个示例中。与之前的示例相比,它的区别要大得多。总的来说,根据经验,我不能诚实地说出哪一种会更常见,因为我在推算中做了很多工作

缺点:

  1. 如果要更新系统,并想添加更多应通过增量进行编辑的数据,则必须创建新函数来更改该数据!(例如,如先前的“ list.kill 30 at 5”,哦,我需要将取消方法添加到客户端!“ list.kill undo”)

推算:简单地说,这是一个比喻。我正在为某人编写关于如何到达位置的地图,而我仅包括一般要去的地方,因为它足够好(停在建筑物上,向左转)。别人的地图上包括街道名称,还有左转弯的角度,这根本有必要吗?(没有...)

推算法是每个客户端都有一个算法的方法,该算法对于每个客户端都是恒定的。通过说出哪些数据需要更改以及如何更改,几乎可以更改数据。客户端自行更改数据。一个例子是,如果我的角色不是我的玩家,而是被另一个和我一起玩的人所移动,则我不必不必每帧都更新数据,因为很多数据是一致的!

可以说我的角色朝某个方向移动,许多服务器会将数据(几乎每帧)发送到客户端,并且播放器正在移动(出于动画原因),这些数据正在播放。这么多不必要的数据!为什么我到底需要更新每个帧,该单元的位置以及它面向的方向以及移动的方向?简单地说:我不知道。仅当方向改变,动词改变(isMoving = true?)以及对象是什么时,才更新客户端。然后,每个客户端将相应地移动对象。

就个人而言,这是一种常识性策略。我很早以前就想出了这一点,后来发现它一直被使用。

答案

坦率地说,请阅读James的文章,并阅读我对数据的看法。是的,您绝对应该使用增量编码,但也请考虑使用航位推测法。

就个人而言,当客户端从服务器接收到有关该数据的信息时,我将实例化该数据(您建议的某种方式)。

首先应该指出只有可更改的对象才可编辑吗?我喜欢您的想法,即通过组件和实体系统包含一个对象应该具有网络数据!它很聪明,应该可以正常工作。但是,绝对不要给画笔(或任何绝对一致的数据)任何联网方法。他们不需要它,因为它甚至是无法更改的(客户端到客户端)。

如果它像一扇门,我会给它提供网络数据,但仅提供布尔值(无论它是否打开),显然是什么类型的对象。客户端应该知道如何更改它,例如,打开,关闭它,每个客户端都会收到他们都应该关闭它的信息,因此您可以更改布尔数据,然后为要关闭的门设置动画。

至于它应该如何知道要联网的变量,我可能有一个真正属于SUB对象的组件,并为其提供了要联网的组件。另一个想法是不仅拥有声音,AddComponent("whatever")而且还AddNetComponent("and what have you")因为个人听起来更聪明。


这是一个荒谬的答案!对此我感到非常抱歉。因为我打算只提供少量知识,然后才提供关于某些事情的2美分。因此,我知道很多地方可能没有必要注意。
约书亚树篱,

3

本来打算发表评论,但认为这可能是答案的足够信息。

首先,为这样一个写得很好的问题加上+1的详细信息,以判断答案。

对于数据加载,我希望客户端从world文件加载世界。如果您的实体中有来自数据文件的ID,那么默认情况下,我也会加载它们,以便您的网络系统可以引用它们以了解它在谈论哪些对象。每个人都加载相同的初始数据应表示它们对于这些对象都具有相同的ID。

其次,不要制作NetworkComponent组件,因为除了在其他现有组件中复制数据(物理,动画等是要传送的一些常见事物)之外,它什么也不会做。要使用自己的命名,您可能需要制作一个NetworkComponentManager。这与您从其他Component到ComponentManager的关系稍有不同,但是当您启动网络游戏并且具有可联网的任何类型的组件并将其数据提供给管理器时,可以将其实例化,以便将其打包并发送出去。如前所述,如果您拥有某种序列化/反序列化机制,也可以在其中使用它的“保存/加载”功能来打包数据,

考虑到您的问题和信息水平,我认为我不需要进一步详细介绍,但是如果不清楚,请发表评论,我将更新答案以解决此问题。

希望这可以帮助。


因此,您要说的是应该联网的组件应该实现这样的某种接口?:void SetNetworkedVariable(string name,NetworkedVariable value); NetworkedVariable GetNetworkedVariable(字符串名称); 其中NetworkedVariable用于插值和其他网络内容的目的。我不知道如何识别实现此目的的组件。我可以使用运行时类型标识,但这对我来说似乎很丑。
卡特
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.