- Home /
Can someone explain how a multiplayer scene should be structured?
I'm working on a multiplayer-based game currently. I'm using unity's netcode, I'm fine with networking, and everything is working as it should be. So, I have more like a theoretical/concept problem instead of programming.
I always worked on singleplayer games, and as far as I understand, a multiplayer game's Scene consists of a different built-up. I want a general idea of how I should make the scene. I have to modify my player prefabs since each joining player's camera exists on every client's scene. Now I have separated the camera from the player, but since I'm using cinemachine, our client's camera going to focus on the last joined player's virtual camera. Should I check if we are the owner of the object and destroy is not, or there is a more sophisticated way?
Anyway, I hope my explanation of my issue is somewhat understand able, and thank you for your help in advance! I'm trying to get the answers from unity's "Boss Room" project.
Answer by GetLitGames · 5 days ago
Well first, things are a lot easier if you build components to spawn things in. I generally build a "SpawnObject" component, and it has a prefab property and maybe a delay and some way to repeat spawning. You can even allow custom gizmo icons and show the mesh, hiding the mesh once the game starts but visible in the editor to make it easy to place. Most libraries handle "networking objects in scene" but they can have problems and you eliminate a lot of it by writing your own custom scripts that spawn in objects. Even if those objects are meant to be in the scene when it starts. For player prefabs, yes usually you want to try to separate the camera rig from the prefab since in multiplayer you spawn in player bodies who are not the local player. If for whatever reason it's easier to keep the camera and other relied on objects on the player prefab then you can at least disable the camera gameobject in the player prefab when you detect that the prefab being spawned in isn't the local player. All networking libraries have some way to determine if what is being spawned/replicated is the local player's body or give you some way to figure that out. The same thing for player input. If possibly, put them on separate gameobjects and not attached to the player prefabs. There are different ways to handle things, sometimes you need scripts that will keep looking for the local player in Update, and start doing things after they see the player is in the scene. One pattern that I used was to have a GameManager singleton class that had a LocalPlayer property so several of my scripts just kept checking for it not to be null in Update() and once it wasn't null it would continue/allow the rest to happen. That way scripts just pause waiting to find local player. If you can just add a little script on Cinemachine to watch for local player then enable it after one is there, maybe that solves your problem. In more than one case you will have things that need a reference to the local player or their transform, and you can set those properties. If the scripts expect it to be there on Start, then you can leave that script disabled and your custom script can enable it once it see the local player is there and set's that other scripts properties. Once you enable the script, it will hit it's Start like normal and function properly. Personally I don't use that pattern, it's better to leave a whole gameobject disabled and enable it rather than disable a single script but it's just an example. Relying on gameobjects and script being disabled is also confusing and I generally try to leave everything enabled and find another way, modify their code if necessary so that it waits for the local player. Other times you can just instantiate those prefabs after the player has been spawned. By not just placing everything in a scene beforehand, it forces you to think more about timing and not just take for granted that you can add a reference to something. If you get used to thinking that way you will come up with easy solutions. Remember that you can use GameObject.FindObjectOfType() to find your own script (maybe one you made just for that) - don't rely on Tags and Find("objectname") they are messy. Use Singletons to tie things together, use a Singleton EventManager kind of class to let people subscribe to events and then others raise the event which gets sent out to everyone listening. So, get used to adding Events in your classes. You will need more indirection, and less hard references to things. More spawning things in rather than them just being there. Once you work through a few of those situations you will have the answers to your questions, because you can reuse the solutions you come up with.
Thank you for your help! You made it brighter how I should think about the scenes and prefabs. I haven't mentioned it, but I also had a problem with referencing some gameobjects that I have to create runtime and assign to some scripts. Now I'm going to try create singletons and static scripts, reduce the references somehow and replace FindObjectWithTag to Type.