Back To Home

Photon

20-04-2024

Mastering Communication with Photon: Building Robust Multiplayer Games in Unity

"This is a continuation of part 4 in which we explore the essential concepts of communication within (PUN)"

Players need a way to exchange information, react to each other's actions, and stay in sync. Networking events in Photon act as the messenger, constantly relaying updates and keeping everyone on the same page.
In Photon, there are primarily two main ways to facilitate communication between players in multiplayer games:

1. Remote Procedure Calls (RPCs):

Remote Procedure Calls (RPCs) are a vital feature in multiplayer game development. RPCs allow you to call methods on specific players or all players in a room, enabling communication and interaction between players across the network. Let's dive into RPCs with a simple example:

Let's understand it by our first example :

Imagine you're creating a multiplayer game where players can shoot bullets at each other. When a player shoots a bullet, you want to inform all other players in the room so they can see the bullet and react accordingly.

I. Define the RPC Method :

First, define a method that represents the action you want to perform on remote players. In our example, let's create an RPC method called ShootBulletRPC that takes the bullet's position and direction as parameters.

II. Call the RPC Method :

When a player shoots a bullet, call the ShootBulletRPC method and pass the bullet's position and direction as arguments. Photon automatically handles the network communication and invokes the method on all remote clients.

III. Receive and Execute the RPC :

On remote players' devices, the ShootBulletRPC method will be called automatically when invoked by the RPC. Remote players will instantiate the bullet at the specified position and move it in the given direction.

code :

  
using Photon.Pun;
using UnityEngine;

public class PlayerController : MonoBehaviourPunCallbacks
{
    public GameObject bulletPrefab;
    public float bulletSpeed = 10f;
    public float offset = 1f;

    void Update()
    {
        if (photonView.IsMine && Input.GetButtonDown("Fire1")) // Check if this is the local player
        {
            Vector3 bulletPosition = transform.position + transform.forward * offset;
            Vector3 bulletDirection = transform.forward;

            // Call the ShootBulletRPC method on all remote players
            photonView.RPC("ShootBulletRPC", RpcTarget.All, bulletPosition, bulletDirection);
        }
    }

    [PunRPC] // Mark the method as an RPC
    void ShootBulletRPC(Vector3 position, Vector3 direction)
    {
        // Instantiate bullet using PhotonNetwork.Instantiate
        GameObject bullet = PhotonNetwork.Instantiate("BulletPrefab", position, Quaternion.identity);
        bullet.GetComponent().velocity = direction * bulletSpeed;
    }
}
  

Example 2 :

Let's consider a different example where we want to synchronize player health across all clients in a multiplayer game.

In a multiplayer game, each player has a health value that represents their remaining health points. We want to ensure that when a player takes damage or is healed, their health value is synchronized across all clients so that all players see the same health status for each player.

I. Define the RPC Method :

First, define an RPC method called UpdateHealthRPC that takes the player's ID and their updated health value as parameters.

code :

  
using Photon.Pun;
using UnityEngine;

public class PlayerHealth : MonoBehaviourPunCallbacks
{
    [PunRPC] // Mark the method as an RPC
    void UpdateHealthRPC(int playerId, int health)
    {
        // Find the player with the specified ID and update their health
        Player player = GetPlayerById(playerId);
        if (player != null)
        {
            player.Health = health;
        }
    }

    // Method to find a player by their ID (example implementation)
    Player GetPlayerById(int playerId)
    {
        // Implement logic to find and return the player with the specified ID
        // This could involve searching through a list of players or using a player ID-to-player mapping
        return null;
    }
}

II. Call the RPC Method :

When a player takes damage or is healed, call the UpdateHealthRPC method and pass the player's ID and their updated health value as arguments. This informs all other players about the health update.

  
using Photon.Pun;
using UnityEngine;

public class PlayerCombat : MonoBehaviour
{
    void TakeDamage(int damage)
    {
        int playerId = photonView.ViewID; // Get the player's unique PhotonView ID
        int currentHealth = GetPlayerHealth(); // Example method to get the player's current health
        int newHealth = Mathf.Max(0, currentHealth - damage); // Calculate new health after taking damage

        // Call the UpdateHealthRPC method on all remote players
        photonView.RPC("UpdateHealthRPC", RpcTarget.All, playerId, newHealth);
    }

    int GetPlayerHealth()
    {
        // Example method to get the player's current health
        return 100; // Assuming the player's health starts at 100
    }
}

III. Receive and Execute the RPC :

On remote players' devices, the UpdateHealthRPC method will be called automatically when invoked by the RPC. Remote players will update the health value of the specified player to match the updated value.

Summary :

In summary, RPCs allow you to synchronize gameplay events, such as player health updates, across all clients in a multiplayer game. By marking a method with the [PunRPC] attribute and calling it using photonView.RPC(), you can ensure that game state changes are communicated effectively to all players, maintaining consistency and fairness in the multiplayer experience.

2. Events :

Events are messages broadcasted to multiple players within a room. Unlike RPCs, which target specific recipients, events are sent to all players connected to the same room. Events are useful for broadcasting updates, notifications, or game state changes to all participants simultaneously. They are particularly effective for implementing global gameplay events or notifying players of important changes in the game world.

Here's an example of how we can use events in Photon to broadcast a message to all players in a room :

code :

  
public class GameManagerr : MonoBehaviourPunCallbacks, IOnEventCallback
{
  // Define custom event codes
  public const byte GameStartedEventCode = 1;
  public const byte GameOverEventCode = 2;


  private void OnEnable()
  {
      PhotonNetwork.AddCallbackTarget(this);
  }

  private void OnDisable()
  {
      PhotonNetwork.RemoveCallbackTarget(this);
  }

  void Start()
  {
      // Check if the current client is the master client
      if (PhotonNetwork.IsMasterClient)
      {
          // Trigger the game start event when the game begins
          RaiseEvent(GameStartedEventCode);
      }
  }

  // Method to raise a custom event
  void RaiseEvent(byte eventCode)
  {
      // Broadcast the event to all players in the room
      PhotonNetwork.RaiseEvent(eventCode, null, RaiseEventOptions.Default, SendOptions.SendReliable);
  }

  // Callback method to handle received events
  public void OnEvent(EventData photonEvent)
  {
      // Check the event code to determine the type of event
      if (photonEvent.Code == GameStartedEventCode)
      {
          // Handle the game start event
          Debug.Log("Game started!");
      }
      else if (photonEvent.Code == GameOverEventCode)
      {
          // Handle the game over event
          Debug.Log("Game over!");
      }
  }

  // Example method to trigger the game over event
  public void TriggerGameOver()
  {
      RaiseEvent(GameOverEventCode);
  }


}

In this example :

  1. We define two custom event codes (GameStartedEventCode and GameOverEventCode) to identify different types of events.

  2. In the Start method, if the current client is the master client (host), we trigger the game start event by calling the RaiseEvent method with the GameStartedEventCode.

  3. The RaiseEvent method sends the specified event code to all players in the room using Photon's event system.

  4. We implement the OnEvent callback method to handle received events. When an event is received, we check its event code and perform the corresponding action.

  5. Additionally, we provide an example method TriggerGameOver to demonstrate how to trigger the game over event from other parts of the code.

  6. This setup allows you to broadcast game events (such as game start or game over) to all players in the room using Photon's event system, enabling synchronized gameplay experiences in multiplayer games.

This setup allows you to broadcast game events (such as game start or game over) to all players in the room using Photon's event system, enabling synchronized gameplay experiences in multiplayer games.


I hope you found this blog post enjoyable!


More Blogs

See All