392 lines
11 KiB
C#
392 lines
11 KiB
C#
using System.Collections.Generic;
|
|
using Oculus.Platform.Models;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
|
|
namespace Oculus.Platform.Samples.VrHoops
|
|
{
|
|
public class MatchController : MonoBehaviour
|
|
{
|
|
private enum State
|
|
{
|
|
UNKNOWN = 0,
|
|
NONE = 1,
|
|
WAITING_TO_START_PRACTICE = 2,
|
|
PRACTICING = 3,
|
|
VIEWING_RESULTS_PRACTICE = 4,
|
|
WAITING_FOR_MATCH = 5,
|
|
WAITING_TO_SETUP_MATCH = 6,
|
|
PLAYING_MATCH = 7,
|
|
VIEWING_MATCH_RESULTS = 8
|
|
}
|
|
|
|
[SerializeField]
|
|
private Text m_timerText;
|
|
|
|
[SerializeField]
|
|
private Camera m_camera;
|
|
|
|
[SerializeField]
|
|
private Transform m_idleCameraTransform;
|
|
|
|
[SerializeField]
|
|
private Text m_matchmakeButtonText;
|
|
|
|
[SerializeField]
|
|
private PlayerArea[] m_playerAreas = new PlayerArea[3];
|
|
|
|
[SerializeField]
|
|
private uint PRACTICE_WARMUP_TIME = 5u;
|
|
|
|
[SerializeField]
|
|
private uint MATCH_WARMUP_TIME = 30u;
|
|
|
|
[SerializeField]
|
|
private uint MATCH_TIME = 20u;
|
|
|
|
[SerializeField]
|
|
private uint MATCH_COOLDOWN_TIME = 10u;
|
|
|
|
[SerializeField]
|
|
private GameObject m_mostWinsLeaderboard;
|
|
|
|
[SerializeField]
|
|
private GameObject m_highestScoresLeaderboard;
|
|
|
|
[SerializeField]
|
|
private GameObject m_leaderboardEntryPrefab;
|
|
|
|
[SerializeField]
|
|
private GameObject m_flytext;
|
|
|
|
private State m_currentState;
|
|
|
|
private float m_nextStateTransitionTime;
|
|
|
|
private int m_localSlot;
|
|
|
|
public float MatchStartTime
|
|
{
|
|
get
|
|
{
|
|
State currentState = m_currentState;
|
|
if (currentState == State.WAITING_TO_START_PRACTICE || currentState == State.WAITING_TO_SETUP_MATCH)
|
|
{
|
|
return m_nextStateTransitionTime;
|
|
}
|
|
return 0f;
|
|
}
|
|
private set
|
|
{
|
|
m_nextStateTransitionTime = value;
|
|
}
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
PlatformManager.Matchmaking.EnqueueResultCallback = OnMatchFoundCallback;
|
|
PlatformManager.Matchmaking.MatchPlayerAddedCallback = MatchPlayerAddedCallback;
|
|
PlatformManager.P2P.StartTimeOfferCallback = StartTimeOfferCallback;
|
|
PlatformManager.Leaderboards.MostWinsLeaderboardUpdatedCallback = MostWinsLeaderboardCallback;
|
|
PlatformManager.Leaderboards.HighScoreLeaderboardUpdatedCallback = HighestScoreLeaderboardCallback;
|
|
TransitionToState(State.NONE);
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
UpdateCheckForNextTimedTransition();
|
|
UpdateMatchTimer();
|
|
}
|
|
|
|
private void TransitionToState(State newState)
|
|
{
|
|
Debug.LogFormat("MatchController State {0} -> {1}", m_currentState, newState);
|
|
if (m_currentState != newState)
|
|
{
|
|
State currentState = m_currentState;
|
|
m_currentState = newState;
|
|
switch (newState)
|
|
{
|
|
case State.NONE:
|
|
SetupForIdle();
|
|
MoveCameraToIdlePosition();
|
|
PlatformManager.TransitionToState(PlatformManager.State.WAITING_TO_PRACTICE_OR_MATCHMAKE);
|
|
m_matchmakeButtonText.text = "Play Online";
|
|
break;
|
|
case State.WAITING_TO_START_PRACTICE:
|
|
SetupForPractice();
|
|
MoveCameraToMatchPosition();
|
|
PlatformManager.TransitionToState(PlatformManager.State.MATCH_TRANSITION);
|
|
m_nextStateTransitionTime = Time.time + (float)PRACTICE_WARMUP_TIME;
|
|
break;
|
|
case State.PRACTICING:
|
|
PlatformManager.TransitionToState(PlatformManager.State.PLAYING_A_LOCAL_MATCH);
|
|
m_nextStateTransitionTime = Time.time + (float)MATCH_TIME;
|
|
break;
|
|
case State.VIEWING_RESULTS_PRACTICE:
|
|
PlatformManager.TransitionToState(PlatformManager.State.MATCH_TRANSITION);
|
|
m_nextStateTransitionTime = Time.time + (float)MATCH_COOLDOWN_TIME;
|
|
m_timerText.text = "0:00.00";
|
|
break;
|
|
case State.WAITING_FOR_MATCH:
|
|
PlatformManager.TransitionToState(PlatformManager.State.MATCH_TRANSITION);
|
|
m_matchmakeButtonText.text = "Cancel";
|
|
break;
|
|
case State.WAITING_TO_SETUP_MATCH:
|
|
m_nextStateTransitionTime = Time.time + (float)MATCH_WARMUP_TIME;
|
|
break;
|
|
case State.PLAYING_MATCH:
|
|
PlatformManager.TransitionToState(PlatformManager.State.PLAYING_A_NETWORKED_MATCH);
|
|
m_nextStateTransitionTime = Time.time + (float)MATCH_TIME;
|
|
break;
|
|
case State.VIEWING_MATCH_RESULTS:
|
|
PlatformManager.TransitionToState(PlatformManager.State.MATCH_TRANSITION);
|
|
m_nextStateTransitionTime = Time.time + (float)MATCH_COOLDOWN_TIME;
|
|
m_timerText.text = "0:00.00";
|
|
CalculateMatchResults();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void UpdateCheckForNextTimedTransition()
|
|
{
|
|
if (m_currentState != State.NONE && Time.time >= m_nextStateTransitionTime)
|
|
{
|
|
switch (m_currentState)
|
|
{
|
|
case State.WAITING_TO_START_PRACTICE:
|
|
TransitionToState(State.PRACTICING);
|
|
break;
|
|
case State.PRACTICING:
|
|
TransitionToState(State.VIEWING_RESULTS_PRACTICE);
|
|
break;
|
|
case State.VIEWING_RESULTS_PRACTICE:
|
|
TransitionToState(State.NONE);
|
|
break;
|
|
case State.WAITING_TO_SETUP_MATCH:
|
|
TransitionToState(State.PLAYING_MATCH);
|
|
break;
|
|
case State.PLAYING_MATCH:
|
|
TransitionToState(State.VIEWING_MATCH_RESULTS);
|
|
break;
|
|
case State.VIEWING_MATCH_RESULTS:
|
|
PlatformManager.Matchmaking.EndMatch();
|
|
TransitionToState(State.NONE);
|
|
break;
|
|
case State.WAITING_FOR_MATCH:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void UpdateMatchTimer()
|
|
{
|
|
if (Time.time <= m_nextStateTransitionTime)
|
|
{
|
|
switch (m_currentState)
|
|
{
|
|
case State.WAITING_TO_START_PRACTICE:
|
|
case State.WAITING_TO_SETUP_MATCH:
|
|
m_timerText.text = string.Format("{0:0}", Mathf.Ceil(Time.time - MatchStartTime));
|
|
break;
|
|
case State.PRACTICING:
|
|
case State.PLAYING_MATCH:
|
|
{
|
|
float num = m_nextStateTransitionTime - Time.time;
|
|
m_timerText.text = string.Format("{0:#0}:{1:#00}.{2:00}", Mathf.Floor(num / 60f), Mathf.Floor(num) % 60f, Mathf.Floor(num * 100f) % 100f);
|
|
break;
|
|
}
|
|
case State.VIEWING_RESULTS_PRACTICE:
|
|
case State.WAITING_FOR_MATCH:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void SetupForIdle()
|
|
{
|
|
for (int i = 0; i < m_playerAreas.Length; i++)
|
|
{
|
|
m_playerAreas[i].SetupForPlayer<AIPlayer>("* AI *");
|
|
}
|
|
}
|
|
|
|
private void SetupForPractice()
|
|
{
|
|
m_localSlot = Random.Range(0, m_playerAreas.Length - 1);
|
|
for (int i = 0; i < m_playerAreas.Length; i++)
|
|
{
|
|
if (i == m_localSlot)
|
|
{
|
|
m_playerAreas[i].SetupForPlayer<LocalPlayer>(PlatformManager.MyOculusID);
|
|
}
|
|
else
|
|
{
|
|
m_playerAreas[i].SetupForPlayer<AIPlayer>("* AI *");
|
|
}
|
|
}
|
|
}
|
|
|
|
private Player MatchPlayerAddedCallback(int slot, User user)
|
|
{
|
|
Player result = null;
|
|
if (m_currentState == State.WAITING_TO_SETUP_MATCH && slot < m_playerAreas.Length)
|
|
{
|
|
if (user.ID == PlatformManager.MyID)
|
|
{
|
|
LocalPlayer localPlayer = m_playerAreas[slot].SetupForPlayer<LocalPlayer>(user.OculusID);
|
|
MoveCameraToMatchPosition();
|
|
result = localPlayer;
|
|
m_localSlot = slot;
|
|
}
|
|
else
|
|
{
|
|
RemotePlayer remotePlayer = m_playerAreas[slot].SetupForPlayer<RemotePlayer>(user.OculusID);
|
|
remotePlayer.User = user;
|
|
result = remotePlayer;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private void MoveCameraToIdlePosition()
|
|
{
|
|
BallEjector componentInChildren = m_camera.gameObject.GetComponentInChildren<BallEjector>();
|
|
if ((bool)componentInChildren)
|
|
{
|
|
componentInChildren.transform.SetParent(m_camera.transform.parent, false);
|
|
m_camera.transform.SetParent(m_idleCameraTransform, false);
|
|
}
|
|
}
|
|
|
|
private void MoveCameraToMatchPosition()
|
|
{
|
|
PlayerArea[] playerAreas = m_playerAreas;
|
|
foreach (PlayerArea playerArea in playerAreas)
|
|
{
|
|
LocalPlayer componentInChildren = playerArea.GetComponentInChildren<LocalPlayer>();
|
|
if ((bool)componentInChildren)
|
|
{
|
|
BallEjector componentInChildren2 = componentInChildren.GetComponentInChildren<BallEjector>();
|
|
m_camera.transform.SetParent(componentInChildren.transform, false);
|
|
componentInChildren2.transform.SetParent(m_camera.transform, false);
|
|
break;
|
|
}
|
|
}
|
|
DisplayAchievementFlytext();
|
|
}
|
|
|
|
public void StartPracticeMatch()
|
|
{
|
|
if (m_currentState == State.NONE)
|
|
{
|
|
TransitionToState(State.WAITING_TO_START_PRACTICE);
|
|
}
|
|
}
|
|
|
|
public void PlayOnlineOrCancel()
|
|
{
|
|
Debug.Log("Play online or Cancel");
|
|
if (m_currentState == State.NONE)
|
|
{
|
|
PlatformManager.Matchmaking.QueueForMatch();
|
|
TransitionToState(State.WAITING_FOR_MATCH);
|
|
}
|
|
else if (m_currentState == State.WAITING_FOR_MATCH)
|
|
{
|
|
PlatformManager.Matchmaking.LeaveQueue();
|
|
TransitionToState(State.NONE);
|
|
}
|
|
}
|
|
|
|
private void OnMatchFoundCallback(bool success)
|
|
{
|
|
if (success)
|
|
{
|
|
TransitionToState(State.WAITING_TO_SETUP_MATCH);
|
|
}
|
|
else
|
|
{
|
|
TransitionToState(State.NONE);
|
|
}
|
|
}
|
|
|
|
private float StartTimeOfferCallback(float remoteTime)
|
|
{
|
|
if (m_currentState == State.WAITING_TO_SETUP_MATCH && remoteTime > MatchStartTime && remoteTime - 60f < MatchStartTime)
|
|
{
|
|
Debug.Log("Moving Start time by " + (remoteTime - MatchStartTime));
|
|
MatchStartTime = remoteTime;
|
|
}
|
|
return MatchStartTime;
|
|
}
|
|
|
|
private void MostWinsLeaderboardCallback(SortedDictionary<int, LeaderboardEntry> entries)
|
|
{
|
|
foreach (Transform item in m_mostWinsLeaderboard.transform)
|
|
{
|
|
Object.Destroy(item.gameObject);
|
|
}
|
|
foreach (LeaderboardEntry value in entries.Values)
|
|
{
|
|
GameObject gameObject = Object.Instantiate(m_leaderboardEntryPrefab);
|
|
gameObject.transform.SetParent(m_mostWinsLeaderboard.transform, false);
|
|
gameObject.GetComponent<Text>().text = string.Format("{0} - {1} - {2}", value.Rank, value.User.OculusID, value.Score);
|
|
}
|
|
}
|
|
|
|
private void HighestScoreLeaderboardCallback(SortedDictionary<int, LeaderboardEntry> entries)
|
|
{
|
|
foreach (Transform item in m_highestScoresLeaderboard.transform)
|
|
{
|
|
Object.Destroy(item.gameObject);
|
|
}
|
|
foreach (LeaderboardEntry value in entries.Values)
|
|
{
|
|
GameObject gameObject = Object.Instantiate(m_leaderboardEntryPrefab);
|
|
gameObject.transform.SetParent(m_highestScoresLeaderboard.transform, false);
|
|
gameObject.GetComponent<Text>().text = string.Format("{0} - {1} - {2}", value.Rank, value.User.OculusID, value.Score);
|
|
}
|
|
}
|
|
|
|
private void CalculateMatchResults()
|
|
{
|
|
LocalPlayer localPlayer = null;
|
|
RemotePlayer remotePlayer = null;
|
|
PlayerArea[] playerAreas = m_playerAreas;
|
|
foreach (PlayerArea playerArea in playerAreas)
|
|
{
|
|
if (playerArea.Player is LocalPlayer)
|
|
{
|
|
localPlayer = playerArea.Player as LocalPlayer;
|
|
}
|
|
else if (playerArea.Player is RemotePlayer && (remotePlayer == null || playerArea.Player.Score > remotePlayer.Score))
|
|
{
|
|
remotePlayer = playerArea.Player as RemotePlayer;
|
|
}
|
|
}
|
|
if ((bool)localPlayer && (bool)remotePlayer)
|
|
{
|
|
bool flag = localPlayer.Score > remotePlayer.Score;
|
|
PlatformManager.Leaderboards.SubmitMatchScores(flag, localPlayer.Score);
|
|
if (flag)
|
|
{
|
|
PlatformManager.Achievements.RecordWinForLocalUser();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void DisplayAchievementFlytext()
|
|
{
|
|
if (PlatformManager.Achievements.LikesToWin)
|
|
{
|
|
GameObject gameObject = Object.Instantiate(m_flytext);
|
|
gameObject.GetComponent<Text>().text = "Likes to Win!";
|
|
gameObject.transform.position = Vector3.up * 40f;
|
|
gameObject.transform.SetParent(m_playerAreas[m_localSlot].NameText.transform, false);
|
|
}
|
|
}
|
|
}
|
|
}
|