× Phaseshift FCOM Tutorials

0.0.15 Online Multiplayer basics, Stats and Feat tracking with new branding



Basics of online multiplayer networking, player stats, feats and data tracking, new branding and performance improvements.

This version focused primarily on online multiplayer, making sure players could connect to a game, their states would sync, and a game could be played where you were racing with a real life human. The existing online test lobbies and netcode was used as a bit of a guide for the 'real' code.

Online Multiplayer and Networking


Even though the online multiplayer worked before by using Unity's Netcode for GameObjects, it was time to finesse the system and allow players to actually race and complete a session. The Lobby code all worked as it did previous, I simply updated the existing UI, utilising Bubble.UI and it's text animations. 

I had to relearn how Unity uses it's NGO system, I had to enable 'allow remote connections' then test what had already worked, the lobby system. This was pretty straightforward thankfully, I tested between two computers (on the same network though) and the connection was established pretty easily using the 'quick join' feature. That was the easy bit.

I now had to sync states to the host and make sure everyone was on the same page. I utilised RPCs to tell each connected client of their state. When all connected clients were ready, the host could advance the session. This was more or less straight forward. I used NetworkObjects that were spawned for each player on connection to monitor any changes in that players state. The host could then listen for changes and allow or disallow actions appropriately. 

The in-game code was where things would get more challenging.

Finding a networking design pattern


This is where a lot of experimentation happened. Currently the clients moved their NetworkRigidbody and NetworkTransform and that would sync across the network. Nothing else got tracked. The vehicles would spawn correctly, but they wouldn't lean, didn't interact with the environment and any visual effects didn't happen (amongst other things). I looked up and did some research on how to best network this using NGO. It was suggested that a host authoritative system would be most appropriate. 

Host Authoritative


A host authoritative system sends and sync data (in my case input data) and have it simulate on the host machine, then their transform and rigidbody is synced to the clients. This sounded good in theory, it was the most fair.

In practice though this was awful for clients. PS:E is a very fast paced game, high velocities, constant changes of direction, it's hard to predict where someone might go and even when I added reconciliation in and things like interpolation to smooth out the 'frames' it still felt awful for the client. I couldn't tune the system to make it feel good for the client, it just always felt awful. A lot of the feeling came from physics inertia and that consistency is super important for driving feel. This was a bit of a failure, but I certainly learned from this experience.

Client Authoritative


I then played with a client authoritative model. Input would still be synced like the host authoritative, but the client would also have authority over their rigidbody and transform. This is then synced to the host and the network. As the input is also synced, effects and abilities etc could also be simulated per local client. The vehicles felt real and behaved exactly like they should. I would then interpolate the frames and the velocity and inertia would be same. The feeling for the client remained, and how they looked simulated local for other connected clients would be authentic. This is basically where I finished for this version. The intention was to make sure the basics worked, and it felt good and fun for all clients. There is far more work to be done to make it feature complete.

This model presents some issues though:

  • Vehicle states are not completely synced with the host, simulations are local with each client offering latency, so positions (1st, 2nd etc) may not be accurate. One player might finish 1st on one local simulation, while on another's 2nd.
  • This opens up possibilities of cheating as clients own their transform and rigidbody

I have outlined another version to sort these issues, but the long and short of it is to make sure there is some amount of host authority. My priority is always how it feels for the person playing the game. I need to make sure that whatever I build is in the realms of possibility for a solo developer, and that I don't spend too much time on features that might not take off, or add massive value. If people can play online, great. If a massive competitive scene takes off, I may have to put more work in!

To fix these issues I can make sure that the overall client race time is authority. No matter how each local simulation looked, the final race time should dictate final race positions. This doesn't have the best feeling, but what I can achieve, is likely the most fair. For cheating protection, I can keep sending the host a reel of transforms per pre-defined tick. If too much distance has been detected from the last tick, the host can perform a respawn. I can also do this with ability damage. The host would validate every damage dealing event, and check the damage dealt is with in correct bounds.

Network Development Difficulties


It's also worth mentioning other difficulties I had when building multiplayer. My PC is not...the best. I was using Unity's Multiplayer Play Mode for the majority of the testing to simulate multiple connected clients. This means effectively running multiple play and scene windows at runtime. My PC struggled. This was the basis of a lot of my struggles with this version; performance. 

Of course testing online with builds is more performant as there isn't the Editor overhead, but the time taken to create builds just means everything is...slow. I should mention that PS:E performs really well, I get 120FPS+ on a build at max settings on a PC that was 'mid' 10 years ago. Just having to double up on everything really kills your PC. A main source of my desync at the start was Unity's default throttling under load. I would cap each client at 30FPS in an effort to save my PC, but in some cases it would dip below 30FPS - it would then slow down game time on the client having difficulty, which would mess up server tick rate and network object sync times. This obviously caused massive desync as each instance of the game was running at different speeds.

Some things that helped with development was the extensive library of debug tools that I had built up already. I had debug functions mapped to my game controller that I can simply toggle at runtime whilst testing. The most useful was an 'AI takeover' feature where the AI would takeover driving the vehicle, and I could swap between both clients to test latency and sync accuracy. Another useful development was the inclusion of video settings presets early on, I simply set all clients graphics to the lowest, and reduced resolution to improve frame rate.

Stats and Feats Tracking


This was a neat addition to the SaveData feature, tracking of stats and feats during an event. This opens up the game for session awards later on (much like Phaseshift 1) and profile stats tracking, where you can see how many times you did x or y over your playtime with PS:E. This also helps me track AI performance; even though AI stats and feats are not saved this time - I can still track them over an event and follow trends with how the AI personalities like to play the game.

AI Character Portraits


Something I'm playing with is how each character looks. In Phaseshift 1 I made all the character artwork and it was....rough. I am no artist! However with AI I've been able to draft the look of each character in high detail. My intention is to use the currently generated artwork as a base, to then hire a skilled artist to create each AI character's portrait and look for the final release. 

Character portrait examples
An example of some of the generated character portraits, depicting Chug, a white male rocker; Kitsune, a charming trickster; Calypso, a dreadlocked badass; and Kryo, the champion.

Soundtrack


I'm also still playing around with the feel of the soundtrack in game. I wasn't completely happy with the feel of the first track I produced, it felt a bit too synthwave and a bit too dark. I want something more bright, intense and drum and bass driven. I produced another track below, it's far more cinematic and intense. It definitely needs a lot of work still, needs better transitions and FX, but the mixing and basic arrangement I feel are a better fit for PS:E. A link to a sample of the work in progress soundtrack can be found here.

0.0.15 Online Multiplayerv0.0.15


May 9, 2026
  • Added Online Multiplayer basics
  • Added client authoritative transform and physics with interpolation
  • Connected clients correctly syncs game state for countdowns and scene loading
  • Added 18 character portraits, and 1 new team
  • Produced and added a new piece of soundtrack to InSession state
  • Stat and Feat tracking for the local player
  • Performance improvements for pit lighting and reflection probes
  • Added new PS:E logos
  • Improved API debug tools

Liked this article?

Please consider sharing!
Author

Josh Lyell

Game Developer

Other Combat Racing games

A futuristic bike races past a logo of the game titled Phaseshift

Phaseshift


Developer: Bubblehead Game Dev

Genres: Combat RacingRacingAction

Platforms: PC


Release date: Apr 8, 2022