using System.Collections; using System.Collections.Generic; using UnityEngine; /// /// Scene manager that contains current player vehicle, current player camera, current player UI, current player character, recording/playing mechanim, and other vehicles as well. /// /// [AddComponentMenu("BoneCracker Games/Realistic Car Controller/Main/RCC Scene Manager")] public class RCC_SceneManager : RCC_Singleton { public RCC_CarControllerV3 activePlayerVehicle; // Current active player vehicle. public RCC_Camera activePlayerCamera; // Current active player camera as RCC Camera. public RCC_UIDashboardDisplay activePlayerCanvas; // Current active UI canvas. public Camera activeMainCamera; // Current active main camera. private RCC_CarControllerV3 lastActivePlayerVehicle; // Last selected player vehicle. public bool registerLastSpawnedVehicleAsPlayerVehicle = true; // Registers the lastly spawned vehicle as player vehicle. public bool disableUIWhenNoPlayerVehicle = false; // Disables the UI when there is no any player vehicle. public bool loadCustomizationAtFirst = false; // Loads the latest customization for the spawned vehicle. public bool useRecord = false; // Use record / replay? public List allRecorders = new List(); // All recorders attached to the vehicles. public enum RecordMode { Neutral, Play, Record } // Current record / replay state. public RecordMode recordMode = RecordMode.Neutral; // Default time scale of the game. private float orgTimeScale = 1f; public List allVehicles = new List(); // All vehicles. #if BCG_ENTEREXIT public BCG_EnterExitPlayer activePlayerCharacter; // Current active player character controller. #endif public Terrain[] allTerrains; // All terrains. public class Terrains { // Terrain data. public Terrain terrain; public TerrainData mTerrainData; public PhysicMaterial terrainCollider; public int alphamapWidth; public int alphamapHeight; public float[,,] mSplatmapData; public float mNumTextures; } public Terrains[] terrains; // All terrains with custom class. public bool terrainsInitialized = false; // All terrains are initialized yet? // Firing an event when main behavior changed. public delegate void onBehaviorChanged(); public static event onBehaviorChanged OnBehaviorChanged; // Firing an event when player vehicle changed. public delegate void onVehicleChanged(); public static event onVehicleChanged OnVehicleChanged; private void Awake() { // Overriding Fixed TimeStep. if (RCC_Settings.Instance.overrideFixedTimeStep) Time.fixedDeltaTime = RCC_Settings.Instance.fixedTimeStep; // Overriding FPS. if (RCC_Settings.Instance.overrideFPS) Application.targetFrameRate = RCC_Settings.Instance.maxFPS; // Instantiate telemetry UI if it's enabled in RCC Settings. if (RCC_Settings.Instance.useTelemetry) Instantiate(RCC_Settings.Instance.RCCTelemetry, Vector3.zero, Quaternion.identity); // Listening events. RCC_Camera.OnBCGCameraSpawned += RCC_Camera_OnBCGCameraSpawned; RCC_CarControllerV3.OnRCCPlayerSpawned += RCC_CarControllerV3_OnRCCSpawned; RCC_AICarController.OnRCCAISpawned += RCC_AICarController_OnRCCAISpawned; RCC_CarControllerV3.OnRCCPlayerDestroyed += RCC_CarControllerV3_OnRCCPlayerDestroyed; RCC_AICarController.OnRCCAIDestroyed += RCC_AICarController_OnRCCAIDestroyed; RCC_InputManager.OnSlowMotion += RCC_InputManager_OnSlowMotion; #if BCG_ENTEREXIT BCG_EnterExitPlayer.OnBCGPlayerSpawned += BCG_EnterExitPlayer_OnBCGPlayerSpawned; BCG_EnterExitPlayer.OnBCGPlayerDestroyed += BCG_EnterExitPlayer_OnBCGPlayerDestroyed; #endif // Getting active UI canvas. activePlayerCanvas = FindObjectOfType(); // Getting default time scale of the game. orgTimeScale = Time.timeScale; // If lock cursor is enabled in RCC Settings, lock the cursor. if (RCC_Settings.Instance.lockAndUnlockCursor) Cursor.lockState = CursorLockMode.Locked; } #region ONSPAWNED /// /// When RCC vehicle is spawned. /// /// private void RCC_CarControllerV3_OnRCCSpawned(RCC_CarControllerV3 RCC) { // If all vehicles list doesn't contain spawned vehicle, add it to the list. if (!allVehicles.Contains(RCC)) { allVehicles.Add(RCC); if (useRecord) { // Finding recorder if attached to the vehicle before. If not found, add it. allRecorders = new List(); allRecorders.AddRange(gameObject.GetComponentsInChildren()); RCC_Recorder recorder = null; if (allRecorders != null && allRecorders.Count > 0) { for (int i = 0; i < allRecorders.Count; i++) { if (allRecorders[i] != null && allRecorders[i].carController == RCC) { recorder = allRecorders[i]; break; } } } if (recorder == null) { recorder = gameObject.AddComponent(); recorder.carController = RCC; } } } // Checking all recorders. StartCoroutine(CheckMissingRecorders()); // Registers the last spawned vehicle as player vehicle. if (registerLastSpawnedVehicleAsPlayerVehicle) RegisterPlayer(RCC); #if BCG_ENTEREXIT // If spawned vehicle has enter exit script, set corresponding camera of the script to RCC Camera. if (RCC.gameObject.GetComponent()) RCC.gameObject.GetComponent().correspondingCamera = activePlayerCamera.gameObject; #endif } /// /// When AI vehicle spawned. /// /// private void RCC_AICarController_OnRCCAISpawned(RCC_AICarController RCCAI) { // If all vehicles list doesn't contain spawned vehicle, add it to the list. if (!allVehicles.Contains(RCCAI.CarController)) { allVehicles.Add(RCCAI.CarController); if (useRecord) { // Finding recorder if attached to the vehicle before. If not found, add it. allRecorders = new List(); allRecorders.AddRange(gameObject.GetComponentsInChildren()); RCC_Recorder recorder = null; if (allRecorders != null && allRecorders.Count > 0) { for (int i = 0; i < allRecorders.Count; i++) { if (allRecorders[i] != null && allRecorders[i].carController == RCCAI.CarController) { recorder = allRecorders[i]; break; } } } if (recorder == null) { recorder = gameObject.AddComponent(); recorder.carController = RCCAI.CarController; } } } if (useRecord) { // Checking all recorders. StartCoroutine(CheckMissingRecorders()); } } /// /// When RCC Camera spawned. /// /// private void RCC_Camera_OnBCGCameraSpawned(GameObject BCGCamera) { if (BCGCamera.GetComponent()) activePlayerCamera = BCGCamera.GetComponent(); } #if BCG_ENTEREXIT /// /// When a character with enter exit script spawned. /// /// private void BCG_EnterExitPlayer_OnBCGPlayerSpawned(BCG_EnterExitPlayer player) { activePlayerCharacter = player; } #endif #endregion #region ONDESTROYED /// /// When a vehicle destroyed. /// /// private void RCC_CarControllerV3_OnRCCPlayerDestroyed(RCC_CarControllerV3 RCC) { if (allVehicles.Contains(RCC)) allVehicles.Remove(RCC); //StartCoroutine(CheckMissingRecorders()); } /// /// When a AI vehicle destroyed. /// /// private void RCC_AICarController_OnRCCAIDestroyed(RCC_AICarController RCCAI) { if (allVehicles.Contains(RCCAI.CarController)) allVehicles.Remove(RCCAI.CarController); StartCoroutine(CheckMissingRecorders()); } #if BCG_ENTEREXIT /// /// When a character with enter exit script destroyed. /// /// private void BCG_EnterExitPlayer_OnBCGPlayerDestroyed(BCG_EnterExitPlayer player) { } #endif #endregion private void Start() { // Getting all terrains. StartCoroutine(GetAllTerrains()); } /// /// Getting all terrains. /// /// public IEnumerator GetAllTerrains() { yield return new WaitForFixedUpdate(); allTerrains = Terrain.activeTerrains; yield return new WaitForFixedUpdate(); // If terrains found... if (allTerrains != null && allTerrains.Length >= 1) { terrains = new Terrains[allTerrains.Length]; for (int i = 0; i < allTerrains.Length; i++) { if (allTerrains[i].terrainData == null) { Debug.LogError("Terrain data of the " + allTerrains[i].transform.name + " is missing! Check the terrain data..."); yield return null; } } // Initializing terrains. for (int i = 0; i < terrains.Length; i++) { terrains[i] = new Terrains(); terrains[i].terrain = allTerrains[i]; terrains[i].mTerrainData = allTerrains[i].terrainData; terrains[i].terrainCollider = allTerrains[i].GetComponent().sharedMaterial; terrains[i].alphamapWidth = allTerrains[i].terrainData.alphamapWidth; terrains[i].alphamapHeight = allTerrains[i].terrainData.alphamapHeight; terrains[i].mSplatmapData = allTerrains[i].terrainData.GetAlphamaps(0, 0, terrains[i].alphamapWidth, terrains[i].alphamapHeight); terrains[i].mNumTextures = terrains[i].mSplatmapData.Length / (terrains[i].alphamapWidth * terrains[i].alphamapHeight); } terrainsInitialized = true; } } private void Update() { // When player vehicle changed... if (activePlayerVehicle) { if (activePlayerVehicle != lastActivePlayerVehicle) { if (OnVehicleChanged != null) OnVehicleChanged(); } lastActivePlayerVehicle = activePlayerVehicle; } // Checking UI canvas. if (disableUIWhenNoPlayerVehicle && activePlayerCanvas) CheckCanvas(); // Getting main camera. if (Camera.main != null) activeMainCamera = Camera.main; if (useRecord) { // Getting all recorders and setting their states. if (allRecorders != null && allRecorders.Count > 0) { switch (allRecorders[0].mode) { case RCC_Recorder.Mode.Neutral: recordMode = RecordMode.Neutral; break; case RCC_Recorder.Mode.Play: recordMode = RecordMode.Play; break; case RCC_Recorder.Mode.Record: recordMode = RecordMode.Record; break; } } } } /// /// Recording. /// public void Record() { if (!useRecord) return; if (allRecorders != null && allRecorders.Count > 0) { for (int i = 0; i < allRecorders.Count; i++) allRecorders[i].Record(); } } /// /// Playing. /// public void Play() { if (!useRecord) return; if (allRecorders != null && allRecorders.Count > 0) { for (int i = 0; i < allRecorders.Count; i++) allRecorders[i].Play(); } } /// /// Stop all records. /// public void Stop() { if (!useRecord) return; if (allRecorders != null && allRecorders.Count > 0) { for (int i = 0; i < allRecorders.Count; i++) allRecorders[i].Stop(); } } /// /// Checking all recorders. If missing found, destroy it. /// /// private IEnumerator CheckMissingRecorders() { if (!useRecord) yield break; yield return new WaitForFixedUpdate(); allRecorders = new List(); allRecorders.AddRange(gameObject.GetComponentsInChildren()); if (allRecorders != null && allRecorders.Count > 0) { for (int i = 0; i < allRecorders.Count; i++) { if (allRecorders[i].carController == null) Destroy(allRecorders[i]); } } yield return new WaitForFixedUpdate(); allRecorders = new List(); allRecorders.AddRange(gameObject.GetComponentsInChildren()); } /// /// Registers the target vehicle as player vehicle. /// /// public void RegisterPlayer(RCC_CarControllerV3 playerVehicle) { activePlayerVehicle = playerVehicle; if (activePlayerCamera) activePlayerCamera.SetTarget(activePlayerVehicle); if (loadCustomizationAtFirst) RCC_Customization.LoadStats(RCC_SceneManager.Instance.activePlayerVehicle); if (FindObjectOfType()) FindObjectOfType().CheckUIs(); } /// /// Registers the target vehicle as player vehicle. Also sets controllable state of the vehicle. /// /// /// public void RegisterPlayer(RCC_CarControllerV3 playerVehicle, bool isControllable) { activePlayerVehicle = playerVehicle; activePlayerVehicle.SetCanControl(isControllable); if (activePlayerCamera) activePlayerCamera.SetTarget(activePlayerVehicle); if (loadCustomizationAtFirst) RCC_Customization.LoadStats(RCC_SceneManager.Instance.activePlayerVehicle); if (FindObjectOfType()) FindObjectOfType().CheckUIs(); } /// /// Registers the target vehicle as player vehicle. Also sets controllable state and engine state of the vehicle. /// /// /// /// public void RegisterPlayer(RCC_CarControllerV3 playerVehicle, bool isControllable, bool engineState) { activePlayerVehicle = playerVehicle; activePlayerVehicle.SetCanControl(isControllable); activePlayerVehicle.SetEngine(engineState); if (activePlayerCamera) activePlayerCamera.SetTarget(activePlayerVehicle); if (loadCustomizationAtFirst) RCC_Customization.LoadStats(RCC_SceneManager.Instance.activePlayerVehicle); if (FindObjectOfType()) FindObjectOfType().CheckUIs(); } /// /// Deregisters the player vehicle. /// public void DeRegisterPlayer() { if (activePlayerVehicle) activePlayerVehicle.SetCanControl(false); activePlayerVehicle = null; if (activePlayerCamera) activePlayerCamera.RemoveTarget(); } /// /// Checks UI canvas. /// public void CheckCanvas() { if (!activePlayerVehicle || !activePlayerVehicle.canControl || !activePlayerVehicle.gameObject.activeInHierarchy || !activePlayerVehicle.enabled) { activePlayerCanvas.SetDisplayType(RCC_UIDashboardDisplay.DisplayType.Off); return; } if (activePlayerCanvas.displayType != RCC_UIDashboardDisplay.DisplayType.Customization) activePlayerCanvas.displayType = RCC_UIDashboardDisplay.DisplayType.Full; } /// /// Sets new behavior. /// public void SetBehavior(int behaviorIndex) { RCC_Settings.Instance.overrideBehavior = true; RCC_Settings.Instance.behaviorSelectedIndex = behaviorIndex; if (OnBehaviorChanged != null) OnBehaviorChanged(); } /// /// Changes current camera mode. /// public void ChangeCamera() { if (activePlayerCamera) activePlayerCamera.ChangeCamera(); } /// /// Transport player vehicle the specified position and rotation. /// /// Position. /// Rotation. public void Transport(Vector3 position, Quaternion rotation) { if (activePlayerVehicle) { activePlayerVehicle.Rigid.velocity = Vector3.zero; activePlayerVehicle.Rigid.angularVelocity = Vector3.zero; activePlayerVehicle.transform.position = position; activePlayerVehicle.transform.rotation = rotation; activePlayerVehicle.throttleInput = 0f; activePlayerVehicle.brakeInput = 1f; activePlayerVehicle.engineRPM = activePlayerVehicle.minEngineRPM; activePlayerVehicle.currentGear = 0; for (int i = 0; i < activePlayerVehicle.AllWheelColliders.Length; i++) activePlayerVehicle.AllWheelColliders[i].WheelCollider.motorTorque = 0f; StartCoroutine(Freeze(activePlayerVehicle)); } } /// /// Transport target vehicle the specified position and rotation. /// /// /// /// public void Transport(RCC_CarControllerV3 vehicle, Vector3 position, Quaternion rotation) { if (vehicle) { vehicle.Rigid.velocity = Vector3.zero; vehicle.Rigid.angularVelocity = Vector3.zero; vehicle.transform.position = position; vehicle.transform.rotation = rotation; vehicle.throttleInput = 0f; vehicle.brakeInput = 1f; vehicle.engineRPM = vehicle.minEngineRPM; vehicle.currentGear = 0; for (int i = 0; i < vehicle.AllWheelColliders.Length; i++) vehicle.AllWheelColliders[i].WheelCollider.motorTorque = 0f; //StartCoroutine(Freeze(vehicle)); } } /// /// Freezing the target vehicle for 1 second. /// /// /// private IEnumerator Freeze(RCC_CarControllerV3 vehicle) { float timer = 1f; while (timer > 0) { timer -= Time.deltaTime; vehicle.canControl = false; vehicle.Rigid.velocity = new Vector3(0f, vehicle.Rigid.velocity.y, 0f); vehicle.Rigid.angularVelocity = Vector3.zero; yield return null; } vehicle.canControl = true; } /// /// Enters slow motion. /// /// private void RCC_InputManager_OnSlowMotion(bool state) { if (state) Time.timeScale = .2f; else Time.timeScale = orgTimeScale; } private void OnDisable() { RCC_Camera.OnBCGCameraSpawned -= RCC_Camera_OnBCGCameraSpawned; RCC_CarControllerV3.OnRCCPlayerSpawned -= RCC_CarControllerV3_OnRCCSpawned; RCC_AICarController.OnRCCAISpawned -= RCC_AICarController_OnRCCAISpawned; RCC_CarControllerV3.OnRCCPlayerDestroyed -= RCC_CarControllerV3_OnRCCPlayerDestroyed; RCC_AICarController.OnRCCAIDestroyed -= RCC_AICarController_OnRCCAIDestroyed; RCC_InputManager.OnSlowMotion -= RCC_InputManager_OnSlowMotion; #if BCG_ENTEREXIT BCG_EnterExitPlayer.OnBCGPlayerSpawned -= BCG_EnterExitPlayer_OnBCGPlayerSpawned; BCG_EnterExitPlayer.OnBCGPlayerDestroyed -= BCG_EnterExitPlayer_OnBCGPlayerDestroyed; #endif } }