Game Networking for Beginners with Unity3D – for Kindle

I’ve developed a great Step-By-Step guide to networking with Unity3D.

Get it here

I’ve been working with Unity3D for a little while now and I’ve found it to be one of the easiest commercial engines I’ve worked with, while still offering considerable power and flexibility. I really like it a lot. I further found the Networking to be very easy and straight forward, but I have been doing networking for many years so it was easy for me to pickup.

When I started working with Unity3D I found a few networking tutorials online, but there were a few things I didn’t like about them. The tutorials I found showed every possible networking variation creating a very complicated, unorganized compilation of examples. I also don’t like when tutorials don’t provide a thorough job of explaining what you’re doing and why, instead just telling you copy this and paste that. I therefore decided to develop a step-by-step eBook covering what I believe is the most common networking techniques for developing multi-player games in Unity3D.

In my eBook you will learn about such things as Master Game Servers, Game Servers, TCP/IP vs UDP/IP, Game Matching and Game Lobby Services, Instantiating Network Objects, Animating Networked Objects, Synchronizing a level and objects across clients, Problems with Firewalls and Routers and how to overcome them with NAT Punch Through, and a whole lot more. See what others are saying about the eBook:

                          Great tutorial

         All networking principles are explained in detail, 
                 with great examples. A must-read

         I just pretty much finished my network coding for 
                   my game with just this tut

          Thanks for the great tutorial! I now have much 
           better understanding of how networking works

                        Just what is needed

                  Good examples with code ready to 
                    be used in your own project!

Get it here

To see details of what’s covered I’ve included the Table of Contents below for your review:

                        Table of Contents

Introduction................................................……... 6
Game Networking Engine Designs................................... 8
    Master Game Server (MGS)..................................….. 8
    Peer-to-Peer (P2P).......................................…... 8
    Game Server (GS)............................................. 9
    Game Networking Engine Styles................................ 9
        Dedicated / NON Client................................... 9
        Non Dedicated / With Client............................. 10
        Relay................................................... 10
        Authoritative........................................... 10
        Hybrid.................................................. 11
    LAG ........................................................ 13
Network Connectivity and Firewalls ............................. 14
    IP Addresses and Ports...................................... 14
        Network IP Address...................................... 14
        IPv4 addresses.......................................... 14
        Network Port............................................ 15
    Network Address Translation or NAT.......................... 15
    NAT Punch Through / NPT..................................... 17
General Coding Overview................................…........ 19
    Converting between C# and Java Script................…...... 19
    Tags........................................................ 20
    Layers...................................................... 20
Overview of our Networking Tutorial:............................ 21
    Demo Overview............................................... 21
    Basic Networking API’s...................................... 22
        TCP vs UDP:............................................. 22
    Unity3D Networking API’s.................................... 22
        NetworkView............................................. 22
    Instantiating a Networked Object............................ 24
Building our Game:.............................................. 24
    Building the Game Level:.................................... 24
        Creating the Floor...................................... 25
        Creating the Scenery:................................... 25
    Creating the Player Character..............................… 25
        Player Controller:...................................... 26
    Player Spawn Area:.......................................... 29
    Pickup Spawn Area:.......................................... 29
    Overview of Networking Classes we’ll create for our Demo.... 31
Analysis and Code of each Network Class......................... 34
    NetworkMasterServer:........................................ 34
    NetworkLoadLevel:........................................... 42
        LoadLevel............................................... 43
        OnPlayerDisconnected.................................... 48
        PlayerSpawn Public Variables Setup...................... 50
        Renaming Remote Objects:................................ 54
        PlayerSpawn code:....................................... 54
    NetworkRigidbody:........................................... 57
        NetworkRigidbody OnSerializeNetworkView................. 58
    Working with Pickups:....................................... 62
        InstantiatePlayer:...................................... 62
        BallSpawnManager:....................................... 62
        BallController:......................................... 62
        BallManager:............................................ 62
    InstantiatePlayer – Updated for Networking:................. 64
        InstantiatePlayer Code.................................. 65
    BallSpawnManager:........................................... 68
        BallSpawnManager Update................................. 68
        BallSpawnManager OnSpawnBall............................ 69
        BallSpawnManager OnInitBall............................. 69
        BallSpawnManager Code:.................................. 69
    Ball Controller:............................................ 74
        BallController Update................................... 74
        BallController OnCollisionEnter......................... 74
        BallController OnPickupBall............................. 74
        BallController OnThrowBall.............................. 75
        BallController UpdatePlayerState........................ 75
        BallController OnUpdatePlayerState...................... 75
        BallController Code:.................................... 75
    Ball Manager:............................................... 80
        BallManager Update...................................... 80
        BallManager OnCollisionEnter............................ 80
        BallManager ReSetBallBackToSpawnArea.................... 80
        Ball Manager Code:...................................... 80
