using System; using Ext.B83.Unity.Attributes; using InterfaceOff.MainMenu; using InterfaceOff.WorldScene; using UnityEngine; using Random = UnityEngine.Random; namespace InterfaceOff { [Serializable] public struct SpawnableWindowType { [field: SerializeField, MonoScript] private string Typename { get; set; } public Type Type => Type.GetType(Typename); [field: SerializeField] public int SpawnWeight { get; private set; } } public class WindowSpawner : MonoBehaviour { [field: SerializeField] private GameObject SampleChild { get; set; } [field: SerializeField] private Canvas GameCanvas { get; set; } [field: SerializeField] private GameObject DeathInfo { get; set; } [field: SerializeField] private SpawnableWindowType[] WindowTypes { get; set; } [field: SerializeField] private GameObject Parent { get; set; } [field: SerializeField] private GameObject PasswordField { get; set; } [field: SerializeField] private GameObject LeaderboardObject { get; set; } private int TotalSpawnWeight { get; set; } [field: SerializeField] public int SpawnedWindowCount { get; private set; } [field: SerializeField] public bool AutoSpawn { get; private set; } = true; private int TimeTillNextSpawn { get; set; } private void Awake() { /* Logs the amount of types found and errors if there is none */ Debug.Log($"Found [{WindowTypes.Length}] different window types "); if (WindowTypes.Length == 0) { Debug.LogError("Could not find any window types"); return; } /* Calculates the total spawn weight */ TotalSpawnWeight = 0; foreach (SpawnableWindowType type in WindowTypes) { TotalSpawnWeight += type.SpawnWeight; } } private Type GetRandomWindowType() { int currentTypeWeight = Random.Range(0, TotalSpawnWeight); foreach (SpawnableWindowType type in WindowTypes) { currentTypeWeight -= type.SpawnWeight; if (currentTypeWeight <= 0) { return type.Type; } } return WindowTypes[0].Type; } private void SpawnNewRandomWindow() { /* Creates the gameobject with a random class */ GameObject go = Instantiate(SampleChild, Parent.transform); go.SetActive(true); Type type = GetRandomWindowType(); go.name = type.Name; WindowBase windowBase = go.AddComponent(type) as WindowBase; /* Checks it created correctly before instantiating further */ if (DebugUtils.IsNull(windowBase)) { Debug.LogError("How did this happen"); return; } /* Updates the window trackers */ SpawnedWindowCount++; /* Makes sure the WindowInteractions and WindowComponents are set up before passing to user code */ windowBase.Interactions = go.GetComponent(); windowBase.Interactions.SetAttachedTo(windowBase); windowBase.Components = go.GetComponent(); windowBase.InstantiateWindowBase(creator: this); } public void AlertOfDespawnedWindow() => SpawnedWindowCount--; private void FixedUpdate() { /* Spawns new windows whilst active */ if (AutoSpawn) { /* Has a random choice for the PasswordField to show up */ if (Random.Range(0, 1000) == 500) { PasswordField.SetActive(true); } /* Calculates the current max spawn time */ const int TICKS_PER_SECOND = 20; // Unity constant const int MIN_SPAWN_TIME = 2 * TICKS_PER_SECOND; const int MAX_SPAWN_TIME = 5 * TICKS_PER_SECOND; int currentMaxSpawnTime = MAX_SPAWN_TIME - (int)(ScoreTracker.CurrentScore() * DifficultyManager.DifficultyEffect); currentMaxSpawnTime = Math.Clamp(currentMaxSpawnTime, MIN_SPAWN_TIME + 1, MAX_SPAWN_TIME); /* Decreases the spawn counter and spawns if at 0 */ TimeTillNextSpawn = Math.Max(0, TimeTillNextSpawn - 1); if (TimeTillNextSpawn == 0) { float difficulty = DifficultyManager.DifficultyMultiplier; TimeTillNextSpawn = Random.Range((int)(MIN_SPAWN_TIME * difficulty), (int)(currentMaxSpawnTime / difficulty)); SpawnNewRandomWindow(); } } else { /* Makes sure the password overlay does not interfere */ PasswordField.SetActive(false); /* Else checks if it should change the active scene */ if (Input.GetKey(KeyCode.Space) && !LeaderboardObject.activeSelf) { SceneController.ReloadScene(); } else if (Input.GetKey(KeyCode.Tab) && !LeaderboardObject.activeSelf) { SceneController.Load(name: "MenuScene"); } } } public void StartEndSequence() { /* Destroys all children and stops them from spawning */ AutoSpawn = false; foreach (Transform child in Parent.transform) { WindowBase window = child.GetComponent(); if (DebugUtils.IsNotNull(window)) { window.DestroyWindow(); } } /* Makes the death text visible to the player */ DeathInfo.SetActive(true); } } }