385 lines
13 KiB
C#
385 lines
13 KiB
C#
using System;
|
|
using UnityEngine;
|
|
using UnityEngine.SceneManagement;
|
|
using UnityEngine.UI;
|
|
#if ENABLE_INPUT_SYSTEM
|
|
using UnityEngine.InputSystem;
|
|
#endif
|
|
|
|
namespace RaceFields.GameFlow
|
|
{
|
|
public sealed class SelectionMenuController : MonoBehaviour
|
|
{
|
|
[Serializable]
|
|
public sealed class VehicleOption
|
|
{
|
|
public string displayName = "BUGGY";
|
|
public GameObject prefab;
|
|
public Vector3 previewRotation = new Vector3(0f, 145f, 0f);
|
|
public float previewScale = 1f;
|
|
}
|
|
|
|
[Serializable]
|
|
public sealed class MapOption
|
|
{
|
|
public string displayName = "DEMO SCENE";
|
|
public string sceneName = "Demo Scene";
|
|
public SelectedGameMode mode = SelectedGameMode.Arena;
|
|
}
|
|
|
|
private enum Step
|
|
{
|
|
Vehicle,
|
|
Mode,
|
|
Map
|
|
}
|
|
|
|
[Header("Content")]
|
|
[SerializeField] private VehicleOption[] vehicles;
|
|
[SerializeField] private MapOption[] maps;
|
|
|
|
[Header("Preview")]
|
|
[SerializeField] private Transform previewRoot;
|
|
[SerializeField] private float previewRotationSpeed = 28f;
|
|
|
|
[Header("Panels")]
|
|
[SerializeField] private GameObject vehiclePanel;
|
|
[SerializeField] private GameObject modePanel;
|
|
[SerializeField] private GameObject mapPanel;
|
|
|
|
[Header("Texts")]
|
|
[SerializeField] private Text titleText;
|
|
[SerializeField] private Text subtitleText;
|
|
[SerializeField] private Text vehicleNameText;
|
|
[SerializeField] private Text vehicleClassText;
|
|
[SerializeField] private Text[] modeLabels;
|
|
[SerializeField] private Text[] mapLabels;
|
|
|
|
private readonly string[] modeNames =
|
|
{
|
|
"\u0410\u0420\u0415\u041d\u0410",
|
|
"\u0413\u041e\u041d\u041a\u0410 \u041d\u0410 \u0412\u042b\u0416\u0418\u0412\u0410\u041d\u0418\u0415"
|
|
};
|
|
|
|
private Step currentStep;
|
|
private GameObject currentPreview;
|
|
private int vehicleIndex;
|
|
private int modeIndex;
|
|
private int mapIndex;
|
|
|
|
private void Awake()
|
|
{
|
|
if (previewRoot == null)
|
|
previewRoot = transform;
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
currentStep = Step.Vehicle;
|
|
ShowVehicle(vehicleIndex);
|
|
RefreshUi();
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
RotatePreview();
|
|
HandleKeyboard();
|
|
}
|
|
|
|
public void SelectPrevious()
|
|
{
|
|
MoveSelection(-1);
|
|
}
|
|
|
|
public void SelectNext()
|
|
{
|
|
MoveSelection(1);
|
|
}
|
|
|
|
public void Confirm()
|
|
{
|
|
if (currentStep == Step.Vehicle)
|
|
{
|
|
currentStep = Step.Mode;
|
|
RefreshUi();
|
|
return;
|
|
}
|
|
|
|
if (currentStep == Step.Mode)
|
|
{
|
|
mapIndex = 0;
|
|
currentStep = Step.Map;
|
|
RefreshUi();
|
|
return;
|
|
}
|
|
|
|
StartSelectedMap();
|
|
}
|
|
|
|
public void ChooseArena()
|
|
{
|
|
modeIndex = 0;
|
|
mapIndex = 0;
|
|
currentStep = Step.Map;
|
|
RefreshUi();
|
|
}
|
|
|
|
public void ChooseSurvivalRace()
|
|
{
|
|
modeIndex = 1;
|
|
mapIndex = 0;
|
|
currentStep = Step.Map;
|
|
RefreshUi();
|
|
}
|
|
|
|
public void ChooseCurrentMap()
|
|
{
|
|
StartSelectedMap();
|
|
}
|
|
|
|
public void Back()
|
|
{
|
|
if (currentStep == Step.Map)
|
|
currentStep = Step.Mode;
|
|
else if (currentStep == Step.Mode)
|
|
currentStep = Step.Vehicle;
|
|
|
|
RefreshUi();
|
|
}
|
|
|
|
private void HandleKeyboard()
|
|
{
|
|
#if ENABLE_INPUT_SYSTEM
|
|
Keyboard keyboard = Keyboard.current;
|
|
if (keyboard == null)
|
|
return;
|
|
|
|
if (keyboard.leftArrowKey.wasPressedThisFrame || keyboard.aKey.wasPressedThisFrame)
|
|
SelectPrevious();
|
|
else if (keyboard.rightArrowKey.wasPressedThisFrame || keyboard.dKey.wasPressedThisFrame)
|
|
SelectNext();
|
|
|
|
if (keyboard.spaceKey.wasPressedThisFrame || keyboard.enterKey.wasPressedThisFrame || keyboard.numpadEnterKey.wasPressedThisFrame)
|
|
Confirm();
|
|
else if (keyboard.escapeKey.wasPressedThisFrame || keyboard.backspaceKey.wasPressedThisFrame)
|
|
Back();
|
|
#endif
|
|
}
|
|
|
|
private void MoveSelection(int direction)
|
|
{
|
|
if (currentStep == Step.Vehicle)
|
|
{
|
|
int length = vehicles != null ? vehicles.Length : 0;
|
|
vehicleIndex = Wrap(vehicleIndex + direction, length);
|
|
ShowVehicle(vehicleIndex);
|
|
}
|
|
else if (currentStep == Step.Mode)
|
|
{
|
|
modeIndex = Wrap(modeIndex + direction, modeNames.Length);
|
|
}
|
|
else if (currentStep == Step.Map)
|
|
{
|
|
int length = GetMapCountForCurrentMode();
|
|
mapIndex = Wrap(mapIndex + direction, length);
|
|
}
|
|
|
|
RefreshUi();
|
|
}
|
|
|
|
private void ShowVehicle(int index)
|
|
{
|
|
if (currentPreview != null)
|
|
Destroy(currentPreview);
|
|
|
|
if (vehicles == null || vehicles.Length == 0 || vehicles[index] == null || vehicles[index].prefab == null)
|
|
return;
|
|
|
|
VehicleOption option = vehicles[index];
|
|
currentPreview = Instantiate(option.prefab, previewRoot.position, Quaternion.Euler(option.previewRotation), previewRoot);
|
|
currentPreview.name = "Runtime Preview - " + option.displayName;
|
|
currentPreview.transform.localPosition = Vector3.zero;
|
|
currentPreview.transform.localRotation = Quaternion.Euler(option.previewRotation);
|
|
currentPreview.transform.localScale = Vector3.one * Mathf.Max(0.01f, option.previewScale);
|
|
DisableGameplayComponents(currentPreview);
|
|
}
|
|
|
|
private void DisableGameplayComponents(GameObject root)
|
|
{
|
|
Rigidbody[] bodies = root.GetComponentsInChildren<Rigidbody>(true);
|
|
for (int i = 0; i < bodies.Length; i++)
|
|
{
|
|
bodies[i].isKinematic = true;
|
|
bodies[i].useGravity = false;
|
|
}
|
|
|
|
Collider[] colliders = root.GetComponentsInChildren<Collider>(true);
|
|
for (int i = 0; i < colliders.Length; i++)
|
|
colliders[i].enabled = false;
|
|
|
|
MonoBehaviour[] behaviours = root.GetComponentsInChildren<MonoBehaviour>(true);
|
|
for (int i = 0; i < behaviours.Length; i++)
|
|
behaviours[i].enabled = false;
|
|
|
|
AudioSource[] audioSources = root.GetComponentsInChildren<AudioSource>(true);
|
|
for (int i = 0; i < audioSources.Length; i++)
|
|
{
|
|
audioSources[i].Stop();
|
|
audioSources[i].enabled = false;
|
|
}
|
|
|
|
ParticleSystem[] particles = root.GetComponentsInChildren<ParticleSystem>(true);
|
|
for (int i = 0; i < particles.Length; i++)
|
|
particles[i].Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear);
|
|
|
|
TrailRenderer[] trails = root.GetComponentsInChildren<TrailRenderer>(true);
|
|
for (int i = 0; i < trails.Length; i++)
|
|
trails[i].emitting = false;
|
|
}
|
|
|
|
private void RotatePreview()
|
|
{
|
|
if (currentPreview == null)
|
|
return;
|
|
|
|
currentPreview.transform.Rotate(Vector3.up, previewRotationSpeed * Time.deltaTime, Space.World);
|
|
}
|
|
|
|
private void RefreshUi()
|
|
{
|
|
if (vehiclePanel != null)
|
|
vehiclePanel.SetActive(currentStep == Step.Vehicle);
|
|
if (modePanel != null)
|
|
modePanel.SetActive(currentStep == Step.Mode);
|
|
if (mapPanel != null)
|
|
mapPanel.SetActive(currentStep == Step.Map);
|
|
|
|
if (titleText != null)
|
|
titleText.text = GetTitle();
|
|
if (subtitleText != null)
|
|
subtitleText.text = GetSubtitle();
|
|
if (vehicleNameText != null)
|
|
vehicleNameText.text = GetVehicleName();
|
|
if (vehicleClassText != null)
|
|
vehicleClassText.text = (vehicleIndex + 1) + " / " + Mathf.Max(vehicles != null ? vehicles.Length : 0, 1);
|
|
|
|
RefreshModeLabels();
|
|
RefreshMapLabels();
|
|
}
|
|
|
|
private void RefreshModeLabels()
|
|
{
|
|
if (modeLabels == null)
|
|
return;
|
|
|
|
for (int i = 0; i < modeLabels.Length && i < modeNames.Length; i++)
|
|
{
|
|
if (modeLabels[i] != null)
|
|
modeLabels[i].text = i == modeIndex ? "< " + modeNames[i] + " >" : modeNames[i];
|
|
}
|
|
}
|
|
|
|
private void RefreshMapLabels()
|
|
{
|
|
if (mapLabels == null)
|
|
return;
|
|
|
|
MapOption selectedMap = GetMapForCurrentMode(mapIndex);
|
|
for (int i = 0; i < mapLabels.Length; i++)
|
|
{
|
|
if (mapLabels[i] != null)
|
|
mapLabels[i].text = selectedMap != null ? selectedMap.displayName : "NO MAPS";
|
|
}
|
|
}
|
|
|
|
private string GetTitle()
|
|
{
|
|
if (currentStep == Step.Mode)
|
|
return "\u0420\u0415\u0416\u0418\u041c \u0418\u0413\u0420\u042b";
|
|
if (currentStep == Step.Map)
|
|
return "\u0412\u042b\u0411\u041e\u0420 \u041a\u0410\u0420\u0422\u042b";
|
|
|
|
return "\u0412\u042b\u0411\u041e\u0420 \u041c\u0410\u0428\u0418\u041d\u042b";
|
|
}
|
|
|
|
private string GetSubtitle()
|
|
{
|
|
if (currentStep == Step.Vehicle)
|
|
return "\u0421\u0422\u0420\u0415\u041b\u041a\u0418 / A-D - \u041c\u0410\u0428\u0418\u041d\u0410 SPACE - \u0412\u042b\u0411\u0420\u0410\u0422\u042c";
|
|
if (currentStep == Step.Mode)
|
|
return "\u0421\u0422\u0420\u0415\u041b\u041a\u0418 / A-D - \u0420\u0415\u0416\u0418\u041c SPACE - \u0414\u0410\u041b\u042c\u0428\u0415 ESC - \u041d\u0410\u0417\u0410\u0414";
|
|
|
|
return "\u0421\u0422\u0420\u0415\u041b\u041a\u0418 / A-D - \u041a\u0410\u0420\u0422\u0410 SPACE - \u0421\u0422\u0410\u0420\u0422 ESC - \u041d\u0410\u0417\u0410\u0414";
|
|
}
|
|
|
|
private string GetVehicleName()
|
|
{
|
|
if (vehicles == null || vehicles.Length == 0 || vehicles[vehicleIndex] == null)
|
|
return "NO VEHICLE";
|
|
|
|
return string.IsNullOrWhiteSpace(vehicles[vehicleIndex].displayName) ? vehicles[vehicleIndex].prefab.name : vehicles[vehicleIndex].displayName;
|
|
}
|
|
|
|
private void StartSelectedMap()
|
|
{
|
|
MapOption selectedMap = GetMapForCurrentMode(mapIndex);
|
|
if (selectedMap == null || string.IsNullOrWhiteSpace(selectedMap.sceneName))
|
|
{
|
|
Debug.LogWarning("No map is configured for selected game mode.");
|
|
return;
|
|
}
|
|
|
|
SelectedGameMode selectedMode = modeIndex == 0 ? SelectedGameMode.Arena : SelectedGameMode.SurvivalRace;
|
|
GameObject selectedPrefab = vehicles != null && vehicles.Length > 0 ? vehicles[vehicleIndex].prefab : null;
|
|
GameSelectionState.SetSelection(selectedPrefab, GetVehicleName(), selectedMode, selectedMap.sceneName);
|
|
SceneManager.LoadScene(selectedMap.sceneName);
|
|
}
|
|
|
|
private MapOption GetMapForCurrentMode(int filteredIndex)
|
|
{
|
|
if (maps == null || maps.Length == 0)
|
|
return null;
|
|
|
|
SelectedGameMode selectedMode = modeIndex == 0 ? SelectedGameMode.Arena : SelectedGameMode.SurvivalRace;
|
|
int currentFilteredIndex = 0;
|
|
for (int i = 0; i < maps.Length; i++)
|
|
{
|
|
if (maps[i] == null || maps[i].mode != selectedMode)
|
|
continue;
|
|
|
|
if (currentFilteredIndex == filteredIndex)
|
|
return maps[i];
|
|
|
|
currentFilteredIndex++;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private int GetMapCountForCurrentMode()
|
|
{
|
|
if (maps == null || maps.Length == 0)
|
|
return 0;
|
|
|
|
SelectedGameMode selectedMode = modeIndex == 0 ? SelectedGameMode.Arena : SelectedGameMode.SurvivalRace;
|
|
int count = 0;
|
|
for (int i = 0; i < maps.Length; i++)
|
|
{
|
|
if (maps[i] != null && maps[i].mode == selectedMode)
|
|
count++;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
private static int Wrap(int value, int length)
|
|
{
|
|
if (length <= 0)
|
|
return 0;
|
|
|
|
value %= length;
|
|
return value < 0 ? value + length : value;
|
|
}
|
|
}
|
|
}
|