Asteroids Advanced
Overview
HostMode
topology.The Fusion Asteroids Advanced sample is a remake of the original PUN Asteroids demo in with Unity 2021.3 for PC (Windows), using some of the more advanced features of Fusion:
- Host Migration: When the host leaves the session, the ownership of NetworkObjects is transferred to one of the remaining clients.
- Addressables: The spaceship and the main game scene are both addressables.
- Lag Compensation: Bullets are using lagcompensated raycasts to check collision with asteroids.
- Custom GameObject Handling: Bullets are not NetworkObjects, but uses a simpler networked struct to manage their state and a custom manager to associate that state with local game objects.
- Custom SceneManager: Specifically needed to handle addressables.
Before You Start
To run the sample, first create a Fusion AppId in the PhotonEngine Dashboard and paste it into the App Id Fusion
field in Real Time Settings (reachable from the Fusion menu).
This example is using Unity's addressable assets, so you need to build those before you can launch the sample:
Go to Window
| AssetManagement
| Addressables
| Groups
to open the asset management window for addressables.
Then find the Build
button and select New Build
| Default Build Script
When the build completes you can load the Launch
scene and press Play
.
Download
Version | Release Date | Download | |
---|---|---|---|
1.1.10 | Sep 11, 2024 | Fusion Asteroids Host Advanced 1.1.10 Build 654 |
Application Flow
The AsteroidsAdvanced-Menu
scene allow the player to either host a game or join a running session with another host. Once the session has started, an instance of AsteroidsGame is instantiated and the AsteroidsAdvanced-Game
scene is loaded. The clients will then wait for the host to start the game.
This initial setup is entirely handled by the code in the Menu folder.
AsteroidsGame
is only responsible for the core session handling. It does not create any additional network state or objects, instead the loaded map contains a GameStateController
that manages the game loop and spawns the required objects - specifically player space ships and asteroids, though the latter is delegated to the AsteroidSpawner
.
While the game is running, SpaceshipController
takes care of collecting input from the player and of predicting/applying that input in FixedUpdateNetwork
. Each spaceship also maintains its own list of bullets as an array of "simple" network objects and associated local GameObjects in a SimpleObjectCollection
.
When the time runs out or a player dies 3 times, the game ends and whoever has more points wins. Arguably an odd form of gameplay since a leading player can win by flying into an asteroid, but that's not the point of this example.
In the event that the host disconnects, the MigrationManager
takes over and initiates the host migration process. Essentially, this allow a former client to become the new host and obtain a previously saved network snapshot from which it can restore selective parts of the original game state. In this example, SpaceShipController
and GameStateController
instances are restored since only these two derive from MigrationBehaviour
(Note that this is a convention used specifically in this sample, not a general Fusion feature).
MigrationManager
Host Migration is a Fusion feature that allow a client to inherit the hosting responsibilities for a network session when the original host leaves. The MigrationManager
attempts to simplify this process by introducing a few limitations and conventions.
Specifically, in order for a NetworkObject to be migrated to a new host, it must have exactly one component that derives from MigrationBehaviour
.
MigrationBehaviour
extends NetworkBehaviour
with a few new properties and a new callback that is called once an object has been migrated (aptly named Migrated
).
An object is "migrated" when it has been spawned again and had its state restored, but also, maybe more importantly, the player who originally had input authority of the object has re-connected to the new migrated session and is once again in control of the object.
The primary thing to remember when using the MigrationManager
is that objects that gets migrated are re-spawned well ahead of their input authority re-connecting, so you generally want to delay activation of the migrated object until Migrated
has been called.
To simplify this, the default implementation if MigrationBehaviour
is to disable the game object in Spawned
if a migration is pending, but call Migrated
immediately if not. The default implementation of Migrated
will then enable the game object.
As a consequence, most derived classes can just move their code from Spawned
to Migrated
, but do remember to call base.Migrated
from you overridden implementation.
SimpleObjectCollection
The SimpleObjectCollection
is a lightweight wrapper for networked objects that does not need to be individually identified on the network and thus does not require a full NetworkObject for each local game object.
The collection has two parts:
- The networked state (a struct implementing
ISimpleState
) which is a specialINetworkStruct
containing everything that needs to be synchronized across the network. In this sample this is theBulletState
. - A MonoBehaviour implementing
ISimpleObject
which represents the state visually. In this sample, this is theBulletBehaviour
. Note that theBulletBehaviour
is not aNetworkBehaviour
The SimpleObjectCollection
will call SimpleFixedUpdateNetwork
on the state struct to advance the state from one tick to the next and it will call SimpleRender
on the mono behaviour to update the visual.
The render method differs a bit from the one used by a common NetworkBehaviour
in that it provides two copies of the state and a normalized offset between the two that should represent the interpolated values. If you want snapshot accuracy, just use the to
value and ignore the rest.