PUN Rally Tutorial 106

download PUN Rally Tutorial 106

of 35

Transcript of PUN Rally Tutorial 106

  • 7/24/2019 PUN Rally Tutorial 106

    1/35

    E R I C K P A S S O S A N D W A N S O U Z A

    P U N R A L L Y

    M U L T I P L A Y E R R A C E R T U T O R I A L B Y S E R T O G A M E S

  • 7/24/2019 PUN Rally Tutorial 106

    2/35

    Copyright 2016 Erick Passos and Wan Souza

    published by serto games

    sertaogames.com

    Licensed under the Apache License, Version 2.0 (the License); you may not use this file except in compliance

    with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.Unless required by applicable law or agreed to in writing, software distributed under the License is distributed

    on an as is basis, without warranties or conditions of any kind , either express or implied.

    See the License for the specific language governing permissions and limitations under the License.

    Tutorial Version 1.0.6, February 2016

    http://www.apache.org/licenses/LICENSE-2.0http://www.apache.org/licenses/LICENSE-2.0http://www.apache.org/licenses/LICENSE-2.0
  • 7/24/2019 PUN Rally Tutorial 106

    3/35

    Contents

    1 Introduction 5

    2 Basic Photon Network Concepts 9

    3 Multiplayer Car Physics 17

    4 Racing Gameplay Control 25

    5 Conclusion 33

    Bibliography 35

  • 7/24/2019 PUN Rally Tutorial 106

    4/35

  • 7/24/2019 PUN Rally Tutorial 106

    5/35

    1Introduction

    This document is the accompanying tutorial for PUN Rally,

    a multiplayer racing game project for the Unity 3D engine. The project

    can be obtained from Unitys Asset Store, and comes complete with

    source code and assets. Figure 1.1: PUN Rally is a multiplayerracing game the is distributed as a com-plete project on Unitys Asset Store. The

    game source code, which is fully com-mented (and complemented by this tuto-rial), teaches you how to develop a rac-ing game with realistic physics, smoothnetwork synchronization with dead reck-oning, lobby, rooms, and RPCs for GUIand gameplay control.

    PUN Rally uses Photon Unity Network (PUN) to handle the mul-

    tiplayer bits of the game; and Unitys built-in PhysX for simulatingrealistic car physics. The project is a good starting point for dealing

    with the challenges of developing multiplayer racing games.

    In this chapter, we introduce Photon Network, talk about some fea-

    tures of PUN Rally, and give you more details about the tutorial con-

    tents.

    What Photon does

    Photon is a complete network solutionfor multi-player games,

    featuring seamless integration with several platforms (including of course

    Unity), real-time cloud-based communication, match-making and many

    more.

    Figure 1.2: PUN is the easiest way todevelop your multiplayer game in Unity.Each game client connects to the cloudservers that are used to relay communi-cation even in firewalled environments.

    PUN (Photon Unity Network) is a Unity plug-in that makes building

    multi-player games with this powerful engine a breeze. It gives you full

    access to Photon cloud-based relay servers, so your multiplayer game

    clients are guaranteed to communicate even under firewalls or NAT In-

    ternet access.

    There are of-the-shelf options for 3d object synchronization (for real-

    time games) and remote procedure calls (good for turn based games or

    other types of messages between peers, such as chats, inventory items,

    etc).

  • 7/24/2019 PUN Rally Tutorial 106

    6/35

    6 erick passos and wan souza

    The PUN Rally Game

    PUN Rally is a multiplayer racing game for up to 4 (four)

    players. You choose a nickname, decide to host or join a race, pick

    your car color, and race to the finish against other players. It is a

    straightforward racing game that demonstrates what you can do with

    Photon for Unity. Controls are simple: use the arrow (or WASD) keys to

    control throttle, braking and steering, while space is the handbrake and

    left shift flips the car back up if you happen to roll it over (remember

    were using realistic physics).Figure 1.3: Car color selection interface.We use the PUN player-properties featureto store and synchronize each players se-lected car color to all client computers.Choosing the color actually defines a carprefab for the player, so you can easilyuse this feature to have different cars forthe player to choose from in your game.

    The game was released as a complete project for the Unity Asset

    store, so you can learn by studying the source code together with this

    tutorial. The code was designed and written to be simple to under-

    stand yet fully functional. We tried to use standard assets as far as we

    could, and the game features all the basic concepts for a good racing

    multiplayer:

    Easy-to-setup realistic car physics based on standard wheel colliders,

    rigidbody and only a few custom scripts;

    Real-time car synchronization with dead-reckoning (prediction of move-

    ment even under network instability);

    Peer-to-peer communication with distributed load (each peer only

    computes complete physics for the local players car);

    Race lobby, with nickname, create/join race and car color selection

    (see Figure1.3);

    Complete GUI including an end-of-race summary with positions and

    individual race times;

    Simple project structure with only two scenes and easy-to-extend

    features;

    (new - bate) A simple weapon system using the same over-the-internet

    features of the physics, good as a template for combat-based games;

    What to Expect from this Tutorial

    The goal of this tutorial is to teach you how to use PUN to

    create a basic multiplayer racer. It is expected that you have familiarity

    with the Unity 3D engine and the C# programming language.

    You will also need to create a free account for the Photon Cloud

    service (we included the instructions for this in the next chapter) before

  • 7/24/2019 PUN Rally Tutorial 106

    7/35

    pun rally 7

    testing your game project, so it can connect to the relay servers that

    handle network communication.

    The project has only two Unity scenes, Menuand Race, designed to

    teach you the basics for using PUN in different situations. The following

    subjects are explored in the project code, tutorial and accompanying

    video, so you can expect to learn about them after reading the tutorial(and testing/modifying the project):

    Setting up realistic car physics with Unitys standard wheel colliders,

    rigidbody and a few custom scripts. You are especially encouraged to

    play with the car parameters found in the CarControllerscript and

    wheel colliders (see Figure1.4), so you can learn by experimenting;

    Figure 1.4: We used Unitys stock stan-dard assetsCarControllerand played withthe parameters to achieve a buggy-likebehavior for the car. Try to modify themor even dare to completely overhaul ourparameters and 3D models, making yourgame feel unique.

    Using PUN to synchronize the cars of several players over the In-

    ternet. In PUNRally, each client computer is responsible for com-

    puting the physics of the local players car and synchronizing it with

    the remote clients (other players computers). You will learn how to

    synchronize position and rotation while keeping a fair load balancebetween peers;

    Using dead-recknoning techniques to handle network instability, so

    remote cars race smoothly even in the presence of latency. You will

    also learn how to make the wheels, fx, accell and braking look realistic

    for remote cars by synchronizing input;

    Other basic PUN concepts such as Remote Procedure Calls (RPCs),

    lobbies, rooms, player properties and error handling are used and

    explained in various parts of the project, such synchronizing car color

    choices, spawn points, raing positions, player disconnections, etc.

    The Next Chapters

    Next chapter introduces PUN basic concepts and teaches

    you how to handle connection to Photon Cloud, lobbies, and dealing

    with players joining and creating rooms; The following chapter brings

    the discussion to the physics simulation of the cars and how to syn-

    chronize its state, input and fx between game clients in a fluid manner

    using dead-reckoning; After that, we explain other important features

    such as race control, position calculation, and the weapon system on a

    multiplayer racing game. Finally, in the concluding chapter, we presentsome ideas for future improvements of your own racing game (and a

    few directions on how to develop them). We remember that some im-

    portant features of a more complete racing game are not included such

    as: AI drivers, (controversial) rubber-band physics, balancing cars with

    different characteristics, etc.

  • 7/24/2019 PUN Rally Tutorial 106

    8/35

  • 7/24/2019 PUN Rally Tutorial 106

    9/35

    2Basic Photon Network Concepts

    Figure 2.1: The PhotonServerSettingsasset is located inside the Assets/PhotonUnity Networking/Resourcesfolder. Justclick on it to access its properties.

    Developing a multiplayer game involves a lot of things besides

    synchronizing 3D objects data. In this chapter we give you a first glimpse

    on the basic stuff that you need to setup PUN for your Unity project,

    and then teach you how to deal with connecting to Photons lobby; room

    creation/joining; using player properties to handle car color selection,

    updating GUI on player connection, etc.

    Setting up PUN for your project

    Figure 2.2: Here youll only need to fillyour AppID (see main text), but you cancheck other the other properties: Hostinglets you choose the type of service. Welluse Photon Cloud here, since this is theeasiest one, but depending on your plan,you can even host your own authorita-tive servers. You can choose yourregion,which will give you the best latencies de-pending where your players are, and theprotocol. We chose UDP for its good

    performance. The RPC list shows allRPC methods you have in your project.

    If youve downloaded the project from the Asset Store and

    opened it, you still need to configure PUN to use your personal creden-

    tials to connect to the Photon servers. The process is very straightfor-

    ward: there is an asset in PUNs bundle that holds the server connection

    settings. Figure2.1 shows where you can find the asset, named Photon-

    ServerSettings.

    The PhotonServerSettingsasset has all the properties you need con-

    figured to use the Photon Network services. Figure 2.2 explains the

    properties. The most important one for us is the AppID, which is a

    unique identifier for your game. Well tell you how to create one now.

    Figure 2.3: The realtime dashboard,showing your newly created AppID.

    Now you need to configure Photon Cloud to act as your multiplayer

    games communication platform. Its simple and you can setup a free

    plan, so your players can race against each other. Follow these steps to

    have it done:

    If you dont have a user account yet, go to https://www.photonengine.com/

    and create one;

    Now follow on to your realtime dashboard and click on the Create

    new realtime App at the bottom of the page;

    Fill in your application name (there are other fields as well but theyre

    optional) then click createto register your app.

    Thats it, you can now see your newly registered application and

    its AppID (see Figure 2.3 for reference). You can change your billing

  • 7/24/2019 PUN Rally Tutorial 106

    10/35

    10 erick passos and wan souza

    plan at anytime (it defaults to the free plan, which is perfectly good for

    development and small-scale testing).

    Remember to copy the AppID and fill it in the correspondent prop-

    erty on your PhotonServerSettingsasset, as shown in Figure 2.2. Youre

    ready to test your game. Open the Menuscene and hit play.

    Connecting to lobby and creating/joining rooms

    Now, lets see how Photon handles multiplayer games.

    There are two important concepts that you need to understand to de-

    velop a multiplayer game with Photon: lobby and rooms. The lobby is

    a virtual place where players connected to (and stay) before entering or

    creating a room. A room is where a multiplayer game actually happens,

    this time to a smaller sub-group of them.

    Figure 2.4: If you can see this screenit means PUN Rally correctly joined thelobby.

    The lobby is normally unique for each game, so every player who

    connects to the Photon Cloud service within your game will be in thesame lobby. The exception is that you might want to have separate

    lobbies for different versions of your game. Lets say your latest updated

    version is not compatible with the old one: you might use a new lobby

    for the updated release, so players with both versions are able to play

    (only not together).

    Now wed like to show you how PUN Rally deals with connecting to

    the Photon servers, entering the lobby (using an initial ID/version) and

    enabling the players to create or join rooms. In PUN Rally, each room

    a player creates represents a race, and is configured to accept up to four

    (4) players, including the creator (called the master client, if you learn

    to speak Photonish).

    Figure 2.5: The PUN Menuscript in thePUNMenuController game object holdsthe references to all GUI elements intheMenuscene and manages connection,lobby, and room creation/joining by play-ers. Notice the PhotonView componentas well, which is needed because we use

    RPCs, explained in the next section.

    In the Menuscene, there is a game object named PUNMenuCon-

    troller, which has the PUNMenu script attached to it. This script has

    several attributes that are used to hold references to GUI elements that

    need to be enabled, disabled and managed (see Figure 2.5). The order

    in which the GUI elements are enabled and used is associated with the

    sequence of network events that happen in the game, which are listed in

    the following table:

    Event GUI elements and actions

    Enters nickname connects and joins lobby

    Joined lobby create-room button; rooms-listCreated/joined room car-selection; player-list; start-buttonPressed start load race scene

    Now open the PUNMenu script in the editor and look for the En-

    teredNicknamemethod, called when the player types a nickname. It has

    the code needed to connect to the Photon servers and looks like this:

  • 7/24/2019 PUN Rally Tutorial 106

    11/35

    pun rally 11

    p u bl i c v o id E n t er e d Ni c k n am e ( ) {

    P h o t o n N e t w o r k . p l a y e r . n a m e =

    e d t N i c k n a m e . t e x t ;

    P h o t o n N e t w o r k . C o n n e c t U s i n g S e t t i n g s (" v 1 . 0 " ) ;

    }

    The code basically calls the method ConnectUsingSettings 1 using 1 Well keep the code examples in this tu-torial very small, so we can explain eachimportant method. We also recommendyou to take a deeper look in the code,which is fully commented. We tried tokeep all scripts fairly small, but some ofthem, especially the ones that deal withGUI, can be a bit long.

    an initial version name as parameter, as explained earlier. It also sets

    the string "Connecting..."to a GUI label, so the player knows whats

    happening. When connected and having joined the master lobby, the

    following callback is invoked by PUN 2:

    2 Notice that were using the override key-word. It means this behaviour extendsthe provided PunBehaviour, getting thevirtual implementations os PUNs call-backs.

    / / W he n c o nn e ct e d t o P ho to n L ob by , d i sa bl e

    n i c kn a m e e d it i n g a n d m e ss a g es t ex t , e n a bl e s

    r o om l i st

    p u bl i c o v e rr i d e v o id O n J oi n e dL o b by ( ) {

    n i c k P a n e l . g a m e O b j e c t . S e t A c t i v e ( false ) ;

    m e s s a g e s . g a m e O b j e c t . S e t A c t i v e ( false ) ;

    r a c e s P a n e l . g a m e O b j e c t . S e t A c t i v e ( true ) ;

    }

    The methodOnJoinedLobbyis one of many callbacks PUN has to deal

    with network events 3. We use this one to manage some GUI elements. 3 PUN has several method callbackswhich are called in network events suchas lobby joining, room creation/joining,player connection, etc. Well use themextensively in this tutorial. Youre en-couraged to read PUNs documentationand other examples so you can feel con-fident about them.

    In this case, we disable the messages label, and enable the GUI panel

    containing the nickname edit-field and OK button, so the player can

    type his name in.

    Then, the existing room listing is enabled (see Figure 2.6). The OK

    button was set to call a method in the PUNMenuscript that enables

    the room listing panel, which also contains a button for the player to

    create a new one.We chose to have a static list of up to 4 GUI elements for available

    rooms, which are filled with the data from the first ones returned by

    PUN. If there are less then 4 available, the remaining GUI elements are

    disabled. We use the method GetRoomListto list the available rooms

    and fill the GUI elements with their data with the following code, part

    of the OnGUImethod in the PUNMenuscript:

    Figure 2.6: This panel shows a list ofup to 4 available rooms/races, each oneshowing the number of connected play-ers. There is also a button for the playerto create a race.

    in t i nd ex = 0;

    foreach ( R o o m In f o g a me in

    P h o t o n N e t w o rk . G e t R o o m L i s t ( ) ) {

    if ( i n d ex > = r o o mB u t to n s . L e n gt h )

    break ;

    R o o mJ o i ne r b u tt o n = r o o mB u t to n s [ i n de x + + ];

    b u t t o n . g a m e O b j e c t . S e t A c t i v e ( true ) ;

    b u tt o n . R o om N a me = g a me . n a m e ;

    string i n fo = g am e . na me . T ri m () + " ( " +

    g a me . p l a y e rC o u nt + " / " +

  • 7/24/2019 PUN Rally Tutorial 106

    12/35

    12 erick passos and wan souza

    g a me . m a x P l ay e r s + " ) " ;

    button.GetComponentInChildren ().text

    = i nf o ;

    }

    To actually join a room, we created a simple script calledRoomJoiner

    that is attached to each of the four available room button game objects,which also have a ButtonGUI component. The script has a single prop-

    erty named RoomName, which is filled with the room name as just

    shown in the code above. When a room button is clicked, the following

    method is called in the RoomJoinerscript, which tells PUN to join the

    correspondent room 4: 4 This code also implies that the clientmachine that is joining a room will waituntil this operation is completed by Pho-ton, which then executes the OnJoined-Room callback (see next notes an followthe main text for more details.

    / / C al le d w he n t hi s r oo m - b u tt on i s c l ic ke d

    p u bl i c v o id J oi n () {

    P h o t o n N e t w o r k . J o i n R o o m ( R o o m N a m e ) ;

    }

    On the other hand, if the player clicks on new race button instead,the following code is called in the PUNMenuscript, which tells Photon

    to create a room for up to four players, using the players nickname as

    room name:

    p u bl i c v o id C r e at e Ga m e ( ) {

    R o o mO p t io n s o p ti o ns = ne w R o o m O p t i o n s ( ) ;

    o p ti o n s . m a xP l a ye r s = 4 ;

    P h o t o n N e t w o r k . C r e a t e R o o m ( e d t N i c k n a m e . t e x t ,

    o p t io n s , T y p e d L o b b y . D e f a u l t ) ;

    }

    Both when joining a room or creating a new one, the OnJoinedRoomevent callback is called in PUNMenu5 , which enables the player list and 5 Only when creating a new room, the

    OnCreatedRoom callback is called beforeOnJoinedRoom, the contents of whichare similar to another callback, so we de-cided not to explain it right now.

    car color selection panel, which are explained in the next section.

    Managing players

    After a player creates or joins a room, Photon is actually

    ready to synchronize game objects attributes and exchange messages

    between the client computers in the same room. Before starting the

    proper race, which is another Unity scene, we still want the player to be

    able to choose the car color and see who else he will be racing against(see Figure2.7).

    Figure 2.7: This panel shows a list ofthe players currently connected to theroom/race. The local player can selecthis car color, and only the master client(the one who created the room) can startthe race.

    There are two important attributes we want to keep for each player in

    the lobby (besides the nickname, of course), which are the selected car

    color, and the order in which they will be placed at the start of the race

    (this will be use to place each car in its correspondent spawn point).

  • 7/24/2019 PUN Rally Tutorial 106

    13/35

    pun rally 13

    The master client computer is responsible for setting the spawn posi-

    tion for each connected player. Selecting the car, however, has to be an

    option for each player. We made use of Photons custom player proper-

    ties for both.

    Custom player properties

    Custom player properties are a collection of values

    (each associated to a key - hence a Hashtable), that is attached to every

    connected player. PUN uses its own implementation ofHashtable for

    custom properties, and the most convenient feature of it is that when

    you update the properties of a certain connected player in one computer,

    all others are synchronized and receive the updated properties for the

    player in question 6. 6 Every client computer connected to thesame room has an updated list the cor-respondent player objects (instances of

    thePhotonPlayer class). Storing individ-ual properties in them is very useful be-cause there are straightforward methodsfor listing all players, or only the localone, and also checking if a player is themaster client, etc.

    We implemented a method namedSetCustomPropertiesto handle the

    two custom properties we use for the player who creates a room, now themaster client, and for every other player that connects to that room. As

    default,caris set to zero (0) and positionis set as the current number of

    players minus one. The following code shows the two callback methods

    in PUNMenuthat call SetCustomProperties for the master client (the

    one who creates the room), and for every other player who joins that

    room 7: 7 Notice the if branch that makes surecustom properties are handled by themaster client computer only. Most call-backs are invoked in all client computers(see Photons documentation for moredetails), so we need to pay attention tothis.

    p u bl i c o v e rr i d e v o id O n C re a t ed R o om ( ) {

    b t S t a r t . g a m e O b j e c t . S e t A c t i v e ( true ) ;

    S e t C u s t o m P r o p e r t i e s ( P h o t o n N e t w o r k . p l a ye r ,

    0 , P h o to n N e tw o r k . p l a ye r L is t . L e n gt h - 1 ) ;

    }

    p u bl i c o v e rr i d e v o id O n P h o t o n P l a y e r C o n n e c t e d

    ( P h o t on P l ay e r n e w Pl a y er ) {

    if ( P h o t o n N e t w o r k . i s M a s t e r C l i e n t ) {

    S e t C u s t o m P r o p e r t ie s ( n e w P l ay e r , 0 ,

    P h o t o n N e t w o r k . p l a y e r L i s t . L e n g t h

    - 1) ;

    p h o t o n V i e w . R P C (" U p d a t e P l a y e r L i s t " ,

    P h o t o n T a r g e t s . A l l ) ;

    }

    }

    The actual SetCustomPropertiesmethod, shown bellow, updates the

    custom player properties 8, receives the values for car color index (we 8 The Hashtableused for custom proper-ties can store any type of object both askey and as value, so be very careful oryou might get confused with the types.

    have 6 different colors, so the index ranges from 0 to 5), and index for

    the players spawn position.

  • 7/24/2019 PUN Rally Tutorial 106

    14/35

    14 erick passos and wan souza

    p r iv a te v o id S e t C u s t o m P r o p e r t i e s ( P h o t o n P l a y e r

    player , in t c a r , int p o s it i o n ) {

    E x i t G a m e s . C l i e n t . P h o t o n . H a s h t a b l e

    c u s t om P r o pe r t i es = ne w

    E x i tG a m es . C l i e nt . P h o t on . H a s h t ab l e ( ) { {

    " s p a w n " , p os it io n } , { " c a r " , c ar } };p l a y e r . S e t C u s t o m P r o p e r t i e s ( c u s t o m P r o p e r t i e s ) ;

    }

    When player properties are changed, the methodOnPlayerPropsChanged

    is called in all clients (see source code bellow), which basically calls for

    the player list to be updated on the GUI:

    p u bl i c o v e rr i d e v o id

    O n P h o t o n P l a y e r P r o p e r t i e s C h a n g e d ( object []

    p l a y e r A n d U p d a t e d P r o ps ) {

    U p d a t e P l a y e r L i s t ( ) ;

    }

    Figure 2.8: These are the car prefabs inPUN Rally. Theyre all the same, exceptfor the color, but they could be com-pletely different cars in behavior, proper-ties and visuals. When a player changesits car color, we actually change a colorindex number, which is used to decidewhat car prefab is loaded in the race, sothis feature can be extended for selectingactually different cars.

    Car selector

    Players love to customize their ridesin racing games. Choos-

    ing car model and make; custom painting; applying special parts and

    accessories or changing suspension and engine parameters are common

    examples of this trend.

    We wanted to give you a glimpse on how this can be done with pho-

    ton, so we included the option for the player to select the car color 9. 9 We included in the scripts a templatecode for synchronizing custom colours to

    be applied in car materials and its remotecopies. Take a look at CarGUI.cs andthe CreateCar method in PunRaceMan-ager.cs.

    Underneath, by picking a color, the player is selecting which car prefabwill be instantiated when the Racescene is loaded (see Figure 2.8).

    When called, the UpdatePlayerListmethod that we discussed in the

    previous section, enables two arrow-like buttons only for the local player

    car icon. These buttons are set to execute, when pressed, the methods

    shown below, which increment or decrement a color index:

    p u bl i c v o id N e x tC a r ( ) {

    c ar In de x = ( c ar In de x + 1) %

    c a r T e x t u r e s . L e n g t h ;

    S e t C u s t o m P r o p e r t i e s ( P h o t o n N e t w o r k . p l a ye r ,

    car , ( in t )

    P h o t o n N e t w o r k . p l a y e r . c u s t o m P r o p e r t i e s [" s p a w n " ])

    }

    p u bl i c v o id P r e v i ou s C ar ( ) {

    carIndex --;

    if ( c a rI nd e x < 0 )

  • 7/24/2019 PUN Rally Tutorial 106

    15/35

    pun rally 15

    c a r In d e x = c a r Te x t ur e s . L e ng t h ;

    S e t C u s t o m P r o p e r t i e s ( P h o t o n N e t w o r k . p l a ye r ,

    car , ( in t )

    P h o t o n N e t w o r k . p l a y e r . c u s t o m P r o p e r t i e s [" s p a w n " ])

    }

    Both methods callSetCustomPropertiesin the end, which is responsi-ble for updating the local players custom properties with the new color

    index chosen. Remember that Photon synchronizes player properties to

    all client computers in the same room.

    Another interesting option would be to have the car prefabs, with

    controls disabled, in a carousel for the player to chose. This would be

    similar in implementation, but with a nicer look, and with the possibility

    to show more detailed features of each car in the GUI, such as engine

    power and other attributes. We encourage you to try this for your own

    game.

    Track Selection

    To select different tracks, were using the same principle used

    for the car selector: a local variable (an attribute in PUNMenu.cs) to

    store the currently selected track number. The methods NextTrackand

    PreviousTrackare accessible from the GUI (for the master client only,

    the creator of the race).

    To synchronize the selected track number, we use a Remote Procedure

    Call (RPC), a feature that is explained in the following section, together

    with

    Loading Scenes

    When is time to start the race, the player who created the

    room will press a button. But we still need to send this command to

    all other client computers, so everyone will load the same Unity scene.

    We accomplish this by the use of Remote Procedure Calls (RPCs). The

    following code, which runs in the master client, shows the GUI call-

    back that asks Photon to remotely execute another method in all client

    computers:

    p u bl i c v o id C a l l L oa d R ac e ( ) {

    p h o t o n V i e w . R P C (" L o a d R a c e " ,

    P h o t o n T a r g e t s . A l l ) ;

    }

  • 7/24/2019 PUN Rally Tutorial 106

    16/35

    16 erick passos and wan souza

    RPCs, as the name implies, are a technique to remotely execute some

    function, method or procedure. In Photon, RPCs are used to execute

    the same method in several computers on the same room. The last

    argument in the RPCmethod even serves to tell in which computers we

    want the desired method to be executed. As shown above, in this case

    we want all connected playerscomputers, including the master clientthat is asking for this execution 10. 10 Methods called by RPC can have pa-

    rameters too, in which case there is athird argument that is a collection of ob-

    jects - the parameter values.

    For a method to be called by RPC, it has to be marked accordingly

    with the PunRPCannotation. The following code shows how this is

    done for the LoadRace method, which makes all computers load the

    same scene, that represents the selected track ("Race" + trackIndex:

    Race0, Race1 or Race2 in our example project) 11: 11 Notice that we use the PhotonNet-work.LoadLevel function instead ofUnitys usual Application.LoadLevel.This is important because we mightneed to instantiate game objects syn-chronously in the race scene, and wedface issues because of network and local

    disk latency causing clients to load atdifferent times. By using this version ofthe LoadLevel method, Photon takescare of delayed clients and makes sureall instantiations happen correctly.

    [ P u n R P C ]

    p u bl i c v o id L o ad Ra c e ( ) {

    P h o t o n N e t w o r k . L o a d L e v e l (" R a c e " +

    t r a c k I n d e x ) ;

    }

    Now that we loaded our race scene corresponding to the selected track,

    lets talk about car physics and understand how a the proper multiplayer

    racing simulator part works.

  • 7/24/2019 PUN Rally Tutorial 106

    17/35

    3Multiplayer Car Physics

    Racing games are a very popular genre, and one we in par-

    ticular like a lot. With the advances in computer games tech over the

    last decades, two main approaches are generally identified: arcade and

    simulators. Arcade racers are all about fun, without any respect to

    coherent physics models, etc.Figure 3.1: The car behavior in a simu-lator has to be predictable in the way areal car is. Even without a proper dam-

    age model, when colliding against a wall,the car shouldnt fly or explode, but ac-tually change its speed accordingly andmaybe sppining out of control dependingon the angle of attack. This is why it is agood approach setting up the car with arigigbody physics engine, such as Unitysbuilt-in PhysX.

    Simulators, on the other hand, are all about being similar to the real

    world. The physics have to feel like a real (or at least imaginable) car

    would. If the car rolls over, it has to do in a manner that is coherent.

    Ideally, we should be able to set any car parameter in the same way we

    do in real cars, and they should be deformable too (but this deserves its

    own tutorial).

    We decided to follow the simulator route, although a very simple one

    for that matter. In this chapter, well show you how we managed to deal

    with two challenges that come with this choice:

    Setting up and calibrating a reasonably realistic car using the physics

    engine without any type of cheating (such as fake acceleration or

    braking forces, below ground centers of mass, etc);

    Synchronizing these cars among all client computers in the race as

    smoothly as possible, also keeping the wheel behaviors and fx coherent

    (if a player turns his car wheels right, all other players should see the

    wheels of his car turning in their own computers as well).Setting up the car behavior is the mostchallenging task in creating a racinggame, and the one you probably spendmost of your time. We do recomend youto start a racing game by doing this, be-cause youll need time to have it right.In this tutorial, we started talking aboutlobbies and rooms because thats what

    comes first for the player, but we actu-ally started of by creating and tweakingthe cars, and we still do.

    Car Physics 101

    The way a car feels to drive is the most important thing a

    racing simulator, so this is the first thing you should make right. Inthis section, we will show how to assembly a physics based car using

    components that come bundled within Unity, and setting it up to feel

    more realistic. Even if you didnt like the feel of the car in PUN Rally,

    we recomend you to read this section to understand how you can make

    it the way you want.

  • 7/24/2019 PUN Rally Tutorial 106

    18/35

    18 erick passos and wan souza

    Structure of a physics car

    Without its wheels, a car is basically a rigidbody , and

    considering were not implementing a complex damaging model (even

    Gran Turismo doesnt do it properly), this is what we will start with: a

    game object with aRigidbodycomponent attached to it (see Figure3.2).

    Figure 3.2: The components of the toplevel car game object: the rigidbody willbe used to simulate the physics of the

    car body, with a proper mass, and let-ting PhysX do all the heavy work. Allcomponents are standard and come bun-dled with Unity, except for the disabledscripts, which we developed for the tuto-rial and will explain one by one.

    We also attach separate box colliders to the car structure and set them

    up to resemble the car shape. This will make the rigidbody use them as

    its bounds, and is lighter than having a complex mesh collider. For the

    wheels, there is a special type of collider, the WheelCollidercomponent,

    that works by casting rays downwards (from the cars local coordinate

    system perspective). Look at the figure bellow and see how the box

    colliders are set. Remember to make them non overlaping, because this

    would mess up the computation of the center of mass:

    Besides the box and wheel colliders, game object hierarchy of the

    car includes the visual meshes (remember that wheel meshes should

    be separate than the body) and some particle FX that we kept from

    Unitys standard assets example car. That is basically it. You can see

    this hierarchy in Figure3.3.

    Figure 3.3: Hierarchy of the car gameobject.

    Controlling the car

    A car moves by having torque applied to its wheel colliders.

    This will instruct PhysX to compute friction and forces, resulting in the

    car body moving, rotating and the wheel colliders to change position

    (up and down).

    The engine will also compute the amount of slip and rotation of each

  • 7/24/2019 PUN Rally Tutorial 106

    19/35

    pun rally 19

    wheel, and this is fundamental because it lets you implement many nice

    features a real car has, such as limited slip differentials, AWD systems,

    etc.

    Figure 3.4: The cars suspension armsare a set of separate meshes that can bemoved independently of the rest of thecars visual. We created a script (Sus-pensionArm) and attached it to each armthat we wanted to move. The script usesa reference to the correspondent wheelcollider, so the suspension travel can becalculated and used to rotate the suspen-sion arm accordingly, so the suspensionmovement doesnt affect the physics atall, being actually computed based on thesimulation.

    For this tutorial, however, we stick to standard assets as much as we

    can, so were using Unitys CarController script to do this work. It is

    not optimal, but can be configured to AWD, FWD or RWD modes, andhas several parameters that can be changed to tweak the car. Well talk

    about some of them in the next section.

    The most important scripts that we implemented for the tutorial are

    CarInputand NetworkCar. CarInputallways sends input values to the

    standardCarControllerscript, but these come from two different origins:

    if this is the car controlled by the local player, the input comes from

    Unitys input system. If it is a remote car, the input will come from the

    NetworkCar script, which is explained in a later section. The following

    code from CarInputshows how this is done:

    void F i x e d Up d a te ( ) {

    / / I f c a r i s l o ca l ly c o nt r ol l ab l e , r e ad

    a nd c ac he p la ye r i np ut

    if ( c o n t r ol a b le ) {

    S te er =

    C r o s s P l a t f o r m I n p u t M a n a g e r . G e t A x i s (" H o r i z o n t a l " ) ;

    A cc el l =

    C r o s s P l a t f o r m I n p u t M a n a g e r . G e t A x i s (" V e r t i c a l " ) ;

    if

    ( C r o s s P l a t f o r m I n p u t M a n a g e r . G e t B u t t o n ( " F i r e 3 " ) )

    {

    U n f l i p ( ) ;

    }

    # if ! M O B I L E _ I N P U T

    H a nd b r ak e =

    C r o s s P l a t f o r m I n p u t M a n a g e r . G e t A x i s (" J u m p " ) ;

    #endif

    }

    / / A ll w ay s m ov e t he c ar , i n de p en d en t ly o f

    w e th e r t h e i n pu t v a lu e s

    / / c am e f ro m ( l oc al p la ye r o r r em ot e ) .

    c a r . M o v e ( S t ee r , A c ce l l , A c c el l , H a n d b r a ke ) ;

    }

    Car physics tweaks and perks

    Setting car parameters rightis subject of much debate in the

    Unity forums (and many other game developer communities as well). If

  • 7/24/2019 PUN Rally Tutorial 106

    20/35

    20 erick passos and wan souza

    youre going the simulator route as we are, these are the things to look

    for:

    Setting mass and center of mass as a real car. The center of mass

    should be as centralized as possible, otherwise the car will behave

    very erratically when rolling over 1 . You might want to dislocate it a 1 Many people set below ground centerof mass to avoid rolling over, but this ischeating - a normal car would roll overeasily as well, except that it has anti-rollbars, which we discuss below.

    bit in the direction where your car engine is;

    Figure 3.5: Anti-roll bars are also known

    as anti-sway bar, sway bar, and stabi-lizer bar. In real life, cars have anti-rollbars attaching left and right wheels of thesame axis, especially for independent sus-pensions. Their function is to distributethe load from the outside wheel to theinside one in a turn, avoiding too muchroll.

    Figure 3.6: One trick we learned froma mechanical engineer who works for amajor car maker is that you can changethe car grip by having different values forthe stabilizer bar torsion strength in thefront and rear axel. We set the front axisto roll more (less tortion strength), so thecar digs and has more grip on that axel.The rear tortion strength is higher, so thecar drifts more easily. Try to play withthese parameters and see what you cando.

    Setting up WheelCollider parameters. The radius, mass, spring,

    damper and target position must resemble those of a real car. The

    friction parameters, however, are a bit trickier, so we encourage you

    to start playing with spring and damper before digging into more

    comple stuff;

    Having a anti-roll bar script implemented and properly set (see Fig-

    ures3.5 and 3.6);

    Ideally, implemeting your own car controller script (Standard Assets

    one is very limited), and making sure you implement things such asbrake balance, engine torque curve, gears that affect wheel torque,

    wind resistance, traction control, etc. Doing all this is out of scope

    of this tutorial, but you can take a look at the Unity Forums. We

    also recommend you to search the internet for good references on car

    physics such as 2;

    2 Marco Monster. Car physics forgames. http://www.asawicki.info/Mirror/CarPhysicsforGames/

    CarPhysicsforGames.html , November2003

    Synchronizing remote cars

    In PUN Rally, each players computer is responsible for in-

    stantiating the car prefab for the local player, which is controlled bythe CarInputscript. Photon will instantiate a copy of this prefab in all

    the other players computers, but making these remote copies move and

    behave in sync with the local original doesnt happen automatically.

    The idea is pretty simple: run periodic updates that send transform

    data from the locally instantiated car prefab to all remote computers to

    be applied in the respective remote copies, which are moved around as

    kinematicrigidbodies. In this section, well see how PUN helps us to do

    this, and what is the data we need to synchronize to have the remote

    copies move smoothly and coherently.

    The PhotonView Component

    PUN comes with the PhotonViewcomponent, which takes care

    of synchronizing a game objects data, when attached to it. It comes

    of the shelf with the ability to synchronize the Transformcomponent

    http://www.asawicki.info/Mirror/Car%20Physics%20for%20Games/Car%20Physics%20for%20Games.htmlhttp://www.asawicki.info/Mirror/Car%20Physics%20for%20Games/Car%20Physics%20for%20Games.htmlhttp://www.asawicki.info/Mirror/Car%20Physics%20for%20Games/Car%20Physics%20for%20Games.htmlhttp://www.asawicki.info/Mirror/Car%20Physics%20for%20Games/Car%20Physics%20for%20Games.htmlhttp://www.asawicki.info/Mirror/Car%20Physics%20for%20Games/Car%20Physics%20for%20Games.htmlhttp://www.asawicki.info/Mirror/Car%20Physics%20for%20Games/Car%20Physics%20for%20Games.htmlhttp://www.asawicki.info/Mirror/Car%20Physics%20for%20Games/Car%20Physics%20for%20Games.html
  • 7/24/2019 PUN Rally Tutorial 106

    21/35

    pun rally 21

    properties, but well need to perform a more detailed synchronization

    technique, which well explain in the following sections.

    There are options for sending periodic synchronization (reliable and

    unreliable) or only when there is a property change (see Figure 3.7).

    Figure 3.7: The PhotonView component

    and its properties. For custom synchro-nization, we need to tell which compo-nent should be observed for changes andhave its callback executed. In our case,we set it to the NetworkCar script weimplemented. Notice that we chose theUnreliable observe option. This will tellPhoton to constantly synchronize cars us-ing a fast (but not reliable) network pro-tocol. There are option for reliable (notso fast) and on properties change only(also unreliable).

    Custom properties serialization

    The problem with synchronizing only Transform data with pe-

    riodic updates is that the position and rotation of the remote cars would

    change in a rate which is much lower than the actual frame-rate of the

    rendering and local physics, leading to heavy stuttering. Network la-

    tency only makes it worse, so we need a better option, given a racing

    game relies on smooth car movement.

    There is also the issue of synchronizing wheel rotation, steering, and

    special FX, which are computed based on wheel rotation and slip rates.

    Because of this, we implemented the OnPhotonSerializeViewcallback

    to send more data than only the Transform properties 3: 3 Besides the Transform position and ro-tation data, we synchronize there inputattributes, which will be used to spin andsteer wheels on the remote cars, and thevelocity vector from the cars Rigidbody,which will be used for dead recknoning.

    void O n P h o t o n S e r i a l i z e V i e w ( P h o t o n S t r e a m s t re a m ,

    P h o to n M e ss a g eI n f o i n fo ) {

    if ( s t r e a m . i s Wr i t in g ) {

    / / We o wn t hi s c ar : s en d t he o th er s

    o ur i np ut a nd t r an s fo r m d at a

    s t r e a m . S e n d N e x t ( ( float ) m _ C a r I n p u t . S t e e r ) ;

    s t r e a m . S e n d N e x t ( ( float ) m _ C a r I n p u t . A c c e l l ) ;

    s t r e a m . S e n d N e x t ( ( float ) m _ C a r I n p u t . H a n d b r a k e ) ;

    s t r e a m . S e n d N e x t ( t r a n s f o r m . p o s i t i o n ) ;

    s t r e a m . S e n d N e x t ( t r a n s f o r m . r o t a t i o n ) ;

    s t r e a m . S e n d N e x t ( r b . v e l o c i t y ) ;

    }

    else {

    / / R e mo t e c ar , r e ce i v e d a ta

    m _ C ar I n pu t . S t e er = ( float )

    s t r e a m . R e c e i v e N e x t ( ) ;

    m _ C ar I n pu t . A c c el l = ( float )

    s t r e a m . R e c e i v e N e x t ( ) ;

    m _ C ar I n pu t . H a n d br a k e = ( float )

    s t r e a m . R e c e i v e N e x t ( ) ;

    c o r re c t P la y e r Po s = ( V e c to r 3 )

    s t r e a m . R e c e i v e N e x t ( ) ;

    c o r re c t P la y e r Ro t = ( Q u a t er n i on )

    s t r e a m . R e c e i v e N e x t ( ) ;

    c u r re n t V el o c it y = ( V e c t or 3 )

    s t r e a m . R e c e i v e N e x t ( ) ;

  • 7/24/2019 PUN Rally Tutorial 106

    22/35

    22 erick passos and wan souza

    u p d at e T im e = T i me . t i m e ;

    }

    }

    Dead Reckoning

    Just sending these properties here and there doesnt do any-

    thing useful yet. We need to use them to smoothly update the remote

    cars, and find a way to compensate for network instability.

    Interpolation smoothing

    To avoid stuttering, we can use interpolation to smoothly update

    the car position and rotation over the course of a few frames. This will

    give time for Photon to send/receive the next synchronization update,creating a more fluid movement that can even mask variations in network

    latency. This would be a version of the FixedUpdatemethod with just

    interpolation:

    p u bl i c v o id F i x e d Up d a te ( ) {

    if ( ! p h o to n V ie w . i s M in e ) {

    t r an s f or m . p o s i ti o n = V e c to r 3 . L er p

    (transform.position ,

    correctPlayerPos ,

    T i m e . d e l t a T i m e ) ;

    t r a n s f o rm . r o t a t i o n =

    Q u a t e r n i o n . L e r p

    (transform.rotation ,

    correctPlayerRot ,

    T i m e . d e l t a T i m e ) ;

    }

    }

    However, an aggressive interpolation has a serious issue: any position

    update takes some time to reach the remote computers, and adding to

    this the interpolation that distributes the update over several frames

    makes the remote copies of the cars to always stay behind a few meters.

    Also, the larger the latency, worse the lag for remote cars.

    Using prediction

    Because of this, we cant be too aggressive with the interpolation, and

    find a better way to compensate for network instability. The idea is to

    try to predict where the car will be be in the next frames based on the

  • 7/24/2019 PUN Rally Tutorial 106

    23/35

    pun rally 23

    position, orientation, and the velocity vector that tells us the rate and

    direction the car is moving at the last update. This is the actual code

    that we use to update a remote car:

    p u bl i c v o id F i x e d Up d a te ( ) {

    if ( ! p h o to n V ie w . i s M in e ) {

    V e c to r 3 p r o j ec t e d Po s i ti o n =

    this . c o r r e ct P l ay e r P os +

    c u r re n t Ve l o c it y * ( T i me . t i m e -

    u p d a t e T i m e ) ;

    t r an s f or m . p o s i ti o n = V e c to r 3 . L er p

    (transform.position ,

    projectedPosition ,

    T i me . d e l t a Ti m e * 4 ) ;

    t r a n s f o rm . r o t a t i o n =

    Q u a t e r n i o n . L e r p

    (transform.rotation ,

    this .correctPl ayerRot ,

    T i me . d e l t a Ti m e * 4 ) ;

    }

    }

    We need two properties to compute the predicted position of the car in

    a certain frame: the velocity vector, and the time since the last update.

    The method above computes and stores the desired position for the car

    in the projectedPositionvariable. It then uses interpolation, now with a

    smoothing factor, to update the actual transform data. There are other options for dead reck-oning, such as using actual physics sim-ulation between update frames. This

    is much more complex to do, but theFX can be more coherent with the inputdata.

    For this to work, all remote cars have their Rigidbodyset as kinematic,

    so the NetworkCarscript can change its transform directly. This way,the input data will make the wheels spin and steer coherently, but this

    will have no effect in the car position and rotation, which are completely

    controlled by the NetworkCarscript.

  • 7/24/2019 PUN Rally Tutorial 106

    24/35

  • 7/24/2019 PUN Rally Tutorial 106

    25/35

    4Racing Gameplay Control

    What else do we need? We already have a functional Menuthat

    connects to Photon and enables players to create/join rooms and se-

    lect cars. Now we need to load the Race and make sure all cars are

    instantiated in all machines, that the race is started simultaneously, and

    the car positions are shown in real time. Besides, we also included a

    simple weapon system, that will be incremented in future updates forcombat-based racing games, and is explained at the end of this chapter.

    Figure 4.1: The spawn points are refer-enced in the PUNRaceManager scripts,so the car instantiation car use their po-sition and rotation.

    The code well show is split between two scripts (well specify which

    one were talking about every time we show some code): PUNRaceMan-

    ager, which is attached to a single control game object (PUNManager) in

    theRacescene; andCarRaceControl, that is attached to all car prefabs.

    Grid positioning

    The first thing we have to take care of is where to instantiate each

    players car in the scene. We decided to place and orient static game

    objects to act as spawn points, shown in Figure4.2.

    Figure 4.2: We positioned the spawnpoints and attached them to the racetrack prefab. Using this approach youcan have many different tracks (prefabs),and the cars can easily be positioned atthe starting grid.

    You should have noticed that, to developa game, a lot of effort is given to extrafeatures that are not exactly pure gamemechanics. Itd be great if we could

    just implement the racing physics, but inthe real world, we need to do everything,from GUI control to error handling.

  • 7/24/2019 PUN Rally Tutorial 106

    26/35

    26 erick passos and wan souza

    How do we use spawn points?. Take a look at the code below,

    taken from the PUNRaceManager script. It is called when the master

    client calls an RPC ordering all peers to load the Racescene:

    p r iv a te v o id C r e a te C a r ( ) {

    / / g et s s pa wn T ra n sf o rm b as ed o n p la ye r

    j o in o r de r ( s p a wn p r o pe r ty )

    in t p os = ( in t )

    P h o t o n N e t w o r k . p l a y e r . c u s t o m P r o p e r t i e s [" s p a w n " ];

    in t c a rN u mb e r = ( in t )

    P h o t o n N e t w o r k . p l a y e r . c u s t o m P r o p e r t i e s [" c a r " ];

    T r a ns f o rm s p aw n = s p a wn P o in t s [ p os ] ;

    / / i n st a nt i at e c ar a t S pa wn T ra n sf o rm

    / / c ar p r ef ab s a re n um b er e d i n t he s am e

    o rd er a s t h e c ar s pr it es t ha t t he

    p l ay e r c h os e f r om

    c ar = P h o to n N et w o rk . I n s t a n ti a t e (" C a r " +

    carNumber , spawn. position ,

    s p a w n . r o t a ti o n , 0 ) ;

    / / s om e c od e o mi tt ed f or c la r it y .

    }

    Figure 4.3: The track prefab includesgraphics, colliders, spawn points andcheckpoints. Spawn points are place tomark where cars will be instantiated.Checkpoints are used by race control.

    It takes thecarandspawncustom properties of the local player, which

    will be used as the car prefab and spawn point indexes respectively.

    Then ir instantiates the right car prefab in the correct position and

    orientation. Notice that we used PhotonNetwork.Instantiateinstead of

    the regular Unity instantiation. This is mandatory for game objects thatyou want to have loaded remotely in all peers. We omitted some control

    code in this method, so take a look at the script in the editor and read

    all the comments to understand everything that it does after that.

    Race Start, Timer and Finish

    Cars controls are disabledwhen we load the prefabs. We need

    to do a countdown and start the race roughly at the same time in all

    client machines. The control code inPUNRaceManageruses an enumer-

    ation to represent four different race states: PRE_START, COUNT-DOWN, RACING, and FINISHED.

    The code snippet below, part of the Updatemethod, checks (at the

    master client machine only) if it is time to start the countdown or the

    actual racing, in which case it then calls an RPC in all machines that

    will change the race state and release the controls for the local car.

  • 7/24/2019 PUN Rally Tutorial 106

    27/35

    pun rally 27

    r a ce T i me + = T i me . d e l t a Ti m e ;

    switch ( s t at e ) {

    case R a c e S t a t e . P R E _ S T A R T :

    if ( P h o t o n N e t w o r k . i s M a s t e r C l i e n t & &

    r ac e Ti me >= 1 ) {

    p h o to n V ie w . R P C ( " S t a r t C o u n t d o w n " ,P h o t o n T a r g e t s . A l l ,

    P h o to n N et w o rk . t i m e + 4 ) ;

    }

    break ;

    case R a c e S t a t e . C O U N T D O W N :

    if ( P h o t o nN e t wo r k . t i me > = s t a rt T i me s t am p ) {

    S t a r t R a c e ( ) ;

    }

    break ;

    Pay attention to the clever use ofPhotonNetwork.time instead ofUnitys managed local Time.time: in a multiplayer racer, we want all

    clients to start the race at roughly the same time, so we use an RPC to

    set a future time (+4 seconds from now) at PRE_START. Then, during

    the proper COUNTDOWN, we compare Photon Servers managed time

    to this future time in all computers, this way we dont need to deal with

    the individual latencies of each computer.

    The StartRace method runs in all peers. It does three things: sets

    the race state to RACING; enables controls for the local players car;

    and creates a list of all cars to control position calculation:

    p u bl i c v o id S t a r tR a c e ( ) {s t at e = R a ce S t at e . R A C IN G ;

    G a m eO b j ec t [ ] c a rs =

    G a m e O b j e c t . F i n d G a m e O b j e c t s W i t h T a g

    ( " P l a y e r " ) ;

    foreach ( G a m e O bj e c t g o in c ar s ) {

    carControllers.Add(go.GetComponent ());

    go.GetComponent ().enable d

    = true ;

    }

    c a r . G e t C o m po n e n t < C a r I n pu t > ( ) . c o n t r o l a b l e =

    true ;r a ce Ti m e = 0 ;

    }

  • 7/24/2019 PUN Rally Tutorial 106

    28/35

    28 erick passos and wan souza

    Laps and player position

    T o cou nt the ca r l a p s, each car has a CarRaceControl script

    attached. This script has one important property, namedcurrentCheck-

    point, that points to the next checkpoint the car is supposed to passthrough to count for race progress.

    Checkpoints are basically colliders marked as triggers, so they wont

    interfere with the physics, but the OnTriggerEntercallback is called on

    CarRaceControl whenever its containing car passes though one of the

    checkpoints:

    void O n T r i g ge r E nt e r ( C o l l id e r o t he r ) {

    C h e ck p o in t w a yp o i nt =

    other. GetComponent ();

    if ( w a y po i n t ! = c u r r en t W a yp o i nt ) {

    / / De bu g . Lo g ( " M is se d C he ck - " +

    o t h e r . g a m e O b j e c t . n a m e ) ;

    } else {

    w a y p o i n t s P a s s e d + + ;

    if ( w a y p o i n t . i s S t a r t F i n i s h )

    l a p s C o m p l e t e d + + ;

    if ( l a p sC o m pl e t ed = = t o ta l L ap s ) {

    C a r In p ut i n pu t =

    GetComponent

    () ;

    i n pu t . c o n t ro l a bl e = false ;

    i n pu t . S t ee r = 0 ;

    i n pu t . H a n d br a k e = 1 ;

    i n pu t . S t ee r = 0 ;

    }

    c u r re n t W ay p o in t = w a y po i n t . n ex t ;

    }

    }

    The method checks if the cause of the trigger callback was the cur-

    rentCheckpoint, in which case it increments the number of checkpoints

    passed, increments the laps if this is the finish line (theres only onecheckpoint with this property true), and verifies if the number of laps

    completed is equal to the race laps, in which case is time to disable con-

    trols and stop the car. Notice that it also sets currentCheckpointto the

    next, given they are organized as a circular linked list.Figure 4.4: The Checkpoint script withthe reference to the next checkpoint andthe bo olean property for the start/finish.

    Each checkpoint game object has a Checkpointscript attached, which

  • 7/24/2019 PUN Rally Tutorial 106

    29/35

    pun rally 29

    is used just to hold a reference to the next checkpoint in the track, and

    a boolean property to mark the sole start/finish checkpoint (explained

    previously).

    The laps are counted everytime the car passed by the start/finish

    checkpoint, but how can em calculate the relative positions of the cars

    in real-time? The idea is to store how far each car has traveled into therace.

    This is the reason we also count how many checkpoints the car has

    passed. This would give a rough idea of progress for each car. But

    how can we update the distance traveled in a frame by frame fashion?

    Well do this by measuring how far we are from the next checkpoint (the

    currentCheckpointproperty).

    With each car storing how far it has traveled into the race, all we

    need to do is sort them in reverse order. The next sections explain how

    we do this.

    Counting the checkpoints

    Figure 4.5 shows the placement of the checkpoints in the track. The

    ccalculation of the distance traveled for each car is done in the Update-

    DistanceTraveledmethod, which is called every frame:

    void U p d a t e Di s t a n c e T r a v e l e d ( ) {

    V e ct o r 3 d i s ta n c e = t r a ns f o rm . p o s i t io n -

    c u r r e n t W a y p o i n t . t r a n s f o r m . p o s i t i o n ;

    d i s t an c e Tr a v el e d = 1 0 00 * w a y po i n ts P a s se d

    + ( 1 00 0 - d i s ta n c e . m a gn i t ud e ) ;

    }

    Figure 4.5: These are all the check-points for our track. Notice that wepositioned them at basically every turn.This is needed for correctly computinghow much the car has traveled based onthe number of checkpoints passed andthe distance to the next. If you want tocreate a racing AI based on checkpoints,youd need to place many many more ofthem along the track.

    We multiply the number of checkpoints passed by a large number, so

    it is given priority in the final result. The distance to the next check-

    point is subtracted from another large number, so it will increase as the

    car travels in the right direction (and would decrease if the car goes

    the wrong way. Now we need to sort the cars based on this computed

    distance.

    Sorting cars and GUI update

    Earlier we showed the StartRacemethod, which created a list with all

    CarRaceControlinstances in the race. A C#Listcan be sorted with its

    Sortmethod, if every element of the list knows how to compare to each

    other. This is done with the CompareTo method below:

    p u bl i c i nt C o mp a r e T o ( C a r R a c e C o n t r o l o t h e r )

    {

    / / e nd o f r ac e c od e o mm it e d

  • 7/24/2019 PUN Rally Tutorial 106

    30/35

    30 erick passos and wan souza

    if ( d i s t a n c eT r a ve l e d >

    o t h e r . d i s t a n c e T r a v e l e d )

    return -1 ;

    e l se i f ( d i s t a n ce T r a ve l e d

    g ui s ) {

    foreach ( C a r R a ce C o nt r o l c in

    c a r Co n t r ol l e rs ) {

    g u i s [ c . c u r r e n t P o s i t i o n -

    1 ] . S e t C a r ( c ) ;

    }

    }

    Weapon System

    Many racing games include weapons, so we implemented a

    simple, extensible weapon system beginning with update 1.0.6 (see Fig-

    ure 4.6). There are three scripts that are used to control the weapon

    system:

  • 7/24/2019 PUN Rally Tutorial 106

    31/35

    pun rally 31

    Figure 4.6: The weapon shoots rocket-like projectiles in other cars, applying anupward impulse force on impact.

    Weapon - attached to the car prefabs (Figure 4.7), it is responsible

    for shooting the projectiles, which consists of instantiating a copy ofa bullet prefab in all client computers. It also takes care of its own

    cooldown time, etc;

    Figure 4.7: The Weapon and Damage

    scripts attached to a car prefab.

    Bullet- attached to the bullet prefab (Figure 4.8), it is responsible

    for synchronizing the projectile position over time and synchronizing

    this over the network. In this first version, bullets behave like rockets.

    In future updates, we might include other bullet types;

    Figure 4.8: The bullet prefab inspector,showing the Bullet script and its othercomponents.

    Damage- also attached to the car prefabs, this script detects when

    a car is hit by a bullet, in which case the damage (in this case an

    upward force from an explosion) is applied, and a message is sent to

    the bullet (RPC, by the Bullet script), ordering it to destroy itself

    and show an explosion;

    Take a look at these scripts and see how simple they are (none is

    more than 30 lines of code). The idea is not to have a definitive weapon

    system, but a head-start for you to implement your own ideas.

    This is it for car race control. In the next chapter, well discuss some

    other ideas the you might use to your racing game, including some stuff

    not covered in this tutorial.

  • 7/24/2019 PUN Rally Tutorial 106

    32/35

  • 7/24/2019 PUN Rally Tutorial 106

    33/35

    5Conclusion

    In this tutorial weve shown you how to create a complete

    multiplayer racing game. The features implemented and explained here

    include:

    Photon account setup, connection to Photon Network, and host-

    ing/joining races;

    Player nickname and synchronized selection of car color/prefab;

    A realistic physics car based on simulation with PhysX;

    Distributed car synchronization with dead reckoning (prediction) to

    compensate for network instability;

    Race start and control and position calculation based on checkpoints;

    A simple weapon system that fire rocket-like projectiles and applies

    a force on impact;

    It is a lot of stuff already, but theres always room for improvement,so weve taken the liberty to suggest you some things you might want

    to have implemented in your racing game.

    What to do Next

    One of the characteristics of great games is their unique-

    ness, so we highly encourage you to think outside the box and try dif-

    ferent approaches with your own project.

    What about trying an arcade style physics? Can you do this and still

    keep the Rigidbodyand CarInput scripts? If you can, there no need tochange the network code at all. It will still work of the shelf.

    But you might also try to implement an authoritative master client,

    which runs all the physics simulation, receiving input from the peers and

    giving back the updated positions. This is good to avoid certain types

    of cheating, but the network latency will be noticed a lot.

  • 7/24/2019 PUN Rally Tutorial 106

    34/35

    34 erick passos and wan souza

    Did you know that checkpoints are also the basic structure for doing

    race AI? If you can store the recommended speed for each checkpoint

    (lets say by doing trial runs), you can have an AI control script doing

    the input to steer and accelerate/brake the car along the track.

    Would it be difficult to use other racers driving styles to influence

    your AI the way it is done in Forza Motorsports?Now it is your turn to code!

  • 7/24/2019 PUN Rally Tutorial 106

    35/35

    Bibliography

    Marco Monster. Car physics for games. http://www.asawicki.info/

    Mirror/CarPhysicsforGames/CarPhysicsforGames.html, November

    2003.

    http://www.asawicki.info/Mirror/Car%20Physics%20for%20Games/Car%20Physics%20for%20Games.htmlhttp://www.asawicki.info/Mirror/Car%20Physics%20for%20Games/Car%20Physics%20for%20Games.htmlhttp://www.asawicki.info/Mirror/Car%20Physics%20for%20Games/Car%20Physics%20for%20Games.htmlhttp://www.asawicki.info/Mirror/Car%20Physics%20for%20Games/Car%20Physics%20for%20Games.htmlhttp://www.asawicki.info/Mirror/Car%20Physics%20for%20Games/Car%20Physics%20for%20Games.html