Multijugador con Photon

Curso de Unity 3D

21.  
40.  

Por 9.99€ al mes tendrás acceso completo a todos los cursos. Sin matrícula ni permanencia.

Vamos a utilizar los servidores de Photon para hacer un juego multijugador. Estos servidores tienen instalada una aplicación llamada PhotonServer. Nosotros también podríamos instalar PhotonServer en nuestro propio servidor, pero utilizando los servidores de Photon nos ahorramos este paso. Los servidores de Photon reciben el nombre de Photon Cloud

PUN (Photon Unity NetWorking) es un framework que tiene scripts que nos facilitan programar videojuegos multiplayer. PUN es:

  • gratuito hasta los 20 UCC (Usuarios Conectados Simultáneamente). Si sobrepasas el límite, los nuevos usuarios no se podrán conectar.
  • Hay un límite de 500 mensajes por Room (partida).

Conexión y Join una Room

  1. Registramos una cuenta en https://www.photonengine.com/
  2. Tras loguearnos creamos una nueva aplicación cuyo Photon Type será Photon PUN.
  3. Copiamos el App ID de la aplicación.
  4. Vamos a Unity 3D e instalamos Photon Networking 2 Free. Al termino de la instalación nos pide un código. Pegamos el código de antes.
  5. Creamos un Empty al que vinculamos el siguiente código:
    1. Cuando pulsamos el botón de Connect, llamamos a la función Connect()
    2. Cuando nos hemos conectado, se ejecuta automáticamente el método OnConnectedToMaster(). Este método habilitará el botón Join Random
    3. Cuando pulsamos el botón de Join Random, llamamos a la función JoinRandom()
    4. Cuando nos hemos unido a una room, se ejecuta automáticamente el método OnJoinedRoom()(). Dentro del FixedUpdate, evaluamos constantemente si nos hemos unido a una Room.Este método habilitará el botón Join Random
using System.Collections;
using System.Collections.Generic;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.UI;
namespace Photon.Pun.Demo.PunBasics{
	public class AutoLobby : MonoBehaviourPunCallbacks{
		public Text Log;
		public Text PlayerCount;
		public int playersCount;

		public byte maxPlayersPerRoom = 4;
		public byte minPlayersPerRoom = 2;
		private string roomName = "amor";
		public Button buttonJoinRoom;
		public Button buttonLoadArena;
		public Text nombre;

		void Start(){
			// La IP del servidor al que se conectará el player será almacenada en las PlayerPrefs.
			// Debemos resetear las PlayerPrefs para evitar ciertos problemas de conexión
			PlayerPrefs.DeleteAll();
			ConnectToPhoton();
		}

		void Awake(){
			// La siguiente línea nos permite sincronizar la escena para todos los players de la room
			PhotonNetwork.AutomaticallySyncScene = true;
		}

		void ConnectToPhoton(){
			Log.text = "Connecting...";
			PhotonNetwork.GameVersion = ""+1; //1
			if (PhotonNetwork.ConnectUsingSettings()){
				Log.text += "\n Connected to server";
			}else{
				Log.text += "\n Falling Connecting to Server";
			}
		}

		// Photon Methods
		public override void OnConnected(){
			base.OnConnected();
			Log.text += "\nConnected to Photon!";

			buttonJoinRoom.interactable = true;
			buttonLoadArena.interactable = false;
		}

		public void JoinRoom(){
			Log.text += "\nJoinRoom() method";

			if (PhotonNetwork.IsConnected){
				PhotonNetwork.LocalPlayer.NickName = nombre.GetComponent<Text>().text; //1
				Log.text += "\nPhotonNetwork.IsConnected! | Trying to Create/Join Room ";
				RoomOptions roomOptions = new RoomOptions(); //2
				TypedLobby typedLobby = new TypedLobby(roomName, LobbyType.Default); //3
				PhotonNetwork.JoinOrCreateRoom(roomName, roomOptions, typedLobby); //4

				Log.text +="\nFin JoinRoom(): " + PhotonNetwork.LocalPlayer.NickName;
			}
		}

