Pun-01/Assets/Photon/PhotonUnityNetworking/Demos/DemoAsteroids/Scripts/Game/AsteroidsGameManager.cs
2022-07-08 09:14:55 +08:00

267 lines
8.6 KiB
C#

// --------------------------------------------------------------------------------------------------------------------
// <copyright file="AsteroidsGameManager.cs" company="Exit Games GmbH">
// Part of: Asteroid demo
// </copyright>
// <summary>
// Game Manager for the Asteroid Demo
// </summary>
// <author>developer@exitgames.com</author>
// --------------------------------------------------------------------------------------------------------------------
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using Photon.Realtime;
using Photon.Pun.UtilityScripts;
using Hashtable = ExitGames.Client.Photon.Hashtable;
namespace Photon.Pun.Demo.Asteroids
{
public class AsteroidsGameManager : MonoBehaviourPunCallbacks
{
public static AsteroidsGameManager Instance = null;
public Text InfoText;
public GameObject[] AsteroidPrefabs;
#region UNITY
public void Awake()
{
Instance = this;
}
public override void OnEnable()
{
base.OnEnable();
CountdownTimer.OnCountdownTimerHasExpired += OnCountdownTimerIsExpired;
}
public void Start()
{
Hashtable props = new Hashtable
{
{AsteroidsGame.PLAYER_LOADED_LEVEL, true}
};
PhotonNetwork.LocalPlayer.SetCustomProperties(props);
}
public override void OnDisable()
{
base.OnDisable();
CountdownTimer.OnCountdownTimerHasExpired -= OnCountdownTimerIsExpired;
}
#endregion
#region COROUTINES
private IEnumerator SpawnAsteroid()
{
while (true)
{
yield return new WaitForSeconds(Random.Range(AsteroidsGame.ASTEROIDS_MIN_SPAWN_TIME, AsteroidsGame.ASTEROIDS_MAX_SPAWN_TIME));
Vector2 direction = Random.insideUnitCircle;
Vector3 position = Vector3.zero;
if (Mathf.Abs(direction.x) > Mathf.Abs(direction.y))
{
// Make it appear on the left/right side
position = new Vector3(Mathf.Sign(direction.x) * Camera.main.orthographicSize * Camera.main.aspect, 0, direction.y * Camera.main.orthographicSize);
}
else
{
// Make it appear on the top/bottom
position = new Vector3(direction.x * Camera.main.orthographicSize * Camera.main.aspect, 0, Mathf.Sign(direction.y) * Camera.main.orthographicSize);
}
// Offset slightly so we are not out of screen at creation time (as it would destroy the asteroid right away)
position -= position.normalized * 0.1f;
Vector3 force = -position.normalized * 1000.0f;
Vector3 torque = Random.insideUnitSphere * Random.Range(500.0f, 1500.0f);
object[] instantiationData = {force, torque, true};
PhotonNetwork.InstantiateRoomObject("BigAsteroid", position, Quaternion.Euler(Random.value * 360.0f, Random.value * 360.0f, Random.value * 360.0f), 0, instantiationData);
}
}
private IEnumerator EndOfGame(string winner, int score)
{
float timer = 5.0f;
while (timer > 0.0f)
{
InfoText.text = string.Format("Player {0} won with {1} points.\n\n\nReturning to login screen in {2} seconds.", winner, score, timer.ToString("n2"));
yield return new WaitForEndOfFrame();
timer -= Time.deltaTime;
}
PhotonNetwork.LeaveRoom();
}
#endregion
#region PUN CALLBACKS
public override void OnDisconnected(DisconnectCause cause)
{
UnityEngine.SceneManagement.SceneManager.LoadScene("DemoAsteroids-LobbyScene");
}
public override void OnLeftRoom()
{
PhotonNetwork.Disconnect();
}
public override void OnMasterClientSwitched(Player newMasterClient)
{
if (PhotonNetwork.LocalPlayer.ActorNumber == newMasterClient.ActorNumber)
{
StartCoroutine(SpawnAsteroid());
}
}
public override void OnPlayerLeftRoom(Player otherPlayer)
{
CheckEndOfGame();
}
public override void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps)
{
if (changedProps.ContainsKey(AsteroidsGame.PLAYER_LIVES))
{
CheckEndOfGame();
return;
}
if (!PhotonNetwork.IsMasterClient)
{
return;
}
// if there was no countdown yet, the master client (this one) waits until everyone loaded the level and sets a timer start
int startTimestamp;
bool startTimeIsSet = CountdownTimer.TryGetStartTime(out startTimestamp);
if (changedProps.ContainsKey(AsteroidsGame.PLAYER_LOADED_LEVEL))
{
if (CheckAllPlayerLoadedLevel())
{
if (!startTimeIsSet)
{
CountdownTimer.SetStartTime();
}
}
else
{
// not all players loaded yet. wait:
Debug.Log("setting text waiting for players! ",this.InfoText);
InfoText.text = "Waiting for other players...";
}
}
}
#endregion
// called by OnCountdownTimerIsExpired() when the timer ended
private void StartGame()
{
Debug.Log("StartGame!");
// on rejoin, we have to figure out if the spaceship exists or not
// if this is a rejoin (the ship is already network instantiated and will be setup via event) we don't need to call PN.Instantiate
float angularStart = (360.0f / PhotonNetwork.CurrentRoom.PlayerCount) * PhotonNetwork.LocalPlayer.GetPlayerNumber();
float x = 20.0f * Mathf.Sin(angularStart * Mathf.Deg2Rad);
float z = 20.0f * Mathf.Cos(angularStart * Mathf.Deg2Rad);
Vector3 position = new Vector3(x, 0.0f, z);
Quaternion rotation = Quaternion.Euler(0.0f, angularStart, 0.0f);
PhotonNetwork.Instantiate("Spaceship", position, rotation, 0); // avoid this call on rejoin (ship was network instantiated before)
if (PhotonNetwork.IsMasterClient)
{
StartCoroutine(SpawnAsteroid());
}
}
private bool CheckAllPlayerLoadedLevel()
{
foreach (Player p in PhotonNetwork.PlayerList)
{
object playerLoadedLevel;
if (p.CustomProperties.TryGetValue(AsteroidsGame.PLAYER_LOADED_LEVEL, out playerLoadedLevel))
{
if ((bool) playerLoadedLevel)
{
continue;
}
}
return false;
}
return true;
}
private void CheckEndOfGame()
{
bool allDestroyed = true;
foreach (Player p in PhotonNetwork.PlayerList)
{
object lives;
if (p.CustomProperties.TryGetValue(AsteroidsGame.PLAYER_LIVES, out lives))
{
if ((int) lives > 0)
{
allDestroyed = false;
break;
}
}
}
if (allDestroyed)
{
if (PhotonNetwork.IsMasterClient)
{
StopAllCoroutines();
}
string winner = "";
int score = -1;
foreach (Player p in PhotonNetwork.PlayerList)
{
if (p.GetScore() > score)
{
winner = p.NickName;
score = p.GetScore();
}
}
StartCoroutine(EndOfGame(winner, score));
}
}
private void OnCountdownTimerIsExpired()
{
StartGame();
}
}
}