This document is about: FUSION 2
SWITCH TO

Karts

Level 4

Overview

The Fusion Kart sample demonstrates an approach on how to make a racing game using a Server Authoritative, Client Predicted model where players can create and join rooms using the names as room identifiers.

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). The photon app settings assets can be selected from the Fusion menu Fusion > Realtime Settings.

Download

Version Release Date Download
2.0.1 Jul 23, 2024 Fusion Karts 2.0.1 Build 605

Highlights

The project has a complete game loop, allowing up to 8 users to join each other and race competitively to see who will win, as well as practice together without timers on a track with infinite laps. The main features include:

  • Two different modes (Race and Practice)
  • Two race tracks
  • Karts with varying stats
  • Shared Items like boosts/banana obstacle, coins
  • Scriptable Object based item system, which is extendable
  • Setting up rooms as a host using codes for clients to join, handles edge-cases like "room not found", "room is full", "room is currently in a session" and so on.

Folder Structure

The main Scripts folder /Scripts has subfolders including Networking and Fusion Helpers which pertain to networking specific components, while the other subfolders contain the various interfaces and manager components, etc, which govern the gameplay.

Game Launcher

The GameLauncher.cs class is responsible for setting the user as a Host or Client depending on which option they select from the Playmode menu. It holds a reference to the UI and is responsible for governing things like spawning players, despawning players, and shutting down.

First-Time Launch

When launching the sample for the first time, users will be prompted to supply a nickname (if desired) and select a Region. This screen can be accessed at any time from the Options Menu. The nickname provided is used in three places:

  • When a user creates or joins a room a UI item is instantiated with their supplied nickname.
  • The nickname is instantiated above each kart during a race in a world-space canvas.
  • In the results screen at the end of a race, the nickname is used to show 1st, 2nd, 3rd place and so on.

Rooms

The Fusion Karts sample uses rooms, an abstraction on top of Photon Cloud Sessions. For this sample, a maximum of 8 users can connect to a room at once. This cap can optionally be set to between 1 and 8.

Creating A Room

The CreateGameUI script stores a reference to the various UI elements under the Create Room Screen found in the Canvas hierarchy. The Input field for the Room Code will set an ID for this room. When a user tries to join a lobby they will be prompted with a similar input field and must present a recognised code. The slider for the Player Count allows hosts to clamp the number of users in the room by setting ServerInfo.MaxUsers in the CreateGameUI script. There are two different Game Modes and also two different Tracks included in the sample which can be selected during room creation via the following methods which set the appropriate integer values in ServerInfo.cs:

C#

    public void SetGameType(int gameType)
    {
        ServerInfo.GameMode = gameType;
    }

    public void SetTrack(int trackId)
    {
        ServerInfo.TrackId = trackId;
        trackImage.sprite = ResourceManager.Instance.tracks[trackId].trackIcon;
    }

Joining A Room

To join a room a user must provide a room code. If a user tries to join a room that doesn't exist they will prompted with a UI message to indicate such. A user is not able to join a room that is currently in a session and must also ensure they are in the same Region as the room they are trying to connect to. The JoinGameUI script holds a reference to the input field to supply the required code. The confirm button is made uninteractable if there is no text supplied in the input field, as creating a room with no code is impossible.

C#

    private void SetLobbyName(string lobby)
    {
        ClientInfo.LobbyName = lobby;
        confirmButton.interactable = !string.IsNullOrEmpty(lobby);
    }

Readying up

The ready state of each user is displayed beside their nickname in the player list, with a user being ready signified by a green checkmark. All players must first ready up before the race is allowed to begin. The EnsureAllPlayersReady function in LobbyUI.cs is subscribed to the PlayerChanged event of each RoomPlayer NetworkBehaviour, whose IsReady networked property invokes via the OnChanged callback provided through Fusion's Networked attribute. When called, the function checks that each RoomPlayer has its IsReady boolean set to true, and then calls LevelManager.LoadTrack with the sceneIndex parameter set to the corresponding index for the selected track. This method sets Fusions active scene which in turn invokes the registered scene object provider.

Handling Input

This sample uses the new Input System, and leverages the InputAction class to handle support for both keyboard and gamepad controls. The new Input System to make supporting various controllers easy. There is keyboard and joystick support out of the box, including haptic feedback.

Keyboard

  • A and D or Left and Right Arrow Keys to Steer
  • W or Up Arrow Key to Accelerate
  • S or Down Arrow Key to Reverse
  • Alt to Look Behind
  • Space to Hop/Drift
  • Shift to use Horn/Item

Gamepad

  • Left Analog stick to Steer
  • South Button to Accelerate
  • East Button to Reverse
  • D-Pad Down to Look Behind
  • Right Bumper to Hop/Drift
  • Left Bumper use Horn/Item

(supports controller rumble)

Karts

Karts are comprised of many individual behaviours, all deriving from KartComponent , with a KartEntity serving as a hub between them and providing periphery. The components are:

  • KartAnimator - references to the Animator component, visual elements such as particle systems and trails, and methods for playing animations and effects.
  • KartAudio - references to each persistent audio source on the kart, and responsible for the engine pitch and volume, and playing the drifting audio.
  • KartCamera - controls the camera perspective, field of view, and speed lines particle system
  • KartController - most of the logic and networking occurs here; acceleration, steering, drifting and boosting, as well as rotating the wheels and orienting to the road.
  • KartInput - polls for input locally and handles InputAction enable/disable and callbacks
  • KartLapController - handles the current lap and checkpoint for the kart
  • KartItemController - handles the behaviour when pressing the use item button

Additionally, KartEntity holds a reference to the GameUI HUD interface, which is not in itself a part of the component structure, but provides a way to outwardly reflect the state of the kart to the player.

Pickups

Pickups is the term used in this sample to label the loosely-defined set of entities with which karts can interact. All pickups implement the ICollidable interface, and specific behaviour is dictated by the ICollidable.Collide implementation. The KartEntity is responsible for initiating the interaction, which is carried out in the OnTriggerStay method, and to which a reference to the KartEntity instance is passed. The use of OnTriggerStay is due to the unreliable nature of the OnTriggerEnter function in a network context.

  • Coins: Coins serve no functional purpose in terms of gameplay, but have the function of demonstrating a basic entity which can be collected by a single player, are despawned, and subsequently add to a counter which is displayed in the UI.
  • Item Box: While not being a pickup themselves, item boxes also implement ICollidable to facilitate their behaviour. Item boxes are responsible for assigning a Powerup to a kart when hit, via the KartEntity.SetHeldItem method.

Powerups

Powerups are a special kind of pickup which is obtained from item boxes, and can be used at an arbitrary time after collection per the player's discretion.
There are two components constituting a powerup; the Powerup ScriptableObject, and the abstract SpawnedPowerup class.
SpawnedPowerup inherits from ICollidable and implements ICollidable.Collide virtually, so as to be an optional implementation for derived classes. A virtual Init method is also provided for optional initialization, which is invoked immediately after being spawned by the Powerup.Use method.

  • Banana: When used, the banana is dropped behind the kart as a physical entity, and acts as a hazard for players. The BananaPowerup overrides SpawnedPowerup.Collide to facilitate spinning out a kart which has run over it.
  • Boost: Provides an instant level 2 boost. The boost powerup has no physical representation like the banana does, and as such despawns promptly after the boost has been given.
Back to top