		public override void OnJoinedRoom(){
			if (PhotonNetwork.IsMasterClient){
				buttonJoinRoom.interactable = false;
				buttonLoadArena.interactable = true;
				Log.text += "\nYour are Lobby Leader";
			}else{
				Log.text += "\nConnected to Lobby";
			}
		}

		public void LoadArena(){
			if (PhotonNetwork.CurrentRoom.PlayerCount > 1){
				PhotonNetwork.LoadLevel("Game");
			}else{
				Log.text += "\nMinimum 2 Players required to Load Arena!";
			}
		}

		void Update(){
			if (PhotonNetwork.InRoom){
				playersCount = PhotonNetwork.CurrentRoom.PlayerCount;
				PlayerCount.text = playersCount + "/" + maxPlayersPerRoom;
			}
		}
        
		public override void OnJoinRandomFailed(short returnCode, string message){
			Log.text += "\nNo Rooms to Join, creating one...";
			if (PhotonNetwork.CreateRoom(null, new Photon.Realtime.RoomOptions() { MaxPlayers = maxPlayersPerRoom })){
				Log.text += "\n Room Created";
			}else{
				Log.text += "\nFail Creating Room";
			}
		}
	}
}
multijugador con photon

Cargamos la escena de juego

Para que el siguiente código funcione, debemos tener el prefab PlayerMonteserin almacenado en la carpeta Assets/Resources.

Además, el Prefab PlayerMonteserin debe tener un componente PhotonView.

1. AutoLobby.cs
...

private void LoadMap(){
	PhotonNetwork.LoadLevel("Game");
}

2. GameManager.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using UnityEngine.UI;
namespace Photon.Pun.Demo.PunBasics{ 
	public class GameManager : MonoBehaviourPunCallbacks{
		private GameObject player1;
		private GameObject player2;
		public Transform player1Position;
		public Transform player2Position;

		void Start(){
			if (PlayerManager.LocalPlayerInstance == null){
				if (PhotonNetwork.IsMasterClient){
					player1 = PhotonNetwork.Instantiate("PlayerMonteserin", player1Position.transform.position, player1Position.transform.rotation, 0);
				}else{
					player2 = PhotonNetwork.Instantiate("PlayerMonteserin", player2Position.transform.position, player2Position.transform.rotation, 0);
				}
			}
		}
	}
}

3. Creamos el Prefab de nuestro player.

Player.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;

public class Player : Photon.Pun.MonoBehaviourPun{
    Controls controls;
    PhotonView photonView;
    enum Controls {
        Idle,
        Left,
        Right
    }

    private void Start(){
        photonView = gameObject.GetComponent<PhotonView>();
    }

    void Update(){
        if (photonView.IsMine){
            if (Input.GetKey(KeyCode.LeftArrow)){
                controls = Controls.Left;
            }else if (Input.GetKey(KeyCode.RightArrow)){
                controls = Controls.Right;
            }
            Move();
        }
    }

    private void Move(){
        if (controls == Controls.Left){
            transform.Translate(new Vector2(-0.01f, 0));
        }else if (controls == Controls.Right){
            transform.Translate(new Vector2(0.01f, 0));
        }
    }
}
  1. Añadimos al GameObject del Prefab los siguientes scripts:
    • PhotonView ubicado en /Assets/Photon/PhotonUnityNetworking/Code/
    • PhotonTransformView ubicado en /Assets/Photon/PhotonUnityNetworking/Code/Views/
  2. Arrastramos el componente PhotonTransformView al campo Observed ComponentsTransformView.
  3. Debemos asegurarnos de que el TransformView tiene la opción Observe option con el valor Unreliable On Change
    Multijugador con Photon 1
  4. En este momento, si compilamos el juego y lo ejecutamos dos veces, veremos que al mover el personaje en una de las dos instancias de juego, este se mueve en la otra instancia de juego. Es mejor que probemos el juego en dispositivos independientes. Arrancando dos instancias del juego en el mismo dispositivo, la sincronización era bastante mala.

Por 9.99€ al mes tendrás acceso completo a todos los cursos. Sin matrícula ni permanencia.