DeveloperBreeze

Introduction

Creating real-time multiplayer games is one of the most exciting and challenging aspects of game development. Unity, combined with C#, offers powerful tools for building these types of games. This tutorial will guide you through the process of developing a basic real-time multiplayer game using Unity and C#. We'll cover setting up the project, implementing multiplayer features using Unity's networking tools, and synchronizing player movements and actions.

Prerequisites

  • Basic understanding of Unity and C#.
  • Unity Hub installed with the latest version of Unity.
  • Familiarity with the Unity Editor and basic game development concepts.

Step 1: Setting Up the Unity Project

  1. Create a New Unity Project:
  • Open Unity Hub and click on "New Project."
  • Choose the "3D" template (you can use 2D if you prefer) and name your project, for example, "RealTimeMultiplayerGame."
  • Click "Create" to generate the new project.
  1. Install the Multiplayer Package:
  • Go to Window > Package Manager.
  • Search for "Netcode for GameObjects" (or any other networking package of your choice, like Photon or Mirror).
  • Click "Install" to add it to your project.

For this tutorial, we'll focus on using "Netcode for GameObjects," which is Unity's official solution for networking.

Step 2: Setting Up the Scene

  1. Create a Simple Game Environment:
  • In the Hierarchy window, right-click and create a new 3D Object > Plane to serve as the ground.
  • Create a 3D Object > Cube to act as the player character.
  • Position the cube above the plane so that it is ready to fall due to gravity.
  • Add a Camera and Light to the scene if they are not already present.
  1. Add Network Manager:
  • Right-click in the Hierarchy and create an empty GameObject. Name it "NetworkManager."
  • Add the NetworkManager component by clicking Add Component and searching for "NetworkManager."
  • Also, add the NetworkManagerHUD component to provide basic controls for starting and stopping the server or client.
  1. Set Up Player Prefab:
  • Convert the player cube into a prefab by dragging it from the Hierarchy to the Assets folder.
  • Delete the original cube from the scene.
  • In the NetworkManager component, assign the player prefab to the "Player Prefab" field.

Step 3: Implementing Multiplayer Functionality

  1. Add Network Components to the Player:
  • Open the player prefab in the prefab editor.
  • Add a NetworkObject component to the player.
  • Add a NetworkTransform component to handle the synchronization of the player’s position and rotation.
  1. Writing the Player Movement Script:
  • Create a new C# script named PlayerController and attach it to the player prefab.
  • Implement basic movement logic:
     using UnityEngine;
     using Unity.Netcode;

     public class PlayerController : NetworkBehaviour
     {
         public float moveSpeed = 5f;
         public float rotateSpeed = 200f;

         void Update()
         {
             if (!IsOwner) return; // Only allow control by the local player

             float move = Input.GetAxis("Vertical") * moveSpeed * Time.deltaTime;
             float rotate = Input.GetAxis("Horizontal") * rotateSpeed * Time.deltaTime;

             transform.Translate(0, 0, move);
             transform.Rotate(0, rotate, 0);
         }
     }

This script allows the player to move forward and backward using the Vertical axis and rotate using the Horizontal axis. The IsOwner check ensures that only the player who owns the object can control it.

  1. Testing the Multiplayer Setup:
  • Save all your changes and go back to the main scene.
  • Press Play and use the NetworkManagerHUD to start as a Host, Client, or Server.
  • You should be able to control the player object and see it move on both the host and client.

Step 4: Synchronizing Player Actions

  1. Synchronize Animations (Optional):
  • If your player has animations, you can synchronize them using NetworkAnimator.
  • Add the NetworkAnimator component to your player prefab and link it to the Animator component.
  1. Handling Shooting or Actions:

Let's say your game involves shooting. Here’s how to synchronize a shooting action:

  • Add a method to shoot, and synchronize it across the network using ServerRpc:
     public class PlayerController : NetworkBehaviour
     {
         public GameObject bulletPrefab;
         public Transform bulletSpawn;

         void Update()
         {
             if (!IsOwner) return;

             // Movement code...

             if (Input.GetButtonDown("Fire1"))
             {
                 ShootServerRpc();
             }
         }

         [ServerRpc]
         void ShootServerRpc()
         {
             GameObject bullet = Instantiate(bulletPrefab, bulletSpawn.position, bulletSpawn.rotation);
             bullet.GetComponent<NetworkObject>().Spawn();
         }
     }

In this example, when the player presses the fire button, a ServerRpc is called to spawn a bullet on the server, which is then synchronized with all clients.

Step 5: Managing Game State and UI

  1. Create a Game Manager:
  • Create a GameManager script to handle the game state (e.g., start, end, scoring).
  • This script can manage player connections, disconnections, and overall game flow.
   using UnityEngine;
   using Unity.Netcode;

   public class GameManager : NetworkBehaviour
   {
       public void StartGame()
       {
           // Code to initialize the game
       }

       public void EndGame()
       {
           // Code to handle game over state
       }

       // Example of starting a game when all players are ready
       public void CheckPlayersReady()
       {
           if (NetworkManager.Singleton.ConnectedClients.Count >= 2)
           {
               StartGame();
           }
       }
   }
  1. Implementing UI for Player Status:
  • Create a simple UI that displays player statuses, such as health or scores.
  • Use NetworkVariable to synchronize data like health or scores:
     public class PlayerController : NetworkBehaviour
     {
         public NetworkVariable<int> playerScore = new NetworkVariable<int>();

         // Score updating method
         public void AddScore(int points)
         {
             if (IsServer)
             {
                 playerScore.Value += points;
             }
         }
     }

