简体   繁体   English

C#-如何同步“玩家统计”实例列表? (统一)

[英]C# - How to synchronize a list of “player stats” instances? (Unity)

It's probably o noob question, but important to me. 这可能是一个新手问题,但对我来说很重要。 Also I think it's an interesting topic. 我也认为这是一个有趣的话题。

I'm using C# with new Unity Multiplayer. 我在新的Unity Multiplayer中使用C#。 You can find tutorial here: https://unity3d.com/learn/tutorials/topics/multiplayer-networking - I'm working on exactly that base. 您可以在这里找到教程: https : //unity3d.com/learn/tutorials/topics/multiplayer-networking-我正在这个基础上工作。 I've just succesfuly made my code so that when player joins or hosts, he adds his "players stats" to a static List as an instance of the "PlayerStats" class. 我已经成功编写了代码,以便在玩家加入或托管时,他将“玩家统计信息”添加到静态列表中,作为“ PlayerStats”类的实例。 It should work this way for every player - whenever someone joins, his instance of his statistics is added to the list. 对于每个玩家,它都应该以这种方式工作-每当有人加入时,他的统计信息实例就会添加到列表中。

Now, this list should be one, global, so I thought - it should be synchronized by server. 现在,该列表应该是一个全局列表,因此我想-应该由服务器同步。 Maybe as some kind of SyncVar , probably SyncList of some type. 可能是某种SyncVar ,可能是某种类型的SyncList And here's the problem - is there any way to synchronize a list of class instances? 问题就在这里-有什么方法可以同步类实例列表吗?

I've checked Unity Documentation and seems that's a bummer. 我已经检查过Unity文档,这似乎很糟糕。 Or maybe I understand it wrong. 也许我理解错了。 SyncList seems to have only basic types like integer, etc, there is also a struct, but... Do I really need to convert class with player stats into a struct for a server-wide synchronization? SyncList似乎只有基本类型,例如整数等,还有一个结构,但是...我真的需要将具有播放器统计信息的类转换为用于服务器范围同步的结构吗?

Once again what I want to achieve: I need to have one, global list of players into which new joining players would be added and identified. 我要再次实现的目标是:我需要一个全局的球员列表,在其中要添加和标识新加入的球员。 I've already done identifying - while adding new instance, I'm giving that player an ID = PlayerList.Count - 1 . 我已经完成识别-在添加新实例时,我给该玩家一个ID = PlayerList.Count - 1 ID which is static, but should be local. 静态的ID,但应为本地ID。 Probably best if elements of PlayerList could be PlayerStats class instances. 如果PlayerList的元素可以是PlayerStats类实例,则可能是最好的。 So each player (at his own index) loads his data from disk into his instance in PlayerList. 因此,每个播放器(以自己的索引)将其数据从磁盘加载到PlayerList中的实例中。 I thought it would be convenient that way (not sure how to do it otherwise, though). 我认为这样会很方便(不过,不知道怎么做)。 It works in singe player mode, but in Multiplayer I don't know how to design it properly. 它可以在单人游戏模式下工作,但是在多人游戏中,我不知道如何正确设计它。 Because I need that static list to be server-wide, aware of other players. 因为我需要该静态列表位于服务器范围内,所以请注意其他播放器。

And what if I had to synchronize equipment, which are made of classes in my project. 还有,如果我必须同步项目中由类构成的设备,该怎么办?

Can you help me somehow with designing that? 您可以以某种方式帮助我吗? I'm trying to create a simple multiplayer rpg based on our new Unity Multiplayer tutorial. 我正在尝试根据新的Unity Multiplayer教程创建一个简单的多人rpg。 Now there's a need to identify players and load their data in proper place, data which is already generated by character generator and saved, and which properly loads in single player already. 现在需要识别玩家并将其数据加载到适当的位置,这些数据已经由角色生成器生成并保存,并且已经正确加载到单个玩家中。 I thought I should use a local singleton instance of a class PlayerStats for player data, and to keep those instances in global server-wide list. 我认为我应该使用PlayerStats类的本地单例实例来存储玩家数据,并将这些实例保留在全局服务器级列表中。 My PlayerStats are a component of PlayerStatsObject (empty gameobject in hierarchy that has DontDestroyOnLoad ). 我的PlayerStats是PlayerStatsObject(层次结构中具有DontDestroyOnLoadgameobject DontDestroyOnLoad )的组成部分。 PlayerStats class, made into singleton instance, contains whole generated character, with his vitals, class, race, equipment lists made of classes, etc. PlayerStats类(做成单例实例)包含整个生成的角色,以及他的体能,职业,种族,由职业组成的装备清单等。