Updating Prefabs:............................................... 83
    Updating the Player Prefab.................................. 83
    Updating the BallPickup Prefab.............................. 84
Initializing Public Variables:.................................. 85
    BallSpawnManager Public Variables:.......................... 85
    BallController Public Variables:............................ 86
    BallManager Public Variables:............................... 87
CONGRATULATIONS, we’re done .................................... 88
Appendix A - Managing dynamic Objects........................... 89
    Creating a Throwing Spear................................... 89
    Spear Code:................................................. 90
        SpearController Code:................................... 90
        SpearManager Code:...................................... 94
        Spear Controller Variables:............................. 95
        Spear Manager Variables:................................ 97
    Buffered RPC commands....................................... 98
    Networking Groups........................................... 99
    SetLevelPrefix............................................. 100
Appendix C – Try This.......................................... 101
Appendix D – Object to Script Associations..................... 102
    MasterGameServerLobby Level................................ 102
    TestGameLevel Level........................................ 102
Conclusion..................................................... 103

Get it here

About Quadgnim

I'm Laurence Grant, and I’ll do my best to post relevant material pertaining to Indie Game Development. I have nearly 30 years of professional IT experience. I’ve worked at VMware, Oracle and EMC to name a few and I’m currently a vSpecialist at EMC Corporation and a certified VCP, and ITIL engineer. I've built a great career as a technology architect, but never lost the passion I get for creating games. I know I have a lot to learn, and I'm always pushing myself to stay abreast of the latest updates in gaming technology. I also think I can share a lot of my experience and maybe help out some just getting started. I hope you enjoy the site and find the information valuable. Follow me on twitter @Quadgnim
This entry was posted in General Indie Gaming, Networking, Unity3D and tagged , , , , , , , , , , , , , , , . Bookmark the permalink.