This ensures that player scores are updated and synchronized across all clients.

Step 6: Polishing and Optimization

  1. Optimizing Network Traffic:
  • Use NetworkTransform settings to optimize the synchronization of player movements, reducing unnecessary data transmission.
  • Consider implementing interpolation and prediction to smooth out player movements.
  1. Polishing the Gameplay:
  • Add sound effects, particle effects, and other visual feedback for actions like shooting or taking damage.
  • Ensure the game is responsive and enjoyable by fine-tuning the controls and networking code.

Step 7: Building and Testing

  1. Building for Multiple Platforms:
  • Use Unity’s build settings to export the game to different platforms (e.g., Windows, Mac, Android).
  • Ensure that the multiplayer functionality works seamlessly across different platforms.
  1. Testing with Real Players:
  • Invite friends or use online services to test your game with real players.
  • Test the game in various network conditions to ensure it handles lag and disconnections gracefully.

Conclusion

Congratulations! You've developed a basic real-time multiplayer game using Unity and C#. This tutorial covered setting up the project, implementing player movement, synchronizing actions, managing game state, and optimizing network performance. With these foundations, you can expand your game with more complex features, such as different game modes, AI opponents, or matchmaking systems.


This tutorial should provide a solid foundation for developing real-time multiplayer games with Unity and C#.

Continue Reading

Discover more amazing content handpicked just for you

Tutorial

Avoiding Memory Leaks in C++ Without Smart Pointers

void legacyFunction(char* data);

void useLegacyAPI() {
    ScopedArray<char> buffer(new char[512]);
    legacyFunction(buffer.get());
}

Even without smart pointers, you can manage memory safely in C++ using the RAII pattern. This approach:

Apr 11, 2025
Read More
Tutorial

Deep Copy in C++: How to Avoid Shallow Copy Pitfalls

In C++, copying objects can lead to serious bugs if you're dealing with raw pointers. By default, C++ uses shallow copy, which means only the pointer's value is copied—not the data it points to.

This tutorial covers:

Apr 11, 2025
Read More
Tutorial

Implementing a Domain-Specific Language (DSL) with LLVM and C++

Modern applications demand flexible, domain-focused solutions. A DSL allows domain experts to express complex logic concisely and can be optimized for performance. Leveraging LLVM gives you access to state-of-the-art optimization and code generation tools, so you can create languages that compile to highly efficient native code. In this tutorial, we’ll implement a simple mathematical expression language (with potential for future extensions) that computes results in real time.

Tools & Libraries:

Feb 12, 2025
Read More
Tutorial
javascript

JavaScript in Modern Web Development

JavaScript isn't limited to the browser anymore. It's being used in diverse domains:

  • Tools like React Native enable building native apps using JavaScript.
  • Example: Facebook's mobile app.

Dec 10, 2024
Read More
Tutorial
python

Build a Multiplayer Game with Python and WebSockets

We’ll use the websockets library to handle communication between players.

import asyncio
import websockets
import json

game = TicTacToe()
players = []

async def handler(websocket, path):
    global players
    players.append(websocket)
    try:
        async for message in websocket:
            data = json.loads(message)
            if "move" in data:
                position = data["move"]
                response = game.make_move(position)
                for player in players:
                    await player.send(json.dumps({"board": game.board, "status": response}))
    except websockets.ConnectionClosed:
        players.remove(websocket)

start_server = websockets.serve(handler, "localhost", 8765)

asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

Dec 10, 2024
Read More
Code
csharp

Unity Inventory System using Scriptable Objects

A simple inventory system that can add, remove, and use items.

using System.Collections.Generic;
using UnityEngine;

public class Inventory : MonoBehaviour
{
    public List<Item> items = new List<Item>();
    public int capacity = 20;

    public bool AddItem(Item item)
    {
        if (items.Count >= capacity)
        {
            Debug.Log("Inventory is full!");
            return false;
        }

        if (item.isStackable)
        {
            Item existingItem = items.Find(i => i.itemName == item.itemName);
            if (existingItem != null)
            {
                // Stack logic (if needed)
                Debug.Log($"Stacking {item.itemName}");
                return true;
            }
        }

        items.Add(item);
        Debug.Log($"{item.itemName} added to inventory.");
        return true;
    }

    public void RemoveItem(Item item)
    {
        if (items.Contains(item))
        {
            items.Remove(item);
            Debug.Log($"{item.itemName} removed from inventory.");
        }
    }

    public void UseItem(Item item)
    {
        if (items.Contains(item))
        {
            item.Use();
        }
    }
}

Aug 12, 2024
Read More
Code
csharp

Unity Player Controller Blueprint

No preview available for this content.

Aug 12, 2024
Read More
Code
csharp

Calculate Sum of Numbers in Array

No preview available for this content.

Jan 26, 2024
Read More

Discussion 0

Please sign in to join the discussion.

No comments yet. Start the discussion!