This section will cover "Player" prefab instantiation over the network and implement the various features needed to accommodate automatic scenes switches while playing.
- Instantiating the player
- Keeping track of the player instance
- Manage player position when outside the arena
Instantiating the Player
It's actually very easy to instantiate our "Player" prefab.
We need to instantiate it when we've just entered the room, and we can rely on the GameManager Script
Start() Message which will indicated we've loaded the Arena, which means by our design that we are in a room.
In the Public Variables region add the following variable
In the Start() method, add the following and save
This exposes a public field for you to reference the "Player" prefab. It's convenient, because in this particular we can drag and drop directly in the "GameManager" prefab, instead of in each scenes, because the "Player" prefab is an asset, and so the reference will be kept intact (as opposed to referencing a GameObject in a hierarchy, which a Prefab can only do when instantiated in the same scene).
Start(), we do instantiate it (after having properly check we have a "Player" prefab referenced)
Notice that we instantiate well above the floor (5 units above while the player is only 2 units high). This is one way amongst many other to prevent collisions when new players join the room, players could be already moving around the center of the arena, and so it avoids abrupt collisions. A "falling" player is also a nice and clean indication and introduction of a new entity in the game.
However, this is not enough for our case, we have a twist :) When other players will join in, different scenes will be loaded, and we want to keep consistency and not destroy existing players just because one of them left. So we need to tell Unity to not destroy the instance we created, which in turn implies we need to now check if instantiation is required when a scene is loaded.
Keeping track of the player instance
In the "Public Variables" Region, add the following
Awake()method, add the following
With these modifications, we can then implement inside the
GameManager Script the check to only instantiate if necessary.
Surround the instantiation call with a if statement
With this, we now only instantiate if the
PlayerManager doesn't have a reference of an existing instance of the
Manage player position when outside the arena
We have one more thing to watch out for. The size of the Arena is changing based on the number of players, which means that there is a case where if one player leave and the other players are near the limits of the current arena size, they will simply find themselves outside the smaller arena when it will load, we need to account for this, and simply reposition the player back to the center of the arena in this case. It's something that is an issue in your gameplay and level design specifically.
There is currently an added complexity because Unity has revamped "Scene Management" and Unity 5.4 has deprecated some Callbacks, which makes it slightly more complex to create a code that works across all Unity versions (from Unity 4.7 to the latest). So we'll need different code based on the Unity version. It's unrelated to Photon Networking, but however important to master for your projects to survive updates.
At the top of the script add the following define
At the end of the
Start()method, add the following code
Add the following two methods inside the "MonoBehaviour CallBacks" region
What this new code does is watching for a level being loaded, and raycast downwards the current player's position to see if we hit anything. If we don't, this is means we are not above the arena's ground and we need to be repositioned back to the center, exactly like when we are entering the room for the first time.
If you are on a Unity version lower than Unity 5.4, we'll use Unity's callback
If you are on Unity 5.4 or up,
OnLevelWasLoaded is not available anymore, instead you have to use the new SceneManagement system.
Finally, to avoid duplicating code, we simply have
CalledOnLevelWasLoaded method that will be called either from
OnLevelWasLoaded or from the