19 Responses to Game Networking for Beginners with Unity3D – for Kindle

  1. Quadgnim says:

    A few users had issues unzipping the eBook and the internal contents. The original files were zipped using 7zip and that seems to be working for everyone to unzip them. If you run into problems please try using 7zip. I will be replacing the base download with one built using winzip in hopes it’ll be more compatible for everyone.

  2. Milad Fathi says:

    Hello Larry
    I got your ebook and red it. i can say this book is what i need. and it is really Great Tuoturial. my English is bad , excuse me i can’t show how i feel but i tried.
    every body who reads this comment , if you don’t get this book you losed a Great tutorial.

  3. enter360 says:

    I am on page 35 of your tutorial. I have tried copying and pasting the code. It has a lot of errors. I have a background in c++, html , C , javascript. I am new to unity so I was hoping your tutorial would be helpful. Up until this part it was great. Could you post the .cs files so that if it’s a formatting issue I can continue. Other wise I would recommend your eBook to anyone.

    • Quadgnim says:

      Enter360,

      Thank you for your support. If you have issues with the eBook it’s easier to correspond through email for me as I get it on my mobile devices and can reply more quickly.

      Most of the code in the eBook itself was not really meant to cut/paste as the footer on each page causes issues and I also had to manually format the text for the eBook so it looked clean and readable within Microsoft Word (pre pdf). However, that is why I also included the unity package with the eBook and an optional fully completed zip file of the project itself. What you should do is import the package from within Unity and you’ll have all the code. You’ll still need to go through the eBook to properly create all the game objects and assemble everything, but you’d be doing that anyway. The package just alleviates having to cut/paste.

      If you get lost, the complete project can be used as a reference, as it has everything done in it. Just unzip the project and open it in unity.

      Does all that make sense? Am I missing something?

      Larry

  4. Graham Gaylor says:

    Hey Larry! First off, your Unity Networking tutorial is awesome; very easy to understand and a very short and concise example of it. Anyways, I’m still trying to understand exactly how all the Unity networking stuff works (reading online docs and what not) and one thing I cannot get is how my game tells the difference between other games. Just a moment ago I realized that when I’d start up the networking tutorial there was somebody else’s game name listed as one of the available games to join, “Solar Space Junk” I believe it was. I decided it had something to do with the “gameType” public variable in the NetworkMasterServer class but after changing it, nothing seemed to change. After a few minutes is seemed to work (but idk if that’s because Solar Space Junk isn’t running right now). Do you mind explaining this?

    Thanks

    • Graham Gaylor says:

      Definitely just answered my own question after searching the docs. Still weird that it took a little while to work? http://docs.unity3d.com/Documentation/Components/net-MasterServer.html

    • Quadgnim says:

      Thanks for the support and I’m happy to help out where I can. You are right, changing GameType should distinguish your version of a game from someone else. However, as many people have downloaded the eBook and are using the default Unity3D testing Master Game Server it’s likely there will be collisions if its not changed. If you did change it and still saw an issue I just wonder did you change the server and restart it, and not just change the client? In all the time I’ve been testing my own examples, I’ve never ran into an issue.

      Also, the Master Gamer Server the eBook uses is only for testing. Unity provides the source code to download and run your own server when you’re ready to move beyond testing. I provided a link to it in the eBook.

      I hope that helps.

  5. warren g says:

    Hi
    First of all thanks for this book, it has helped me out alot.
    I have written a mini review on it and also added the review link
    to reddit hopefully you get a boost in sales =)

    Warren.
    Peace. Love. Happiness.

    • Quadgnim says:

      I’m so glad you enjoyed the eBook and found it useful. I’m applying the skills I learned while creating the eBook to create a very advanced multi-player space combat game (Pulsar). Maybe I’ll develop an advanced networking eBook as I’ve been getting many requests for one. We’ll see if time permits. In the interim please check out Pulsar, and like my Facebook page. I might be posting a link to an early web preview soon.

  6. Adam Walker says:

    I’m working through this tutorial now, and I have to say, it is fantastic. The depth you explain everything in is just what I needed to get my head around Unity networking land. You’ve done a much better job than the ‘premium’ networking tutorial on the asset store and for a fraction of the price. Keep up the great work man, Pulsar is looking awesome :)

    • Quadgnim says:

      Thank you so much for those kind words. That’s great to hear. I’m really glad it’s working out.

      • Adam Walker says:

        One question I do have is, would it not be better to have two versions of the player? One for user locally which contained the camera/controller etc, and then another to represent remote users (without camera/controller etc)? I’m trying to get my head around translating what you’ve done into an fps style game where the player object could be quite complex, and it seems like manually disabling everything inside the player in the ‘PlayerSpawn’ script could be a little unreliable/time consuming.

        If this is feasible, how would you reccomend modifying the code to allow for different prefabs to be spawned, dependant on wether on the not the player was local or remote?

        • Quadgnim says:

          Adam,

          To a certain extent its going to be personal preference. If you’re using Network.Instantiate it has to be the same prefab. If you’re generating the viewID ahead of time and using an RPC you could certainly instantiate a different prefab for local vs remote avatars. However, if you go that route you’ll need to manually maintain two different prefabs for every object. For some projects you could have many 10′s or even hundreds of objects, and maintaining two copies could be overwhelming.

          Another option is to get more sophisticated with how you toggle components on/off. For the Networking eBook I purposefully didn’t want to get involved with non networking concepts, so I did those things brute force. In my own game I actually have a component manager that I can drop into an object and that component manager has a list of all local components that are defined as local, remote, local_and_remote, and other special case items. This component is then connected to any object or sub object where I may have to toggle things on/off. It might be for local/remote instantiation, or it might be because the player paused and I want to change what’s displayed. I have a method that I would call using mygameobject.Broadcast(“SetPause”, true, receivernotrequired); for example or …..Broadcast(“SetPlayerLocal”, receivernotrequired );

          Using something like this makes it easy to design a single prefab that supports all the various modes I need and I don’t have to hardcode things in game logic. As a matter of fact some of the existing Unity demos do something very similar but I expanded upon it for my specific needs.

          I hope that helps. Best of luck.

          Larry

          • Adam Walker says:

            That helps a lot! I think I’ll go down the component managing route. That way I guess all players would just have a first person and a third person model, which is turned on/off dependant on local/remote (or infact users preference of 3rd vs 1st person).

            It’s all a little clearer now, thanks again :)

          • Adam Walker says:

            I’ve just got to the nightmarish physics syncing part of networking, and I read a thread here http://forum.unity3d.com/threads/125084-objects-owned-by-other-players-twitch-when-moving-in-the-same-direction-as-the-player

            Where you seem to have solved some issues with an improved version of networkRigidBody.

            I’m getting odd issues where the clients effects on the rigidbodys are delayed (so if I push a box as the client, it kinda sticks on the servers screen, then catches up and flies miles). You didn’t cover network physics stuff too much in your tutorial, so I wondered if you had any insight?

  7. Quadgnim says:

    Here is a new version of NetworkRigidBody that works great for me. However, part of how it works is to also pass the control inputs too. I’m not including those details here, but in short when the users control inputs change a issue a Broadcast(“UpdateInputControls”….) where I then store the input control changes. Since network updates are less often than every frame, I store the largest input value between network updates, not the last input value.

    [code]
    using UnityEngine;
    using System.Collections;

    public class NetworkRigidbody : MonoBehaviour {

    public double m_InterpolationBackTime = 0.1;
    public double m_ExtrapolationLimit = 0.5;
    private float interpolationConstant = 0.01f;
    InputManager _inputs; // = new InputManager();

    internal struct State
    {
    internal double timestamp;
    internal Vector3 pos;
    internal Vector3 velocity;
    internal Quaternion rot;
    internal Vector3 angularVelocity;
    internal float yaw;
    internal float pitch;
    internal float roll;
    internal float speed;
    }

    // We store twenty states with "playback" information
    State[] m_BufferedState = new State[20];
    // Keep track of what slots are used
    int m_TimestampCount;
    PhotonView _pv;
    float queuedyaw;
    float queuedpitch;
    float queuedroll;
    float queuedspeed;
    float lastsentyaw;
    float lastsentpitch;
    float lastsentroll;

    void Awake () {
    _pv = (PhotonView)gameObject.GetComponent("PhotonView");

    enabled = !_pv.isMine;
    }

    void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
    {
    // Send data to server
    if (stream.isWriting)
    {
    Vector3 pos = transform.position;
    Quaternion rot = transform.rotation;
    Vector3 velocity = rigidbody.velocity;
    Vector3 angularVelocity = rigidbody.angularVelocity;
    float yaw = queuedyaw;
    float pitch = queuedpitch;
    float roll = queuedroll;
    float speed = queuedspeed;
    lastsentyaw = queuedyaw;
    lastsentpitch = queuedpitch;
    lastsentroll = queuedroll;

    //Debug.Log ("Sending Remote Inputs - Yaw = " + queuedyaw.ToString() + ", Pitch = " + queuedpitch.ToString() + ", Roll = " + queuedroll.ToString() );

    queuedyaw = 0;
    queuedpitch = 0;
    queuedroll = 0;

    stream.Serialize(ref pos);
    stream.Serialize(ref velocity);
    stream.Serialize(ref rot);
    stream.Serialize(ref angularVelocity);
    stream.Serialize(ref yaw);
    stream.Serialize(ref pitch);
    stream.Serialize(ref roll);
    stream.Serialize(ref speed);
    }
    // Read data from remote client
    else
    {
    Vector3 pos = Vector3.zero;
    Vector3 velocity = Vector3.zero;
    Quaternion rot = Quaternion.identity;
    Vector3 angularVelocity = Vector3.zero;
    float yaw = 0f;
    float pitch = 0f;
    float roll = (short)0;
    float speed = 0f;

    stream.Serialize(ref pos);
    stream.Serialize(ref velocity);
    stream.Serialize(ref rot);
    stream.Serialize(ref angularVelocity);
    stream.Serialize(ref yaw);
    stream.Serialize(ref pitch);
    stream.Serialize(ref roll);
    stream.Serialize(ref speed);

    //Debug.Log ("Processed Remote Inputs - Yaw = " + yaw.ToString() + ", Pitch = " + pitch.ToString() + ", Roll = " +roll.ToString() );

    // Shift the buffer sideways, deleting state 20
    for (int i=m_BufferedState.Length-1;i>=1;i--)
    {
    m_BufferedState[i] = m_BufferedState[i-1];
    }

    // Record current state in slot 0
    State state;
    state.timestamp = info.timestamp;
    state.pos = pos;
    state.velocity = velocity;
    state.rot = rot;
    state.angularVelocity = angularVelocity;
    state.yaw = yaw;
    state.pitch = pitch;
    state.roll = roll;
    state.speed = speed;
    m_BufferedState[0] = state;

    // Update used slot count, however never exceed the buffer size
    // Slots aren't actually freed so this just makes sure the buffer is
    // filled up and that uninitalized slots aren't used.
    m_TimestampCount = Mathf.Min(m_TimestampCount + 1, m_BufferedState.Length);

    // Check if states are in order, if it is inconsistent you could reshuffel or
    // drop the out-of-order state. Nothing is done here
    for (int i=0;i {
    if (m_BufferedState[i].timestamp < m_BufferedState[i+1].timestamp)
    Debug.Log("State inconsistent");
    }
    }
    }

    // We have a window of interpolationBackTime where we basically play
    // By having interpolationBackTime the average ping, you will usually use interpolation.
    // And only if no more data arrives we will use extra polation
    void FixedUpdate () {
    if ( _pv.isMine )
    {
    if ( Mathf.Abs(_inputs.mouseYaw) > Mathf.Abs( queuedyaw ) )
    queuedyaw = _inputs.mouseYaw;
    if ( Mathf.Abs(_inputs.mousePitch) > Mathf.Abs(queuedpitch) )
    queuedpitch = _inputs.mousePitch;
    if ( Mathf.Abs(_inputs.mouseRoll) > Mathf.Abs(queuedroll) )
    queuedroll = _inputs.mouseRoll;

    }

    if (m_BufferedState[0].timestamp == 0)
    return;

    // This is the target playback time of the rigid body
    double interpolationTime = PhotonNetwork.time - m_InterpolationBackTime;

    // Use interpolation if the target playback time is present in the buffer
    if (m_BufferedState[0].timestamp > interpolationTime)
    {
    //Debug.Log("Performing Smoothing");

    // Go through buffer and find correct state to play back
    for (int i=1;i {
    if (m_BufferedState[i].timestamp <= interpolationTime || i == m_TimestampCount-1)
    {
    // The state one slot newer (<100ms) than the best playback state
    State rhs = m_BufferedState[i-1];
    // The best playback state (closest to 100 ms old (default time))
    State lhs = m_BufferedState[i];

    // Use the time between the two slots to determine if interpolation is necessary
    double length = rhs.timestamp - lhs.timestamp;
    float t = 0.0F;
    // As the time difference gets closer to 100 ms t gets closer to 1 in
    // which case rhs is only used
    // Example:
    // Time is 10.000, so sampleTime is 9.900
    // lhs.time is 9.910 rhs.time is 9.980 length is 0.070
    // t is 9.900 - 9.910 / 0.070 = 0.14. So it uses 14% of rhs, 86% of lhs
    if (length > 0.0001){
    t = (float)((interpolationTime - lhs.timestamp) / length);
    }

    // if t=0 => lhs is used directly
    transform.localPosition =
    Vector3.Lerp (transform.localPosition,
    Vector3.Lerp (lhs.pos, rhs.pos, t),
    interpolationConstant);
    transform.localRotation =
    Quaternion.Slerp (transform.localRotation,
    Quaternion.Slerp(lhs.rot, rhs.rot, t),
    interpolationConstant);
    rigidbody.velocity =
    Vector3.Lerp (rigidbody.velocity,
    Vector3.Lerp (lhs.velocity, rhs.velocity, t),
    interpolationConstant);
    rigidbody.angularVelocity =
    Vector3.Lerp (rigidbody.angularVelocity,
    Vector3.Lerp (lhs.angularVelocity, rhs.angularVelocity, t),
    interpolationConstant);
    _inputs.mouseYaw = Mathf.Lerp (lhs.yaw, rhs.yaw, t);
    _inputs.mousePitch = Mathf.Lerp (lhs.pitch, rhs.pitch, t);
    _inputs.mouseRoll = Mathf.Lerp (lhs.roll, rhs.roll, t);
    BroadcastMessage("UpdateInputControlls", _inputs, SendMessageOptions.DontRequireReceiver);

    float newspeed = Mathf.Lerp (lhs.speed, rhs.speed, t);
    BroadcastMessage("UpdateThrottle", newspeed, SendMessageOptions.DontRequireReceiver);
    return;
    }
    else
    Debug.Log("Timestamp 0 < = Interpolatin");
    }
    }
    else
    {
    //Debug.Log("Performing Prediction");

    float dt = (float)(PhotonNetwork.time - m_BufferedState[0].timestamp);
    Vector3 extra_pos = m_BufferedState[0].pos + m_BufferedState[0].velocity * dt;

    float angle = m_BufferedState[0].angularVelocity.magnitude;
    Vector3 axis = m_BufferedState[0].angularVelocity / angle;
    Quaternion extra_rot = m_BufferedState[0].rot * Quaternion.AngleAxis (angle * dt, axis);

    transform.localPosition = Vector3.Lerp (transform.localPosition, extra_pos, interpolationConstant);
    transform.localRotation = Quaternion.Slerp (transform.localRotation, extra_rot, interpolationConstant);

    rigidbody.velocity = Vector3.Lerp (rigidbody.velocity, m_BufferedState[0].velocity, interpolationConstant);
    rigidbody.angularVelocity = Vector3.Lerp (rigidbody.angularVelocity, m_BufferedState[0].angularVelocity, interpolationConstant);

    _inputs.mouseYaw = m_BufferedState[0].yaw;
    _inputs.mousePitch = m_BufferedState[0].pitch;
    _inputs.mouseRoll = m_BufferedState[0].roll;
    BroadcastMessage("UpdateInputControlls", _inputs, SendMessageOptions.DontRequireReceiver);

    BroadcastMessage("UpdateThrottle", m_BufferedState[0].speed, SendMessageOptions.DontRequireReceiver);
    }
    }

    ///*
    void UpdateInputControlls( InputManager _im)
    {
    _inputs.acceleratePressed = _im.acceleratePressed;
    _inputs.deceleratePressed = _im.deceleratePressed;
    _inputs.fullspeedPressed = _im.fullspeedPressed;
    _inputs.fullstopPressed = _im.fullstopPressed;
    _inputs.mouseYaw = _im.mouseYaw;
    _inputs.mousePitch = _im.mousePitch;
    _inputs.mouseRoll = _im.mouseRoll;
    }
    //*/

    void UpdateThrottle(float throttle)
    {
    queuedspeed = throttle;

    }

    }
    [/code]

    • Adam Walker says:

      Excellent! Thanks, will give that a go. I’ve gotten things working pretty nicely by letting the server handle physics calculations. So players send their force etc via an RPC, the server applies the physics and the results are sent back via the network view. Working very nicely so far!

  8. Pingback: Unity3D Multiplayer Networking Ebook | CompeteForNothing

Leave a Reply