Quantum 104 - Player Spawning
Overview
With the player character entity created the next steps are spawning a player character for each player that joins the game and linking up the input of the player to the entity.
Player Character Prefab
Currently, the character is a scene object. Quantum can spawn entities at runtime similar to how prefabs can be spawned at runtime in a single player Unity game. Create a Prefabs
folder under QuantumUser/Resources/
. Then create a PlayerCharacter
prefab by dragging the PlayerCharacter
GameObject from the scene into the Prefabs
folder. After doing so, delete the PlayerCharacter
from the scene.
Note how a EntityPrototype
and a EntityView
file have been created nested into the prefab. These are used by Quantum to spawn the entity and link it up to the Unity view.
Player Link Component
Quantum has the concept of players. Each client can own one or multiple players. However, Quantum does not have a built-in concept of a player object/avatar. Each player that is connected to the game is given a unique ID. This ID is called a PlayerRef
. To link an entity to a specific player we will create a PlayerLink component that contains the PlayerRef
of the owner.
Create a PlayerLink.qtn
file in the Assets/QuantumUser/Simulation/Platformer
folder and add the following code to it:
C#
component PlayerLink
{
player_ref Player;
}
Player Data
To dynamically spawn a character we need to let the gameplay code know which entity it should create. Quantum has the concept of player data. Player data allows each player to pass information into the simulation upon connection. It can be information such as which character a player has selected or which skin they are using.
By default the player data contains an Avatar
entity and a Player Nickname
, however the data can also be extended in the Photon/QuantumUser/Simulation/RuntimePlayer.User.cs
file.
IMPORTANT: All data added to the RuntimePlayer
class must be serialized in the SerializeUserData
function. The BitStream
provides serialization for all basic types.
To spawn the player entity we will use the predefined avatar field. An AssetRefEntityPrototype
is the Quantum equivalent to a prefab.
When entering play mode the Quantum simulation automatically runs. This is driven by the QuantumRunnerLocalDebug
component on the QuantumDebugRunner
GameObject in the QuantumGameScene
scene in Unity. This component is used to run a single player version of the Game
locally for development purposes.
The QuantumLocalRunnerDebug
allows to simulate any numbers of local players. In the QuantumLocalRunnerDebug
under Local Players
drag and drop the PlayerCharacterEntityPrototype
file that can be found under the PlayerCharacter
prefab into the Player Avatar
field of the player.
Now that the prefab is linked up to the player data all that is left is to write code to spawn the entity when a player joins.
Spawning Player Objects
Create a new PlayerSpawnSystem.cs
class. Add the following code:
C#
namespace Quantum
{
unsafe class PlayerSpawnSystem : SystemSignalsOnly, ISignalOnPlayerDataSet
{
public void OnPlayerDataSet(Frame frame, PlayerRef player)
{
var data = frame.GetPlayerData(player);
// resolve the reference to the avatar prototype.
var prototype = frame.FindAsset<EntityPrototype>(data.PlayerAvatar);
// Create a new entity for the player based on the prototype.
var entity = frame.Create(prototype);
// Create a PlayerLink component. Initialize it with the player. Add the component to the player entity.
var playerLink = new PlayerLink()
{
Player = player,
};
frame.Add(entity, playerLink);
// Offset the instantiated object in the world, based in its ID.
if (frame.Unsafe.TryGetPointer<Transform3D>(entity, out var transform))
{
transform->Position.X = player._index;
}
}
}
}
This code creates the character entity when a player joins and links it up to the player by adding a PlayerLink component to it.
Signals are similar to events in C#. They are used by Quantum systems to communicate with each other. Quantum comes with a lot of existing signals such as the ISignalOnPlayerDataSet
which gets called after a player has joined the session and shared their player data.
SystemSignalsOnly is a special type of system that doesn't have an Update routine, which makes it leaner and can be used solely for reacting to signals.
Add the PlayerSpawnSystem to the list of systems in the SystemSetup.User.cs
after the MovementSystem
.
Update MovementSystem
Until now the MovementSystem always moved using inputs from player 0:
C#
var input = *f.GetPlayerInput(0);
Replace it with the following code to get the input from the linked player:
C#
Input input = default;
if(f.Unsafe.TryGetPointer(filter.Entity, out PlayerLink* playerLink))
{
input = *f.GetPlayerInput(playerLink->Player);
}
Note that the filter has not been adjusted so the system will still filter for entities with a CharacterController but no PlayerLink component. In this case it will use the default
value for the input. This results in no movement besides gravity being applied.
Getting a component using TryGet
in Quantum is very fast O(1) because Quantum uses a sparse set ECS.
Switch to Unity and enter play mode. A player character will be spawned and the player reacts to keyboard inputs.
Back to top