I have two scripts one manages the PhotonNetwork which is responsible for loging in with nickname, creating and joining room and other instantiating the player, I have have two scenes once scene consists PhotonNetwork_Manager which has network manager scene which is shown below.
using System.Collections;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using Photon.Pun;
using Photon.Realtime;
public class Photon_Manager : MonoBehaviourPunCallbacks
{
[SerializeField] TMP_InputField nameField;
[SerializeField] TMP_InputField roomNameField;
[SerializeField] TMP_InputField joinRoomField;
[SerializeField] GameObject createJoinCanvas;
[SerializeField] GameObject logInCanvas;
[SerializeField] GameObject createCanvas;
[SerializeField] GameObject joinCanvas;
[SerializeField] string sceneToLoad;
[SerializeField] public bool createRoomStatus = false;
[SerializeField] public bool joinRoomStatus = false;
[SerializeField] public bool logInStatus = false;
public override void OnConnectedToMaster()
{
Debug.Log("Connected to master server");
PhotonNetwork.JoinLobby();
}
public override void OnCreatedRoom()
{
Debug.Log("Created room: " PhotonNetwork.CurrentRoom.Name);
}
void Start()
{
Debug.Log(" started");
}
public void LogIn()
{
StartCoroutine(waitSeconds());
string temp = nameField.text;
PhotonNetwork.LocalPlayer.NickName = temp;
PhotonNetwork.ConnectUsingSettings();
logInCanvas.SetActive(false);
createJoinCanvas.SetActive(true);
logInStatus = true;
Debug.Log("LogIn Done");
}
public void CreateRoom()
{
StartCoroutine(waitSeconds());
string roomName = roomNameField.text;
PhotonNetwork.CreateRoom(roomName);
createCanvas.SetActive(false);
ChangeScene(sceneToLoad);
createRoomStatus = true;
Debug.Log(PhotonNetwork.LocalPlayer.NickName " joined " roomName);
}
public void JoinRoom()
{
StartCoroutine(waitSeconds());
string tempRoomName = joinRoomField.text;
PhotonNetwork.JoinRoom(tempRoomName);
joinCanvas.SetActive(false);
ChangeScene(sceneToLoad);
joinRoomStatus = true;
Debug.Log(PhotonNetwork.LocalPlayer.NickName " joined " tempRoomName);
}
public void ChangeScene(string sceneName)
{
StartCoroutine(waitSeconds());
PhotonNetwork.LoadLevel(sceneName);
}
public IEnumerator waitSeconds()
{
yield return new WaitForSeconds(2.5f);
}
}
other scene has Instantiate player to instantiate player, but whenever I run the application player is not spawned even though it has Photon view component attached to it. Below is script to instantiate player.
using UnityEngine;
using Photon.Pun;
using System.Collections;
public class Instantiate_Player : MonoBehaviour
{
[SerializeField] GameObject playerPrefab;
[SerializeField] float xMin;
[SerializeField] float zMin;
[SerializeField] float xMax;
[SerializeField] float zMax;
void Start()
{
StartCoroutine(waitSeconds());
if (PhotonNetwork.IsConnectedAndReady)
{
Vector3 playerPos = new Vector3(Random.Range(xMin, xMax), 0.0f, Random.Range(zMin, zMax));
GameObject obj = PhotonNetwork.Instantiate(playerPrefab.name, playerPos, Quaternion.identity, 1, null);
obj.SetActive(true);
}
}
public IEnumerator waitSeconds()
{
yield return new WaitForSeconds(1.5f);
}
}
What could be the problem??, the player has movement script attached to it with camera as its child.
CodePudding user response:
Note that your Coroutine waitSeconds
does .. absolutely nothing at all!
Using StartCoroutine
does not delay the code which is calling it!
You could give it a callback to do after the time has passed like e.g.
public class Photon_Manager : MonoBehaviourPunCallbacks
{
...
public void LogIn()
{
// You can directly pass in a lambda expression
StartCoroutine(waitSeconds(() =>
{
string temp = nameField.text;
PhotonNetwork.LocalPlayer.NickName = temp;
PhotonNetwork.ConnectUsingSettings();
logInCanvas.SetActive(false);
createJoinCanvas.SetActive(true);
logInStatus = true;
Debug.Log("LogIn Done");
});
}
public void CreateRoom()
{
// or as demo pass in an explicit method
StartCoroutine(waitSeconds(CreateRoomDelayed);
}
private void CreateRoomDelayed()
{
string roomName = roomNameField.text;
PhotonNetwork.CreateRoom(roomName);
createCanvas.SetActive(false);
ChangeScene(sceneToLoad);
createRoomStatus = true;
Debug.Log(PhotonNetwork.LocalPlayer.NickName " joined " roomName);
}
...
private IEnumerator waitSeconds(Action whenDone)
{
yield return new WaitForSeconds(2.5f);
whenDone?.Invoke();
}
}
Though tbh from a user perspective it seems quite odd that I have to wait 2.5 seconds (which is looong) in order to get a reaction to e.g. clicking LogIn.
You can also make Start
return IEnumerator
itself. In that case Unity automatically runs it as a Coroutine:
public class Instantiate_Player : MonoBehaviour
{
...
IEnumerator Start()
{
yield return new WaitForSeconds(1.5f);
if (PhotonNetwork.IsConnectedAndReady)
{
Vector3 playerPos = new Vector3(Random.Range(xMin, xMax), 0.0f, Random.Range(zMin, zMax));
GameObject obj = PhotonNetwork.Instantiate(playerPrefab.name, playerPos, Quaternion.identity, 1, null);
obj.SetActive(true);
}
}
}
In general though:
Waiting based on a fixed time is always dirty and error prone. coul rather wait until you are actually connected:
IEnumerator Start()
{
yield return new WaitUntil(() => PhotonNetwork.IsConnectedAndReady);
Vector3 playerPos = new Vector3(Random.Range(xMin, xMax), 0.0f, Random.Range(zMin, zMax));
GameObject obj = PhotonNetwork.Instantiate(playerPrefab.name, playerPos, Quaternion.identity, 1, null);
obj.SetActive(true);
}