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
}
}
}