Megacity demo game for UOS
您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

340 行
12 KiB

// Add Platforms here that exclude Quit Menu option
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Unity.MegaCity.Audio;
using UnityEngine;
using Unity.MegaCity.CameraManagement;
using Unity.MegaCity.Gameplay;
using UnityEngine.SceneManagement;
using UnityEngine.UIElements;
using UnityEngine.UIElements.Experimental;
using Random = UnityEngine.Random;
namespace Unity.MegaCity.UI
{
public enum MultiplayerMode
{
Matchmaker = 0,
Connect = 1
}
/// <summary>
/// Manages the UI for the main menu.
/// This sets the audio settings for the city.
/// Defines if the player should be manual or automatic.
/// Allows the execution to exiting by pressing Escape
/// Has access to the UI game settings
/// </summary>
public class MainMenu : MonoBehaviour
{
public HybridCameraManager m_HybridCameraManager;
[SerializeField] private AudioMaster m_AudioMaster;
[SerializeField] private UIGameSettings m_GameSettings;
[SerializeField] private GameObject m_LobbyPanel;
[SerializeField] private GameObject m_IPConnectorPanel;
[field: SerializeField]
public MultiplayerMode SelectedMultiplayerMode { get; private set; } = MultiplayerMode.Matchmaker;
public AudioMaster AudioMaster => m_AudioMaster;
private int m_CurrentMenuItem;
private int m_PrevMenuItem;
private Button m_PlayerControllerButton;
private Button m_IPConnectorControllerButton;
private Button m_QuitButton;
private Button m_GameSettingsButton;
private VisualElement m_VisualMenu;
private VisualElement m_OverlayMenu;
private VisualElement m_MainMenuContainer;
private List<Button> m_Options;
// 进度条控制
private float _mockProgress = -1;
private float _deltaTime = 0;
public static MainMenu Instance { get; private set; }
public bool IsVisible => m_VisualMenu.style.display == DisplayStyle.Flex;
private void Awake()
{
if (Instance == null)
{
Instance = this;
}
else
{
Destroy(gameObject);
return;
}
}
private void OnDestroy()
{
if (Instance == this)
Instance = null;
}
private void Start()
{
// too strongly coupled to the ui so there we go :(
// In Awake() the AudioManager is not present (before OnEnable()) so we would run into a null-ref exception.
#if UNITY_SERVER && !UNITY_EDITOR
Debug.Log("Beginning server mode");
gameObject.SetActive(false);
return;
#else
MultiverseRoomAPI.Instance.ClientIsInGame = false;
InitUI();
#endif
}
private void InitUI()
{
m_Options = new List<Button>();
m_MainMenuContainer = GetComponent<UIDocument>().rootVisualElement;
m_PlayerControllerButton = m_MainMenuContainer.Q<Button>("lobby-controller-button");
m_IPConnectorControllerButton = m_MainMenuContainer.Q<Button>("ip-controller-button");
m_GameSettingsButton = m_MainMenuContainer.Q<Button>("settings-button");
m_QuitButton = m_MainMenuContainer.Q<Button>("quit-button");
m_VisualMenu = m_MainMenuContainer.Q<VisualElement>("visual-menu");
m_OverlayMenu = m_MainMenuContainer.Q<VisualElement>("overlay");
m_VisualMenu.style.display = DisplayStyle.Flex;
var userName = MultiverseRoomAPI.Instance.PlayerName;
Debug.Log($"Initializing UI as {userName}");
if (!string.IsNullOrEmpty(userName))
{
PlayerInfoController.Instance.Name = userName;
}
m_PlayerControllerButton.clicked += () =>
{
m_CurrentMenuItem = 0;
SelectItem();
};
m_IPConnectorControllerButton.clicked += () =>
{
m_CurrentMenuItem = 3;
SelectItem();
};
m_GameSettingsButton.clicked += () =>
{
m_CurrentMenuItem = 1;
SelectItem();
};
m_QuitButton.clicked += () =>
{
m_CurrentMenuItem = 2;
SelectItem();
};
m_PlayerControllerButton.RegisterCallback<MouseOverEvent>(e => { m_CurrentMenuItem = 0; });
m_GameSettingsButton.RegisterCallback<MouseOverEvent>(e => { m_CurrentMenuItem = 1; });
m_QuitButton.RegisterCallback<MouseOverEvent>(e => { m_CurrentMenuItem = 2; });
m_Options.Add(m_PlayerControllerButton);
m_Options.Add(m_GameSettingsButton);
m_Options.Add(m_QuitButton);
SetMenuOptionUIElements(m_CurrentMenuItem);
SetConnectionMode(SelectedMultiplayerMode);
SetupCosmeticFlickering(m_MainMenuContainer);
}
private string FilterNonAlphanumeric(string input)
{
return Regex.Replace(input, @"[^a-zA-Z0-9-_]", string.Empty);
}
private void SetConnectionMode(MultiplayerMode mode)
{
SelectedMultiplayerMode = mode;
var isMatchMaking = mode == MultiplayerMode.Matchmaker;
}
private void OnLobbyPanelSelected()
{
if (MultiverseRoomAPI.Instance.ClientIsInGame)
{
Debug.LogWarning("Cant hit play while already in-game!");
return;
}
// show lobby panel
m_LobbyPanel.SetActive(true);
}
private void OnIPConnectorPanelSelected()
{
if (MultiverseRoomAPI.Instance.ClientIsInGame)
{
Debug.LogWarning("Cant hit play while already in-game!");
return;
}
// show lobby panel
m_IPConnectorPanel.SetActive(true);
}
public void ConnectionSucceeded()
{
m_HybridCameraManager.m_CameraTargetMode = HybridCameraManager.CameraTargetMode.FollowPlayer;
m_LobbyPanel.SetActive(false);
m_IPConnectorPanel.SetActive(false);
MultiverseRoomAPI.Instance.ConnectionSucceeded();
AnimateOut();
}
public void ConnectionFailed()
{
MultiverseRoomAPI.Instance.ConnectionFailed();
SceneManager.LoadScene("MegaCity");
m_IPConnectorPanel.SetActive(false);
m_LobbyPanel.SetActive(false);
HideLoading();
}
public void Show()
{
m_VisualMenu.style.display = DisplayStyle.Flex;
m_VisualMenu.visible = true;
MultiverseRoomAPI.Instance.ClientIsInGame = false;
CursorUtils.ShowCursor(true);
}
private void AnimateOut()
{
HideLoading();
//LoadAudioSettings();
m_OverlayMenu.style.display = DisplayStyle.Flex;
m_OverlayMenu.experimental.animation
.Start(new StyleValues { opacity = 1 }, 1000)
.Ease(Easing.Linear)
.OnCompleted(() =>
{
m_VisualMenu.style.display = DisplayStyle.None;
m_VisualMenu.visible = false;
m_OverlayMenu.experimental.animation
.Start(new StyleValues { opacity = 0f }, 2000)
.Ease(Easing.Linear)
.OnCompleted(() => { m_OverlayMenu.style.display = DisplayStyle.None; });
// Show HUD
TutorialScreen.Instance.ShowTutorial();
});
}
private void Update()
{
if (_mockProgress >= 0 && _mockProgress < 95)
{
_deltaTime += Time.deltaTime;
if (_deltaTime > 1)
{
_deltaTime = 0;
_mockProgress += Random.Range(0, 7);
// 每秒进度 + 1 或 + 2
LoadingScreen.Instance.UpdateProgressBar(_mockProgress / 100);
}
}
if (!IsVisible)
return;
if (Input.GetKeyDown(KeyCode.Escape) && !m_GameSettings.IsVisible)
QuitSystem.WantsToQuit = true;
// Only restrict update interval with respect to moving, not selecting
if (Input.GetKeyDown(KeyCode.DownArrow))
++m_CurrentMenuItem;
else if (Input.GetKeyDown(KeyCode.UpArrow))
--m_CurrentMenuItem;
else if (Input.GetKeyDown(KeyCode.Return))
SelectItem();
m_CurrentMenuItem =
Mathf.Clamp(m_CurrentMenuItem, 0, m_Options.Count > 0 ? m_Options.Count - 1 : 0);
if (m_CurrentMenuItem != m_PrevMenuItem)
{
SetMenuOptionUIElements(m_CurrentMenuItem);
m_PrevMenuItem = m_CurrentMenuItem;
}
}
private void SetMenuOptionUIElements(int optionActive)
{
foreach (var buttonOption in m_Options)
buttonOption.RemoveFromClassList("button-menu-active");
m_Options[optionActive].AddToClassList("button-menu-active");
}
private void SelectItem()
{
switch (m_CurrentMenuItem)
{
case 0:
OnLobbyPanelSelected();
break;
case 1:
ShowGameSettings();
break;
case 2:
QuitDemo();
break;
case 3:
OnIPConnectorPanelSelected();
break;
}
}
private void QuitDemo()
{
QuitSystem.WantsToQuit = true;
}
private void ShowGameSettings()
{
m_GameSettings.Show(m_VisualMenu);
m_VisualMenu.style.display = DisplayStyle.None;
}
private void SetupCosmeticFlickering(VisualElement root)
{
var flickeringElements = root.Query(className: "flicker").ToList();
foreach (var flickeringElement in flickeringElements)
{
var randomDelay = Random.Range(1, 4);
flickeringElement.AddToClassList($"transition-{randomDelay}");
flickeringElement.RegisterCallback<TransitionEndEvent>(_ =>
flickeringElement.ToggleInClassList("flicker-loop"));
root.schedule.Execute(() => flickeringElement.ToggleInClassList("flicker-loop")).StartingIn(100);
}
}
public void ShowLoading()
{
LoadingScreen.Instance.UpdateProgressBar(0);
LoadingScreen.Instance.Show();
LoadingScreen.Instance.UpdateProgressBar(0);
_mockProgress = 0;
m_LobbyPanel.SetActive(false);
m_IPConnectorPanel.SetActive(false);
}
public void HideLoading()
{
_mockProgress = -1;
LoadingScreen.Instance.UpdateProgressBar(1);
LoadingScreen.Instance.Hide();
}
}
}