using System; using System.Collections.Generic; using UnityEngine; using WSMGameStudio.Splines; namespace WSMGameStudio.RailroadSystem { public static class CustomWagonCreator { /// /// /// /// /// /// /// /// public static bool Validate(CustomWagonProfile profile, GameObject modelPrefab, string name, out string message) { message = string.Empty; if (profile == null) { message = string.Format("Profile cannot be null.{0}Please select a profile and try again.", System.Environment.NewLine); return false; } if (modelPrefab == null) { message = string.Format("Model cannot be null.{0}Please select your custom model and try again.", System.Environment.NewLine); return false; } if (name == null || name == string.Empty) { message = string.Format("Name cannot be null.{0}Please select a name and try again.", System.Environment.NewLine); return false; } return true; } /// /// /// /// /// /// /// public static bool Create(CustomWagonProfile profile, GameObject modelPrefab, string name, out string message) { message = string.Empty; Vector3 railsOffset = profile.railsOffset; //Wagon/locomotive game object GameObject wagonInstance = new GameObject(name); //Model GameObject modelInstance; if (modelPrefab != null) modelInstance = InstantiateChild(modelPrefab, modelPrefab.name, profile.modelOffset, Quaternion.identity, wagonInstance.transform); //Default child instances GameObject wheels = InstantiateChild("Wheels", railsOffset, Quaternion.identity, wagonInstance.transform); GameObject sfx = InstantiateChild("SFX", Vector3.zero, Quaternion.identity, wagonInstance.transform); GameObject vfx = InstantiateChild("VFX", Vector3.zero, Quaternion.identity, wagonInstance.transform); GameObject colliders = InstantiateChild("Colliders", Vector3.zero, Quaternion.identity, wagonInstance.transform); GameObject bumpers = InstantiateChild("Bumpers", Vector3.zero, Quaternion.identity, wagonInstance.transform); GameObject doors = InstantiateChild("Doors", Vector3.zero, Quaternion.identity, wagonInstance.transform); GameObject lights = InstantiateChild("Lights", Vector3.zero, Quaternion.identity, wagonInstance.transform); GameObject sensors = null; GameObject suspension = null; if (profile.trainType == TrainType.PhysicsBased) { sensors = InstantiateChild("Sensors", railsOffset, Quaternion.identity, wagonInstance.transform); suspension = InstantiateChild("Suspension", railsOffset, Quaternion.identity, wheels.transform); } //Add common unity components Rigidbody rigidbody = wagonInstance.AddComponent(); //Configure common unity components rigidbody.mass = 10000f; rigidbody.useGravity = (profile.trainType == TrainType.PhysicsBased); rigidbody.isKinematic = (profile.trainType == TrainType.SplineBased); rigidbody.interpolation = (profile.trainType == TrainType.PhysicsBased) ? RigidbodyInterpolation.Interpolate : RigidbodyInterpolation.None; rigidbody.detectCollisions = true; //Instantiate common profile components InstantiateWagonComponents(profile.bumper, bumpers.transform, null); if (profile.trainType == TrainType.PhysicsBased) InstantiateWagonComponents(profile.suspensionCollider, suspension.transform, null); InstantiateWagonComponents(profile.colliders, colliders.transform, null); InstantiateWagonComponents(profile.internalDetails, wagonInstance.transform, null); InstantiateWagonComponents(profile.passengerSensor, wagonInstance.transform, null); //Instantiate specific profile components if (profile.type == WagonType.Wagon) { IRailwayVehicle wagonScript = null; HingeJoint hingeJoint = null; //Add specific unity components if (profile.trainType == TrainType.PhysicsBased) { wagonScript = wagonInstance.AddComponent(); hingeJoint = wagonInstance.AddComponent(); hingeJoint.axis = new Vector3(1f, 1f, 0f); } else if (profile.trainType == TrainType.SplineBased) wagonScript = wagonInstance.AddComponent(); //Instantiate specific unity components InstantiateWagonComponents(profile.wheelsSFX, sfx.transform, new Action>(ConfigureWheelSFX), wagonScript); InstantiateWagonComponents(profile.brakesSFX, sfx.transform, new Action>(ConfigureBrakesSFX), wagonScript); InstantiateWagonComponents(profile.wagonConnectionSFX, sfx.transform, new Action>(ConfigureConnectionSFX), wagonScript); //Couplers if (profile.trainType == TrainType.PhysicsBased) InstantiateWagonComponents(profile.frontCoupler, wagonInstance.transform, new Action>(ConfigureFrontCoupler), rigidbody, wagonScript, hingeJoint); else if (profile.trainType == TrainType.SplineBased) InstantiateWagonComponents(profile.frontCoupler, wagonInstance.transform, new Action>(ConfigureFrontCoupler), rigidbody, wagonScript); InstantiateWagonComponents(profile.backCoupler, wagonInstance.transform, new Action>(ConfigureBackCoupler), rigidbody, wagonScript); //Lights InstantiateWagonComponents(profile.externalLights, lights.transform, new Action>(ConfigureExternalLights), wagonScript); InstantiateWagonComponents(profile.internalLights, lights.transform, new Action>(ConfigureInternalLights), wagonScript); //Wheels InstantiateWagonComponents(profile.wheelsVisuals, wheels.transform, new Action>(ConfigureWheels), wagonScript); if (profile.trainType == TrainType.PhysicsBased) { InstantiateWagonComponents(profile.wheelsPhysics, wheels.transform, new Action>(ConfigurePhysicsWheels), rigidbody, wagonScript); //Sensors InstantiateWagonComponents(profile.railSensor, sensors.transform, new Action>(ConfigureSensors), wagonScript); InstantiateWagonComponents(profile.defaultJointAnchor, wagonInstance.transform, new Action>(ConfigureDefaultJointAnchor), wagonScript); } } else if (profile.type == WagonType.Locomotive) { ILocomotive locomotiveScript = null; //Add specific unity components if (profile.trainType == TrainType.PhysicsBased) locomotiveScript = wagonInstance.AddComponent(); else if (profile.trainType == TrainType.SplineBased) { locomotiveScript = wagonInstance.AddComponent(); } TrainPlayerInput playerInput = wagonInstance.AddComponent(); TrainSpeedMonitor speedMonitor = wagonInstance.AddComponent(); TrainStationController stationController = wagonInstance.AddComponent(); PassengerTags passengerTags = wagonInstance.AddComponent(); passengerTags.passengerTags = new List() { "Player", "NPC" }; BoxCollider locomotiveTrigger = wagonInstance.AddComponent(); //Configure specific unity components locomotiveScript.EnginesOn = true; locomotiveScript.Acceleration = 1f; locomotiveScript.SpeedUnit = profile.speedUnits; playerInput.inputSettings = profile.inputSettings; locomotiveTrigger.isTrigger = true; locomotiveTrigger.size = new Vector3(0.5f, 0.5f, 0.5f); locomotiveTrigger.center = profile.controlZoneTriggerPosition; //Instantitate specific unity components InstantiateWagonComponents(profile.engineSFX, sfx.transform, new Action>(ConfigureEngineSFX), locomotiveScript); InstantiateWagonComponents(profile.brakesSFX, sfx.transform, new Action>(ConfigureBrakesSFX), locomotiveScript); InstantiateWagonComponents(profile.wheelsSFX, sfx.transform, new Action>(ConfigureWheelSFX), locomotiveScript); InstantiateWagonComponents(profile.hornSFX, sfx.transform, new Action>(ConfigureHornSFX), locomotiveScript); InstantiateWagonComponents(profile.bellSFX, sfx.transform, new Action>(ConfigureBellSFX), locomotiveScript); //Particles InstantiateWagonComponents(profile.smokeParticles, vfx.transform, new Action>(ConfigureSmokeParticles), locomotiveScript); InstantiateWagonComponents(profile.brakingSparksParticles, vfx.transform, new Action>(ConfigureBrakingSparksParticles), locomotiveScript); //Couplers InstantiateWagonComponents(profile.frontCoupler, wagonInstance.transform, new Action>(ConfigureFrontCoupler), rigidbody, locomotiveScript); InstantiateWagonComponents(profile.backCoupler, wagonInstance.transform, new Action>(ConfigureBackCoupler), rigidbody, locomotiveScript); //Lights InstantiateWagonComponents(profile.externalLights, lights.transform, new Action>(ConfigureExternalLights), locomotiveScript); InstantiateWagonComponents(profile.internalLights, lights.transform, new Action>(ConfigureInternalLights), locomotiveScript); //Wheels InstantiateWagonComponents(profile.wheelsVisuals, wheels.transform, new Action>(ConfigureWheels), locomotiveScript); //Steam Locomotive Rear wheels and Pistons InstantiateWagonComponents(profile.steamLocomotiveRearWheelsAndPistons, wheels.transform, new Action>(ConfigureWheels), locomotiveScript); //Bell InstantiateWagonComponents(profile.bell, wagonInstance.transform, new Action>(ConfigureBell), locomotiveScript); if (profile.trainType == TrainType.PhysicsBased) { InstantiateWagonComponents(profile.wheelsPhysics, wheels.transform, new Action>(ConfigurePhysicsWheels), rigidbody, locomotiveScript); //Sensors InstantiateWagonComponents(profile.railSensor, sensors.transform, new Action>(ConfigureSensors), locomotiveScript); } } TrainDoorsController doorsController = wagonInstance.AddComponent(); wagonInstance.AddComponent(); if (profile.trainType == TrainType.PhysicsBased) wagonInstance.AddComponent(); InstantiateWagonComponents(profile.cabinDoorLeft, doors.transform, new Action>(ConfigureLeftCabinDoor), doorsController); InstantiateWagonComponents(profile.cabinDoorRight, doors.transform, new Action>(ConfigureRightCabinDoor), doorsController); InstantiateWagonComponents(profile.passengerDoorLeft, doors.transform, new Action>(ConfigureLeftPassengerDoors), doorsController); InstantiateWagonComponents(profile.passengerDoorRight, doors.transform, new Action>(ConfigureRightPassengerDoors), doorsController); InstantiateWagonComponents(profile.openCabinDoorSFX, sfx.transform, new Action>(ConfigureOpenCabinDoorSFX), doorsController); InstantiateWagonComponents(profile.closeCabinDoorSFX, sfx.transform, new Action>(ConfigureCloseCabinDoorSFX), doorsController); InstantiateWagonComponents(profile.openPassengerDoorSFX, sfx.transform, new Action>(ConfigureOpenPassengerDoorSFX), doorsController); InstantiateWagonComponents(profile.closePassengerDoorSFX, sfx.transform, new Action>(ConfigureClosePassengerDoorSFX), doorsController); InstantiateWagonComponents(profile.closeDoorWarningSFX, sfx.transform, new Action>(ConfigureCloseDoorWarningSFX), doorsController); string carType = profile.type.ToString(); message = string.Format("{0} created successfully!", carType); return true; } /// /// Instantiate new child based on prefab /// /// /// /// /// /// /// private static GameObject InstantiateChild(GameObject prefab, string name, Vector3 position, Quaternion rotation, Transform parent) { GameObject child = GameObject.Instantiate(prefab, position, rotation, parent); child.name = name; return child; } /// /// Creates a new child game object instance /// /// /// /// /// /// private static GameObject InstantiateChild(string name, Vector3 position, Quaternion rotation, Transform parent) { GameObject child = new GameObject(name); child.transform.SetParent(parent); child.transform.position = position; child.transform.rotation = rotation; return child; } /// /// Instatiate wagon component based on profile settings /// /// /// private static void InstantiateWagonComponents(CustomWagonComponent wagonComponent, Transform parent, Delegate configMethod, params object[] configParams) { if (wagonComponent.prefab == null) return; string instanceName = string.Empty; List instances = new List(); for (int i = 0; i < wagonComponent.positions.Length; i++) { instanceName = wagonComponent.customName != string.Empty ? wagonComponent.customName : wagonComponent.prefab.name; GameObject newComponentInstance = InstantiateChild(wagonComponent.prefab, instanceName, wagonComponent.positions[i].position, Quaternion.Euler(wagonComponent.positions[i].rotation), parent); EnforceUniqueName(newComponentInstance); instances.Add(newComponentInstance); } if (configMethod != null) { List args = new List(); for (int i = 0; i < configParams.Length; i++) args.Add(configParams[i]); args.Add(instances); configParams = args.ToArray(); configMethod.DynamicInvoke(configParams); } } #region COMPONENTS CONFIGURATION METHODS /// /// /// /// /// private static void ConfigurePhysicsWheels(Rigidbody parent, IRailwayVehicle carScript, List wheels) { ConnectHingeAnchor(parent, wheels); ConfigureWheels(carScript, wheels); } /// /// /// /// /// private static void ConfigureWheels(IRailwayVehicle carScript, List wheels) { carScript.Wheels = carScript.Wheels == null ? new List() : carScript.Wheels; foreach (var item in wheels) { foreach (Transform t in item.transform) { TrainWheel_v3[] wheelScripts = t.GetComponentsInChildren(); if (wheelScripts != null) carScript.Wheels.AddRange(wheelScripts); } } } /// /// /// /// /// private static void ConfigureDefaultJointAnchor(IRailwayVehicle carScript, List joints) { if (joints != null && joints.Count > 0) { foreach (var item in joints) { Rigidbody rigid = item.GetComponent(); if (rigid != null) carScript.JointAnchor = rigid; } } } /// /// Configure front coupler and connect to parent /// /// /// /// private static void ConfigureFrontCoupler(Rigidbody parent, IRailwayVehicle carScript, HingeJoint parentJoint, List couplers) { ConnectHingeAnchor(parent, couplers); if (couplers != null && couplers.Count > 0) { foreach (var item in couplers) { Rigidbody rigid = item.GetComponent(); if (rigid != null) carScript.FrontJoint = rigid; parentJoint.anchor = item.transform.position; } } } /// /// Configure front coupler /// /// /// /// private static void ConfigureFrontCoupler(Rigidbody parent, IRailwayVehicle carScript, List couplers) { ConnectHingeAnchor(parent, couplers); if (couplers != null && couplers.Count > 0) { foreach (var item in couplers) { Rigidbody rigid = item.GetComponent(); if (rigid != null) carScript.FrontJoint = rigid; } } } /// /// /// /// /// wagon or locomotive script /// private static void ConfigureBackCoupler(Rigidbody parent, IRailwayVehicle carScript, List couplers) { ConnectHingeAnchor(parent, couplers); if (couplers != null && couplers.Count > 0) { foreach (var item in couplers) { Rigidbody rigid = item.GetComponent(); if (rigid != null) carScript.BackJoint = rigid; } } } /// /// /// /// /// private static void ConnectHingeAnchor(Rigidbody connectedBody, List toConnect) { foreach (var item in toConnect) { HingeJoint joint = item.GetComponent(); if (joint != null) joint.connectedBody = connectedBody; } } /// /// /// /// /// private static void ConfigureWheelSFX(IRailwayVehicle carScript, List sfxs) { if (sfxs != null && sfxs.Count > 0) { foreach (var item in sfxs) { AudioSource wheelSFX = item.GetComponent(); if (wheelSFX != null) carScript.WheelsSFX = wheelSFX; } } } /// /// /// /// /// private static void ConfigureConnectionSFX(IRailwayVehicle carScript, List sfxs) { if (sfxs != null && sfxs.Count > 0) { foreach (var item in sfxs) { AudioSource connectionSFX = item.GetComponent(); if (connectionSFX != null) carScript.WagonConnectionSFX = connectionSFX; } } } /// /// /// /// /// private static void ConfigureHornSFX(ILocomotive locomotive, List sfxs) { if (sfxs != null && sfxs.Count > 0) { foreach (var item in sfxs) { AudioSource audio = item.GetComponent(); if (audio != null) locomotive.HornSFX = audio; } } } /// /// /// /// /// private static void ConfigureBellSFX(ILocomotive locomotive, List sfxs) { if (sfxs != null && sfxs.Count > 0) { foreach (var item in sfxs) { AudioSource audio = item.GetComponent(); if (audio != null) locomotive.BellSFX = audio; } } } /// /// /// /// /// private static void ConfigureEngineSFX(ILocomotive locomotive, List sfxs) { if (sfxs != null && sfxs.Count > 0) { foreach (var item in sfxs) { AudioSource audio = item.GetComponent(); if (audio != null) locomotive.EngineSFX = audio; } } } /// /// /// /// /// private static void ConfigureBrakesSFX(IRailwayVehicle carScript, List sfxs) { if (sfxs != null && sfxs.Count > 0) { foreach (var item in sfxs) { AudioSource audio = item.GetComponent(); if (audio != null) carScript.BrakesSFX = audio; } } } /// /// /// /// /// private static void ConfigureSensors(IRailwayVehicle carScript, List sensors) { if (sensors != null && sensors.Count > 0) { carScript.Sensors = new Sensors(); for (int i = 0; i < sensors.Count; i++) { if (i % 2 == 0) carScript.Sensors.leftSensor = sensors[i].GetComponent(); else carScript.Sensors.rightSensor = sensors[i].GetComponent(); } } } /// /// /// /// /// private static void ConfigureExternalLights(IRailwayVehicle carScript, List lights) { if (lights != null && lights.Count > 0) { carScript.ExternalLights = new List(); foreach (var item in lights) { Light light = item.GetComponent(); if (light != null) carScript.ExternalLights.Add(light); } } } /// /// /// /// /// private static void ConfigureInternalLights(IRailwayVehicle carScript, List lights) { if (lights != null && lights.Count > 0) { if (carScript.InternalLights == null) carScript.InternalLights = new List(); foreach (var item in lights) { Light light = item.GetComponent(); if (light != null) carScript.InternalLights.Add(light); } } } /// /// /// /// /// private static void ConfigureLeftCabinDoor(TrainDoorsController doorController, List doors) { if (doors != null && doors.Count > 0) { foreach (var item in doors) { TrainDoor doorScript = item.GetComponent(); if (doorScript != null) doorController.cabinDoorLeft = doorScript; } } } /// /// /// /// /// private static void ConfigureRightCabinDoor(TrainDoorsController doorController, List doors) { if (doors != null && doors.Count > 0) { foreach (var item in doors) { TrainDoor doorScript = item.GetComponent(); if (doorScript != null) doorController.cabinDoorRight = doorScript; } } } /// /// /// /// /// private static void ConfigureLeftPassengerDoors(TrainDoorsController doorController, List doors) { if (doors != null && doors.Count > 0) { doorController.passengerDoorsLeft = new List(); foreach (var item in doors) { TrainDoor doorScript = item.GetComponent(); if (doorScript != null) doorController.passengerDoorsLeft.Add(doorScript); } } } /// /// /// /// /// private static void ConfigureRightPassengerDoors(TrainDoorsController doorController, List doors) { if (doors != null && doors.Count > 0) { doorController.passengerDoorsRight = new List(); foreach (var item in doors) { TrainDoor doorScript = item.GetComponent(); if (doorScript != null) doorController.passengerDoorsRight.Add(doorScript); } } } /// /// /// /// /// private static void ConfigureOpenCabinDoorSFX(TrainDoorsController doorController, List sfxs) { if (sfxs != null && sfxs.Count > 0) { foreach (var item in sfxs) { AudioSource openDoorSFX = item.GetComponent(); if (openDoorSFX != null) doorController.openCabinDoorSFX = openDoorSFX; } } } /// /// /// /// /// private static void ConfigureOpenPassengerDoorSFX(TrainDoorsController doorController, List sfxs) { if (sfxs != null && sfxs.Count > 0) { foreach (var item in sfxs) { AudioSource openDoorSFX = item.GetComponent(); if (openDoorSFX != null) doorController.openPassengerDoorSFX = openDoorSFX; } } } /// /// /// /// /// private static void ConfigureCloseCabinDoorSFX(TrainDoorsController doorController, List sfxs) { if (sfxs != null && sfxs.Count > 0) { foreach (var item in sfxs) { AudioSource closeDoorSFX = item.GetComponent(); if (closeDoorSFX != null) doorController.closeCabinDoorSFX = closeDoorSFX; } } } /// /// /// /// /// private static void ConfigureClosePassengerDoorSFX(TrainDoorsController doorController, List sfxs) { if (sfxs != null && sfxs.Count > 0) { foreach (var item in sfxs) { AudioSource closeDoorSFX = item.GetComponent(); if (closeDoorSFX != null) doorController.closePassengerDoorSFX = closeDoorSFX; } } } /// /// /// /// /// private static void ConfigureCloseDoorWarningSFX(TrainDoorsController doorController, List sfxs) { if (sfxs != null && sfxs.Count > 0) { foreach (var item in sfxs) { AudioSource closeDoorSFX = item.GetComponent(); if (closeDoorSFX != null) doorController.closeDoorsWarningSFX = closeDoorSFX; } } } /// /// /// /// /// private static void ConfigureSmokeParticles(ILocomotive locomotive, List smokeParticles) { if (smokeParticles != null && smokeParticles.Count > 0) { foreach (var item in smokeParticles) { ParticleSystem smoke = item.GetComponent(); if (smoke != null) locomotive.SmokeParticles = smoke; } } } /// /// /// /// /// private static void ConfigureBrakingSparksParticles(ILocomotive locomotive, List brakingSparksParticles) { if (brakingSparksParticles != null && brakingSparksParticles.Count > 0) { locomotive.BrakingSparksParticles = new ParticleSystem[brakingSparksParticles.Count]; for (int i = 0; i < brakingSparksParticles.Count; i++) { ParticleSystem sparks = brakingSparksParticles[i].GetComponent(); if (sparks != null) locomotive.BrakingSparksParticles[i] = sparks; } } } /// /// /// /// /// private static void ConfigureBell(ILocomotive locomotive, List bells) { if (bells != null && bells.Count > 0) { foreach (var item in bells) { Animator bellAnimator = item.GetComponent(); if (bellAnimator != null) locomotive.BellAnimator = bellAnimator; } } } /// /// Make sure new object has a unique name /// /// private static void EnforceUniqueName(GameObject targetObject) { #if UNITY_EDITOR targetObject.name = targetObject.name.Replace("(Clone)", string.Empty); UnityEditor.GameObjectUtility.EnsureUniqueNameForSibling(targetObject); #endif } #endregion } }