using System.Collections.Generic; using WSMGameStudio.Splines; using UnityEngine; using UnityEditor; namespace WSMGameStudio.RailroadSystem { [ExecuteInEditMode] public class TrainSpawner : MonoBehaviour { #region SINGLETON private static TrainSpawner _instance; public static TrainSpawner Instance { get { return _instance; } } private void Awake() { if (_instance != null && _instance != this) { if (Application.isPlaying) Destroy(this.gameObject); else DestroyImmediate(this.gameObject); } else { _instance = this; } } #endregion [Range(0, 1)] [SerializeField] private float _positionAlongRails = 0.9f; public float PositionAlongRails { get { return _positionAlongRails; } set { _positionAlongRails = value; } } /// /// Spawns a instance of the selected train prefab on target rails /// /// /// /// /// public GameObject SpawnTrain_Prefab(GameObject trainPrefab, List targetRails, float t, string trainName = "Train") { if (trainPrefab == null) return null; ILocomotive locomotiveValidation = trainPrefab.GetComponentInChildren(); if (locomotiveValidation == null) { Debug.LogWarning(string.Format("{0} must have a locomotive!", trainPrefab.name)); return null; } IRailwayVehicle[] wagonsValidation = trainPrefab.GetComponentsInChildren(); if (wagonsValidation == null) { Debug.LogWarning(string.Format("{0} must have at least 1 wagon!", trainPrefab.name)); return null; } Vector3 position = GetTargetSpawnPosition(targetRails, t); Vector3 lookTarget = GetLookTarget(targetRails, t, position); GameObject trainInstance = SpawnInstance(trainPrefab, position, lookTarget); ILocomotive locomotive = trainInstance.GetComponentInChildren(); SetupSplineBasedLocomotive(locomotive.GetGameObject, targetRails, t); return trainInstance; } /// /// Spawn train on target rails based on profile /// /// /// /// /// public GameObject SpawnTrain_Profile(TrainProfile trainProfile, List targetRails, float t, string trainName = "Train") { if (trainProfile == null) return null; if (trainProfile.locomotivePrefab == null) { Debug.LogWarning(string.Format("{0} must have a locomotive prefab reference!", trainProfile.name)); return null; } if (trainProfile.wagonsPrefabs == null) { Debug.LogWarning(string.Format("{0} must have wagon prefabs references!", trainProfile.name)); return null; } return SpawnTrain(trainProfile.locomotivePrefab, trainProfile.wagonsPrefabs, targetRails, t, trainName); } /// /// Spawn train on target rails /// /// /// /// /// /// public GameObject SpawnTrain(GameObject locomotivePrefab, List wagonsPrefabs, List targetRails, float t, string trainName) { if (locomotivePrefab.GetComponent() == null) { Debug.LogWarning(string.Format("{0} is not a locomotive prefab!", locomotivePrefab.name)); return null; } GameObject locomotiveInstance = SpawnRailwayVehicle(locomotivePrefab, targetRails, t); ILocomotive locomotiveScript = locomotiveInstance.GetComponent(); GameObject trainInstance = new GameObject(trainName); #if UNITY_EDITOR UnityEditor.GameObjectUtility.EnsureUniqueNameForSibling(trainInstance); #endif trainInstance.transform.position = locomotiveInstance.transform.position; trainInstance.transform.rotation = locomotiveInstance.transform.rotation; locomotiveInstance.transform.SetParent(trainInstance.transform); List wagonInstances = new List(); foreach (GameObject wagonPrefab in wagonsPrefabs) { if (wagonPrefab.GetComponent() == null) continue; GameObject wagonInstance = SpawnInstance(wagonPrefab, Vector3.zero, Quaternion.identity); wagonInstance.transform.SetParent(trainInstance.transform); wagonInstances.Add(wagonInstance); } SetupSplineBasedLocomotive(locomotiveInstance, targetRails, t); ConnectWagons(locomotiveScript, wagonInstances, targetRails); return trainInstance; } /// /// If locomotive is spline based, setup spline following properties /// /// /// /// private static void SetupSplineBasedLocomotive(GameObject locomotiveInstance, List targetRails, float t) { if (locomotiveInstance == null) return; SplineBasedLocomotive splineBasedLoco = locomotiveInstance.GetComponent(); if (splineBasedLoco == null) return; splineBasedLoco.customStartPosition = t * 100f; splineBasedLoco.splines = targetRails; splineBasedLoco.CalculateWagonsPositions(); } /// /// Connect wagons to the locomotive /// /// /// /// private static void ConnectWagons(ILocomotive locomotiveScript, List wagonInstances, List targetRails) { locomotiveScript.RemoveAllWagons(); //Make sure wagons list will not be duplicated locomotiveScript.AddWagons(wagonInstances); locomotiveScript.CalculateWagonsPositions(targetRails); } /// /// Spawns either a locomotive or wagon at target position /// /// /// /// /// public GameObject SpawnRailwayVehicle(GameObject railwayVehiclePrefab, Vector3 position, Quaternion rotation) { if (railwayVehiclePrefab.GetComponent() == null) { Debug.LogWarning(string.Format("{0} is not a Railway Vehicle!", railwayVehiclePrefab.name)); return null; } return SpawnInstance(railwayVehiclePrefab, position, rotation); } /// /// Spawns either a locomotive or wagon at target position /// /// /// /// /// public GameObject SpawnRailwayVehicle(GameObject railwayVehiclePrefab, Vector3 position, Vector3 lookTarget) { if (railwayVehiclePrefab.GetComponent() == null) { Debug.LogWarning(string.Format("{0} is not a Railway Vehicle!", railwayVehiclePrefab.name)); return null; } return SpawnInstance(railwayVehiclePrefab, position, lookTarget); } /// /// Spawns either a locomotive or wagon along target rails /// /// /// /// /// public GameObject SpawnRailwayVehicle(GameObject railwayVehiclePrefab, List targetRails, float t) { Vector3 position = GetTargetSpawnPosition(targetRails, t); Vector3 lookTarget = GetLookTarget(targetRails, t, position); GameObject railwayVehicleInstance = SpawnRailwayVehicle(railwayVehiclePrefab, position, lookTarget); SetupSplineBasedLocomotive(railwayVehicleInstance, targetRails, t); return railwayVehicleInstance; } /// /// Get Target Spawn Position /// /// /// public Vector3 GetTargetSpawnPosition(List targetRails) { return GetTargetSpawnPosition(targetRails, _positionAlongRails); } /// /// Get Target Spawn Position /// /// /// /// private Vector3 GetTargetSpawnPosition(List targetRails, float t) { return targetRails[0].GetPoint(t); } /// /// Get Look Target /// /// /// /// /// private Vector3 GetLookTarget(List targetRails, float t, Vector3 position) { return position + targetRails[0].GetDirection(t); } /// /// Spawn instance and enforce unique name /// /// /// /// /// private GameObject SpawnInstance(GameObject prefab, Vector3 position, Quaternion rotation) { GameObject instance = null; if (Application.isEditor) { #if UNITY_EDITOR instance = PrefabUtility.InstantiatePrefab(prefab) as GameObject; instance.transform.position = position; instance.transform.rotation = rotation; #endif } else instance = Instantiate(prefab, position, rotation); EnforceUniqueName(instance); return instance; } /// /// Spawns either a locomotive or wagon along target rails /// /// /// /// /// private GameObject SpawnInstance(GameObject prefab, Vector3 position, Vector3 lookTarget) { GameObject instance = null; if (Application.isEditor) { #if UNITY_EDITOR instance = PrefabUtility.InstantiatePrefab(prefab) as GameObject; instance.transform.position = position; instance.transform.rotation = Quaternion.identity; #endif } else instance = Instantiate(prefab, position, Quaternion.identity); instance.transform.LookAt(lookTarget, Vector3.up); EnforceUniqueName(instance); return instance; } /// /// Make sure new object has a unique name /// /// private void EnforceUniqueName(GameObject targetObject) { #if UNITY_EDITOR targetObject.name = targetObject.name.Replace("(Clone)", string.Empty); UnityEditor.GameObjectUtility.EnsureUniqueNameForSibling(targetObject); #endif } } }