This document is about: FUSION 2
SWITCH TO

Architecture - Client Host

Unity Project

All game scripts are located in the Scripts folder under the Asteroids.HostSimple namespace.

Folder Content
/Scripts GameManager and PlayerColorPalette
/Scripts/Asteroid AsteroidBehaviour and AsteroidSpawner
/Scripts/Player SpaceshipController, PlayerWeapon, LocalInputPoller, SpaceshipSpawner, SpaceshipVisuals and SpaceshipSounds
/Scripts/UI StartMenu, GameUI and PlayerUI
/Scripts/Utilities NetworkObjectPool, ScreenBoundary, ScreenUtils and SelfDestructingVFX
/Prefabs NetworkRunner prefab, Asteroids with BigAsteroid and SmallAsteroid, Player with Spaceship and Bullet, UI with GameUI and VFX
/Scenes Menu and Game scenes
/TextMesh Pro TextMesh Pro resources with the Exo 2 font, see Overview
/Photon Fusion SDK

The project has two scenes:

  • Menu: The start menu with the StartMenu script, the first scene of a build.
  • Game: The play area with the Spawner object holding the AsteroidSpawner and the SpaceshipSpawner, the GameStateController object holding the GameManager, the GameUI and four spawn points.

The host loads the Game scene with NetworkRunner.LoadScene once the session runs, see Scene Loading.

High Level Breakdown

The game boots in the Menu scene, StartMenu instantiates the NetworkRunner prefab and starts the session with GameMode.AutoHostOrClient or GameMode.Client, see Session and Menu.

In the Client Host topology the host has state authority over all network objects. The other clients send their input to the host and predict their own spaceship, see Network Topologies. The same game exists as a Shared Authority project, see Architecture - Shared Authority.

Game Manager spawns a spaceship per player and runs the game state and the round timer.

Spaceship reads the network input, moves the ship, wraps it around the screen and detects asteroid collisions.

Weapon fires projectiles stored as networked data and scores asteroid hits.

Asteroids spawns big asteroids, breaks them into small ones and pools them.

Session and Menu

StartMenu.StartGameAsync instantiates the NetworkRunner prefab and starts the session:

C#

_runnerInstance.ProvideInput = true;

var startGameArgs = new StartGameArgs()
{
    GameMode = mode,
    SessionName = roomName,
    ObjectProvider = _runnerInstance.GetComponent<NetworkObjectPool>(),
};

START HOST passes GameMode.AutoHostOrClient and START CLIENT passes GameMode.Client, the room name becomes the session name, see Network Runner. The session uses the PlayerCount of 4 from the NetworkProjectConfig, GameManager.MaxPlayers sizes the spawn points to match. When the runner runs as the host (IsServer), StartMenu loads the Game scene. The nickname of the local player is kept in the static StartMenu.ChosenLocalPlayerNickname.

Game Manager

GameManager sits on the GameStateController scene object and implements IPlayerJoined and IPlayerLeft. When a player joins, SpaceshipSpawner.SpawnShip spawns the Spaceship prefab on the host at a free spawn point, gives the player input authority and registers the ship with Runner.SetPlayerObject, see Spawning. When a player leaves, the host despawns the ship.

The game state and the round timer are networked properties, the timer is a TickTimer:

C#

[Networked] private TickTimer _timer { get; set; }
[Networked] private EGameState _gameState { get; set; }

StartGame closes the session, sets every ship alive and starts the timer with the _gameSessionLength of 180 seconds. CheckEndGame runs on the host and switches the state to Ending when the timer expired or no ship has lives left.

GameManager calls Runner.SetIsSimulated(Object, true) in Spawned, so FixedUpdateNetwork also runs on the clients and every peer reacts to a state change. It starts or stops the asteroid spawner, raises GameStateChanged for the GameUI and shuts the runner down _endDelay seconds after the round ended. NetworkEvents.OnShutdown then loads the Menu scene. GameUI shows the winners from CalculateWinners, the highest score wins and remaining lives break a tie.

Spaceship

SpaceshipController adds a LocalInputPoller to the ship of the local player and registers it with NetworkEvents.OnInput. LocalInputPoller reads the Move and Fire actions of the InputSystem_Actions asset in Update and hands a SpaceshipInput struct to Fusion:

C#

public struct SpaceshipInput : INetworkInput
{
    public Vector2 MovementInput;
    public NetworkButtons Buttons;
}

A fire press stays set until the next OnInput call, so a press between two ticks is not lost, see Client-Server Player Input.

SpaceshipController reads the struct with GetInput in FixedUpdateNetwork on the host and on the client with input authority. The x axis rotates the ship and the y axis accelerates it, the velocity is the networked _velocity and a drag slows the ship down without input. ScreenBoundary on the camera sets the play area from the orthographic size and a fixed 16:9 aspect. A ship that leaves the play area moves to the opposite edge with NetworkTransform.Teleport, see Network Transform.

Once the spawn shield ShieldTimer expired, HasHitAsteroid runs a lag compensated OverlapSphere against the asteroid layer. A hit destroys the asteroid through TryHitAsteroid and sets IsAlive to false, the host removes a life and starts the respawn timer, the respawned ship gets a new shield. The nickname travels from the input authority to the host with RPC_SetNickname in Spawned, see RPCs.

Weapon

PlayerWeapon stores up to 16 projectiles as ProjectileData structs in a networked array, the bullets are local visuals, see Projectiles Essentials:

C#

[Networked, Capacity(16)] private NetworkArray<ProjectileData> _projectileData { get; }

A fire press detected with WasPressed against the networked previous buttons writes a new entry with the fire tick, position and velocity. The networked _shootCooldown limits the fire rate to one shot per 0.2 seconds.

In FixedUpdateNetwork every active projectile casts a lag compensated ray from its previous to its current position, see Lag Compensation. A hit on an asteroid calls AsteroidBehaviour.TryHitAsteroid and adds the asteroid Points to the networked Score of the ship. The asteroid prefabs carry a HitboxRoot with a sphere Hitbox, lag compensation is enabled in the NetworkProjectConfig.

Render instantiates the bullet visuals for new shots by comparing the networked FireCount with a local counter and moves them along the calculated path.

Asteroids

AsteroidSpawner spawns a BigAsteroid at a random screen edge every 5 to 10 seconds while the round runs. The host pushes the asteroid towards the center with a force on its Rigidbody, a NetworkTransform replicates its position. Asteroids that leave the play area are despawned.

AsteroidBehaviour ignores hits during a short spawn immunity. A hit sets the networked _wasHit and starts a despawn timer, so the destruction effect plays before the host despawns the asteroid. A big asteroid calls AsteroidSpawner.BreakUpBigAsteroid, which spawns three to five SmallAsteroid objects around it.

The NetworkObjectPool on the NetworkRunner prefab derives from NetworkObjectProviderDefault and recycles the asteroid objects instead of instantiating and destroying them, see NetworkObjectProvider. AsteroidBehaviour.Spawned resets the local state of a reused asteroid, such as the scale of its model.

Last updated on

Back to top