using System.Collections.Generic; using UnityEngine; namespace WSMGameStudio.RailroadSystem { public class Wagon_v3 : MonoBehaviour, IRailwayVehicle { #region VARIABLES private TrainController_v3 _locomotive; private HingeJoint _carJoint; private Rigidbody _rigidbody; private Transform _transform; private bool _isGrounded; private float _maxSpeedMps = 65f; [Range(-1f, 1f)] private float _acceleration = 0f; [Range(0f, 1f)] private float _brake = 0f; private float _speed_MPS; private float _accelerationRate_MPS = 5f; private float _brakingDecelerationRate_MPS = 4.0f; private float _inertiaDecelerationRate_MPS = 2.0f; //private bool _shouldBeStatic = false; private bool _reverseAcceleration = false; private bool _locomotiveEngineOn = false; //Movement private Vector3 _targetVelocity; private float _targetSpeed; private float _currentSpeed; private float _wagonAccel; private Vector3 _localVelocity; //SFX private TrainAudio _trainAudio; public AudioSource wheelsSFX; public AudioSource wagonConnectionSFX; [Range(0f, 3f)] public float minWheelsPitch = 0.6f; [Range(0f, 3f)] public float maxWheelsPitch = 1.5f; public List wheelsScripts; public Sensors sensors; public List externalLights; public List internalLights; public Rigidbody backJoint; //Must be rigibody for hinge connection public Rigidbody frontJoint; public Rigidbody jointAnchor; public WagonCoupling coupling; public WagonDecouplingSettings decouplingSettings; public float recouplingTimeout = 1f; #endregion #region PROPERTIES // Locomotive that commands this wagon public TrainController_v3 Locomotive { get { return _locomotive; } set { _locomotive = value; } } public bool IsConected { get { return _locomotive != null; } } public bool IsGrounded { get { return _isGrounded; } } public float MaxSpeedMps { get { return _maxSpeedMps; } set { _maxSpeedMps = value; } } public float Acceleration { get { return _acceleration; } set { _acceleration = value; } } public float AccelerationRate_MPS { get { return _accelerationRate_MPS; } set { _accelerationRate_MPS = Mathf.Abs(value); } } public float Brake { get { return _brake; } set { _brake = value; } } /// /// Identify if wagon was connected backwards and needs to move the oposite direction /// public bool ReverseAcceleration { get { return _reverseAcceleration; } set { _reverseAcceleration = value; } } // Joint for wagon connection public HingeJoint CarJoint { get { return _carJoint; } } public Rigidbody JointAnchor { get { return jointAnchor; } set { jointAnchor = value; } } public Rigidbody FrontJoint { get { return frontJoint; } set { frontJoint = value; } } public Rigidbody BackJoint { get { return backJoint; } set { backJoint = value; } } public List Wheels { get { return wheelsScripts; } set { wheelsScripts = value; } } public AudioSource WheelsSFX { get { return wheelsSFX; } set { wheelsSFX = value; } } public AudioSource WagonConnectionSFX { get { return wagonConnectionSFX; } set { wagonConnectionSFX = value; } } public AudioSource BrakesSFX { get { return null; } set { } } public Sensors Sensors { get { return sensors; } set { sensors = value; } } public List ExternalLights { get { return externalLights; } set { externalLights = value; } } public List InternalLights { get { return internalLights; } set { internalLights = value; } } public GameObject GetGameObject { get { return gameObject; } } public TrainType TrainType { get { return TrainType.PhysicsBased; } } /// /// Distance between front and back couplers /// public float CouplersDistance { get { if (frontJoint == null || backJoint == null) { Debug.LogError(string.Format("Couplers not set on {0}. Please manually set the couplers references and try again", gameObject.name.ToUpper())); return 0f; } return Mathf.Abs(frontJoint.transform.localPosition.z) + Mathf.Abs(backJoint.transform.localPosition.z); ; } } /// /// 1 - moving forward /// 0 - not moving /// -1 - moving backwards /// public int LocalDirection { get { float localVel = _transform.InverseTransformDirection(_rigidbody.velocity).z; return localVel > 0f ? 1 : (localVel < 0f ? -1 : 0); } } #endregion #region UNITY EVENTS /// /// Initialie wagon /// private void Start() { _rigidbody = GetComponent(); _transform = GetComponent(); _carJoint = GetComponent(); InitializeSFX(); } /// /// Physics /// void FixedUpdate() { EnforceAnchorPosition(); UpdateVelocity(); _isGrounded = sensors.leftSensor.Grounded || sensors.rightSensor.Grounded; _speed_MPS = _rigidbody.velocity.magnitude; _wagonAccel = _reverseAcceleration ? (_acceleration * (-1)) : _acceleration; _localVelocity = _transform.InverseTransformDirection(_rigidbody.velocity); TrainPhysics.UpdateWheels(wheelsScripts, _brake, _localVelocity.z); TrainPhysics.SpeedControl_PhysicsBased(_rigidbody, _locomotiveEngineOn, _isGrounded, _maxSpeedMps, _speed_MPS, _wagonAccel, _brake, _accelerationRate_MPS, _brakingDecelerationRate_MPS, _inertiaDecelerationRate_MPS, _targetVelocity, out _targetVelocity, _currentSpeed, out _currentSpeed, _targetSpeed, out _targetSpeed); _trainAudio.UpdateSFX(Speed.Convert_MPS_To_KPH(_speed_MPS), _brake, false, _isGrounded); } #endregion #region METHODS /// /// Initialize SFX /// private void InitializeSFX() { SFX sfx = new SFX(); sfx.wheelsSFX = wheelsSFX; sfx.wagonConnectionSFX = wagonConnectionSFX; sfx.minWheelsPitch = minWheelsPitch; sfx.maxWheelsPitch = maxWheelsPitch; _trainAudio = new TrainAudio(sfx); } /// /// Turn external lights on/off /// public void ToggleLights() { if (externalLights == null) return; foreach (Light light in externalLights) light.enabled = !light.enabled; } /// /// Turn internal lights on/off /// public void ToggleInternalLights() { if (internalLights == null) return; foreach (Light light in internalLights) light.enabled = !light.enabled; } /// /// Connect wagon to train /// /// Current wagon coupler (front or back) /// Other wagon coupler public void Connect(TrainCarCoupler carCoupler, TrainCarCoupler otherCarCoupler, bool playSFX) { if (coupling == WagonCoupling.Enabled) { if (otherCarCoupler.IsLocomotive) { _locomotive = otherCarCoupler.Locomotive as TrainController_v3; _reverseAcceleration = (carCoupler.IsBackJoint == otherCarCoupler.IsBackJoint); } else if (otherCarCoupler.IsWagon) { if (!otherCarCoupler.Wagon.IsConected) return; _locomotive = otherCarCoupler.Wagon.Locomotive; _reverseAcceleration = (carCoupler.IsBackJoint != otherCarCoupler.IsBackJoint) ? otherCarCoupler.Wagon.ReverseAcceleration : !otherCarCoupler.Wagon.ReverseAcceleration; } TrainPhysics.ConnectTrainCar(_carJoint, otherCarCoupler.GetComponent()); _locomotive.WagonsScripts.Add(this); _locomotive.UpdateDoorController(); if (playSFX && _trainAudio != null) _trainAudio.PlayConnectionSFX(); } } /// /// Disconnect wagon from train /// public void Disconnect(bool disconnectJoint) { if (disconnectJoint) _carJoint.connectedBody = jointAnchor; _locomotive = null; _trainAudio.PlayConnectionSFX(); coupling = WagonCoupling.Disabled; if (decouplingSettings == WagonDecouplingSettings.AllowRecoupling) { Invoke("ReenabledCoupling", Mathf.Abs(recouplingTimeout)); } } /// /// Reenable wagon coupling /// private void ReenabledCoupling() { coupling = WagonCoupling.Enabled; } /// /// Updates wagon velocity /// private void UpdateVelocity() { if (_locomotive != null) { _locomotiveEngineOn = _locomotive.EnginesOn; _acceleration = _locomotive.IsGrounded ? _locomotive.Acceleration : 0; _maxSpeedMps = _locomotive.IsGrounded ? _locomotive.MaxSpeed_MPS : 0; _brake = _locomotive.IsGrounded ? _locomotive.Brake : 0; _accelerationRate_MPS = _locomotive.IsGrounded ? _locomotive.AccelerationRate_MPS : _accelerationRate_MPS; _brakingDecelerationRate_MPS = _locomotive.IsGrounded ? _locomotive.BrakingDecelerationRate_MPS : _brakingDecelerationRate_MPS; _inertiaDecelerationRate_MPS = _locomotive.IsGrounded ? _locomotive.InertiaDecelerationRate_MPS : _inertiaDecelerationRate_MPS; } else { _locomotiveEngineOn = false; _acceleration = Mathf.MoveTowards(_acceleration, 0f, _inertiaDecelerationRate_MPS * Time.deltaTime); _maxSpeedMps = Mathf.MoveTowards(_maxSpeedMps, 0f, _inertiaDecelerationRate_MPS * Time.deltaTime); _brake = 1f; _targetVelocity = Vector3.zero; } } /// /// Always keeps anchor in the right place /// private void EnforceAnchorPosition() { if (jointAnchor != null) { jointAnchor.transform.localPosition = _carJoint.anchor; jointAnchor.transform.localRotation = Quaternion.identity; } } #endregion } }