So basically, I need every player to be added to the list, have his own PlayerStats, and make those PlayerStats easily interactable/modifiable by other players (and AI enemies / Environment, but that's easy, it's single player). 因此,基本上,我需要将每个玩家添加到列表中,拥有自己的PlayerStats,并使这些PlayerStats易于与其他玩家(和AI敌人/环境,但很简单,它是单个玩家)进行交互/修改。 Adding PlayerStats as a component to Player prefab seems overkill to me, as those stats will be called by almost everything in game all the time. 对我而言,将PlayerStats作为组件添加到Player prefab中似乎是过大的,因为这些统计数据几乎总是被游戏中的所有内容调用。 So that's a ton of GameObject.Find("Player").GetComponent<PlayerStats>(); 这就是大量的GameObject.Find("Player").GetComponent<PlayerStats>(); . Seems that would be disastrous design. 看来那将是灾难性的设计。

How about generating UUIDs for the users on the server. 如何为服务器上的用户生成UUID These will provide a solid base to exchange information about the users between clients. 这些将为在客户端之间交换有关用户的信息提供坚实的基础。

Next step would be the actually exchange of data. 下一步将是实际的数据交换。 You'll need a way to extrapolate the data from the object. 您需要一种从对象推断数据的方法。 Sending complete instances of objects over the network would ask quite the bandwidth and is not necessary seeing the other clients know the structure of the class itself. 通过网络发送对象的完整实例会占用相当大的带宽,而不必看到其他客户端也知道类本身的结构。 So all you want is the information to construct an exact equal of an object on machine B as exists on machine A. 因此,您所需要的就是在机器B上构造与在机器A上存在的对象完全相等的信息。

ToString is kind of a standard used for transforming complex data into a string. ToString是一种用于将复杂数据转换为字符串的标准。 Most often used for displaying or storing such data. 最常用于显示或存储此类数据。 You can pick the objects fields to synchronize and combine them into a string. 您可以选择对象字段进行同步并将它们组合为一个字符串。 So by adding a ToString method to your PlayerStats class you would be able to: 因此,通过将ToString方法添加到PlayerStats类,您将能够:

  1. loop (more on this later) over your PlayerStats instances PlayerStats实例上循环播放(稍后会详细介绍)
  2. convert them to strings 将它们转换为字符串
  3. concatenate those strings into one single string, separated with a delimiter (eg ## ) 将这些字符串连接成一个字符串,并用定界符(例如## )分隔
  4. send it off to clients/server 发送给客户端/服务器
  5. clients can split the string back to multiple strings 客户可以将字符串拆分成多个字符串
  6. by matching the UUIDs, the client can determine which players already exist and which need to be newly created. 通过匹配UUID,客户端可以确定哪些球员已经存在以及哪些球员需要重新创建。

About the looping, my suggestion would be to use the Observer Pattern . 关于循环,我的建议是使用观察者模式 In short you'll have a single monitoring instance per type of object, PlayerStats in this case. 简而言之,每种类型的对象将只有一个监视实例,在这种情况下为PlayerStats Every instance of PlayerStats will register itself at the observer on instantiating OR you can create a Factory who does the instantiating and registering for you. 每个PlayerStats实例都会在实例化时向观察者注册,或者您可以创建一个Factory来为您实例化和注册。 On destruction of a PlayerStats instance you'll need to "unsubcribe" from the monitoring instance again (you don't want ghost references haunting your application). 在销毁PlayerStats实例后,您将需要再次从监视实例“取消订阅”(您不希望幽灵引用困扰您的应用程序)。

Your idea about using the PlayerStats as component isn't that much of a strange idea. 您关于使用PlayerStats作为组件的想法并不是一个奇怪的想法。 Yet you're right that finding the component over and over again is a waste of resources. 但是,您一次又一次地找到组件是对的,这是对资源的浪费。 Using the Observer Pattern you can keep track of all PlayerStats instances and easily loop over them. 使用观察者模式,您可以跟踪所有PlayerStats实例并轻松遍历它们。

Hopefully this will get you started in the right direction! 希望这将使您朝正确的方向开始!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM