GaelVanhalst

Linked: AirElevator

Nov 11th, 2016
227
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 11.47 KB | None | 0 0
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4.  
  5. //This handles the air elevators. With this object players can move vertically and certain objects can float in it
  6. public class AirElevatorScript : BaseComboInputTriggerableObject
  7. {
  8.     private const float ClimbSpeed = 5.0f;
  9.     private const float ClimbAcceleration = 10.0f;
  10.     private const float FloatingSpeed = 2.0f;
  11.     private const float FloatDelta = 0.15f;
  12.     private const float DistanceToKeepFromFloor = 0.1f;
  13.     private const float VertialPushForce = 0.025f;
  14.     private static int _linkId;
  15.  
  16.     [SerializeField]private float _heightElevator = 4.5f;
  17.     [SerializeField]private float _diameter = 2;
  18.     [SerializeField]private ResizableOpenCylinder _cylinder = null;
  19.     [SerializeField]private bool _defaultOn = true;
  20.     [SerializeField]private Renderer _pedestalRenderer = null;
  21.     [SerializeField]private int _indexLinkMaterial = 0;
  22.  
  23.     private List<AirElevatorObject> _airElevatorObjects=new List<AirElevatorObject>();
  24.     private float _currentHeightElevator = 0;
  25.     private float _growingSpeed = 10.0f;
  26.     private bool _on = false;
  27.  
  28.     private Coroutine _growingOrShrinking;
  29.     private Coroutine _airElevatorUpdate = null;
  30.  
  31.     private void Awake()
  32.     {
  33.         //The shader property to make the pedestal show if it is on or off.
  34.         _linkId = Shader.PropertyToID("_Linked");
  35.  
  36.         //Set the correct start state and height of the elevator
  37.         _on = _defaultOn;
  38.         if(_on)
  39.         {
  40.             _currentHeightElevator = _heightElevator;
  41.         }
  42.         else
  43.         {
  44.             _currentHeightElevator = 0;
  45.         }
  46.  
  47.         UpdateElevatorHeight();
  48.     }
  49.  
  50.     private IEnumerator AirElevatorUpdate()
  51.     {
  52.         while (_airElevatorObjects.Count>0)
  53.         {
  54.             yield return new WaitForFixedUpdate();
  55.  
  56.             for (int i = 0; i < _airElevatorObjects.Count;)
  57.             {
  58.                 var airElevatorObject = _airElevatorObjects[i];
  59.                 if (airElevatorObject.Rigidbody == null)
  60.                 {
  61.                     //The object is gone so remove it
  62.                     _airElevatorObjects.RemoveAt(i);
  63.                     continue;
  64.                 }
  65.  
  66.                 float climbAmount = 0;
  67.                 bool needsSpecialMovement = false;
  68.  
  69.                 var airElevatorEnabledObject = airElevatorObject.AirElevatorEnabledObject;
  70.                 //If object can't move go to the next object
  71.                 if (!airElevatorEnabledObject.CanMove())
  72.                 {
  73.                     i++;
  74.                     continue;
  75.                 }
  76.  
  77.                 //Update
  78.                 airElevatorEnabledObject.AirElevatorUpdate();
  79.                 needsSpecialMovement = airElevatorEnabledObject.NeedsSpecialMovement();
  80.  
  81.                 //Get the climbspeed that the object wants
  82.                 var wantedClimbSpeed = airElevatorEnabledObject.GetVerticalMovement() * ClimbSpeed;
  83.                 var climbCurrentAcceleration = ClimbAcceleration * Time.deltaTime;
  84.  
  85.                 //Calculate the current speed
  86.                 var deltaSpeed = wantedClimbSpeed - airElevatorObject.CurrentClimbSpeed;
  87.                 if (Mathf.Abs(deltaSpeed) < climbCurrentAcceleration)
  88.                 {
  89.                     airElevatorObject.CurrentClimbSpeed = wantedClimbSpeed;
  90.                 }
  91.                 else
  92.                 {
  93.                     airElevatorObject.CurrentClimbSpeed += climbCurrentAcceleration * Mathf.Sign(deltaSpeed);
  94.                 }
  95.                 //Calculate the amount the object climbs
  96.                 climbAmount += Time.deltaTime * airElevatorObject.CurrentClimbSpeed;
  97.  
  98.                 //Floating calculations
  99.                 float previousSinHeight = Mathf.Sin(airElevatorObject.SinTime);
  100.  
  101.                 if (!Mathf.Approximately(airElevatorObject.CurrentClimbSpeed, 0))
  102.                 {
  103.                     //The object has moved up or down, so the next floating wave should continue on that movement
  104.                     if (airElevatorObject.CurrentClimbSpeed > 0) airElevatorObject.SinTime = Mathf.PI;
  105.                     else airElevatorObject.SinTime = 0;
  106.                 }
  107.                 else
  108.                 {
  109.                     //Get the delta the object has moved in by floating
  110.                     airElevatorObject.SinTime += Time.deltaTime*FloatingSpeed;
  111.                     var sinHeight = Mathf.Sin(airElevatorObject.SinTime);
  112.  
  113.                     var sinDelta = (sinHeight - previousSinHeight)*FloatDelta;
  114.                     climbAmount += sinDelta;
  115.                 }
  116.  
  117.                 //Extra forces
  118.                 var rigidBody = airElevatorObject.Rigidbody;
  119.                     //Drag
  120.                 rigidBody.AddForce(-rigidBody.velocity*Time.deltaTime,ForceMode.VelocityChange);
  121.  
  122.                     //Counter gravity
  123.                 if (rigidBody.useGravity && !rigidBody.isKinematic)
  124.                 {
  125.                     //Add reverse gravity to counteract gravity
  126.                     rigidBody.AddForce(-Physics.gravity,ForceMode.Acceleration);
  127.                 }
  128.  
  129.                 //Check to not go through walls and floors
  130.                 RaycastHit hit;
  131.  
  132.                 float originalClimbAmount = climbAmount;
  133.                 if (rigidBody.SweepTest(new Vector3(0, climbAmount, 0).normalized, out hit, Mathf.Abs(climbAmount)+DistanceToKeepFromFloor))
  134.                 {
  135.                     if (hit.rigidbody != null&&!hit.rigidbody.isKinematic)
  136.                     {
  137.                         //Give a small push to the object that got hit.
  138.                         hit.rigidbody.AddForce((new Vector3(0,climbAmount,0)/Time.deltaTime)*VertialPushForce,ForceMode.VelocityChange);
  139.                     }
  140.  
  141.                     //Calculate the new climb amount so we don't move through the floor
  142.                     climbAmount = (hit.distance-DistanceToKeepFromFloor) * Mathf.Sign(climbAmount);
  143.                 }
  144.  
  145.                 //If new climb amount has another direction compared to original climbamount then the climbamount should be 0
  146.                 if (Mathf.Sign(originalClimbAmount*climbAmount) < 0) climbAmount = 0;
  147.  
  148.                 if (needsSpecialMovement)
  149.                 {
  150.                     //This object needs to handle movement on its own.
  151.                     airElevatorEnabledObject.SpecialMovement(new Vector3(0,climbAmount,0));
  152.                 }
  153.                 else
  154.                 {
  155.                     rigidBody.MovePosition(rigidBody.position + new Vector3(0, climbAmount, 0));
  156.                 }
  157.  
  158.  
  159.                 //Update all the values
  160.                 _airElevatorObjects[i] = airElevatorObject;
  161.  
  162.                 i++;
  163.             }
  164.         }
  165.         _airElevatorUpdate = null;
  166.     }
  167.  
  168.     private IEnumerator GrowOrShrinkAirElevator()
  169.     {
  170.         while (true)
  171.         {
  172.             yield return new WaitForFixedUpdate();
  173.             if (_on)
  174.             {
  175.                 //Grow elevator to max height
  176.                 _currentHeightElevator+=_growingSpeed*Time.deltaTime;
  177.  
  178.                 if (_currentHeightElevator >= _heightElevator)
  179.                 {
  180.                     _currentHeightElevator = _heightElevator;
  181.                     UpdateElevatorHeight();
  182.                     break;
  183.                 }
  184.             }
  185.             else
  186.             {
  187.                 //Shrink elevator to minimum
  188.                 _currentHeightElevator -= _growingSpeed * Time.deltaTime;
  189.                 if (_currentHeightElevator < 0)
  190.                 {
  191.                     _currentHeightElevator = 0;
  192.                     UpdateElevatorHeight();
  193.                     break;
  194.                 }
  195.             }
  196.             UpdateElevatorHeight();
  197.         }
  198.         _growingOrShrinking = null;
  199.     }
  200.  
  201.     protected override void Triggered(bool positive)
  202.     {
  203.         //Activate or deactivate the air elevator
  204.  
  205.         if (_defaultOn) positive = !positive;
  206.         _on = positive;
  207.         if (_growingOrShrinking == null)
  208.         {
  209.             _growingOrShrinking = StartCoroutine(GrowOrShrinkAirElevator());
  210.         }
  211.     }
  212.  
  213.     public void OnTriggerEnter(Collider other)
  214.     {
  215.         //Check if the object is compatible with the air elevator
  216.         var enabledObject = other.GetComponent<IAirElevatorEnabledObject>();
  217.  
  218.         if (enabledObject != null)
  219.         {
  220.             _airElevatorObjects.Add(new AirElevatorObject(other.attachedRigidbody, enabledObject));
  221.  
  222.             //If there is no current update running start a new one
  223.             if (_airElevatorUpdate==null)
  224.             {
  225.                 _airElevatorUpdate=StartCoroutine(AirElevatorUpdate());
  226.             }
  227.         }
  228.     }
  229.  
  230.     public void OnTriggerExit(Collider other)
  231.     {
  232.         //Check if the object is compatible with the air elevator
  233.         var airElevatorEnabledObject = other.GetComponent<IAirElevatorEnabledObject>();
  234.  
  235.         if (airElevatorEnabledObject != null)
  236.         {
  237.             RemoveAirElevatorObject(airElevatorEnabledObject);
  238.  
  239.             //If there are no objects anymore in the air elevator, then the update can be stopped
  240.             if (_airElevatorObjects.Count == 0&&_airElevatorUpdate!=null)
  241.             {
  242.                 StopCoroutine(_airElevatorUpdate);
  243.                 _airElevatorUpdate = null;
  244.             }
  245.         }
  246.     }
  247.  
  248.     private void RemoveAirElevatorObject(IAirElevatorEnabledObject airElevatorEnabledObject)
  249.     {
  250.         for (int i = 0; i < _airElevatorObjects.Count; i++)
  251.         {
  252.             if (_airElevatorObjects[i].AirElevatorEnabledObject != airElevatorEnabledObject) continue;
  253.  
  254.             _airElevatorObjects[i].AirElevatorEnabledObject.ObjectLeft();
  255.             _airElevatorObjects.RemoveAt(i);
  256.             return;
  257.         }
  258.     }
  259.  
  260.     //Change how high the elevator can be
  261.     private void UpdateElevatorHeight()
  262.     {
  263.         _cylinder.ChangeHeight(_currentHeightElevator, _diameter);
  264.  
  265.         //The shader property to make the pedestal show if it is on or off.
  266.         var amount = _currentHeightElevator / _heightElevator;
  267.         _pedestalRenderer.materials[_indexLinkMaterial].SetFloat(_linkId, amount);
  268.     }
  269.  
  270. #if UNITY_EDITOR
  271.     public void GenerateElevators()
  272.     {
  273.         var cylinder = GetComponent<ResizableOpenCylinder>();
  274.  
  275.         //Do checks, because a chance in diameter or height means that the cylinder needs to be regenerated.
  276.         if (!Mathf.Approximately(cylinder.Diameter,_diameter))
  277.         {
  278.             cylinder.Diameter = _diameter;
  279.         }
  280.         if (!Mathf.Approximately(cylinder.Height, _heightElevator))
  281.         {
  282.             cylinder.Height = _heightElevator;
  283.         }
  284.     }
  285. #endif
  286.  
  287.     private struct AirElevatorObject
  288.     {
  289.         public AirElevatorObject(Rigidbody rigidbody, IAirElevatorEnabledObject airElevatorEnabledObject)
  290.         {
  291.             Rigidbody = rigidbody;
  292.             CurrentClimbSpeed = 0.0f;
  293.             //Sin start at PI, so it moves down first
  294.             SinTime = Mathf.PI;
  295.             AirElevatorEnabledObject = airElevatorEnabledObject;
  296.         }
  297.  
  298.         public Rigidbody Rigidbody;
  299.         public float CurrentClimbSpeed;
  300.         public float SinTime;
  301.         public IAirElevatorEnabledObject AirElevatorEnabledObject;
  302.     }
  303.  
  304.     public interface IAirElevatorEnabledObject
  305.     {
  306.         void ObjectEnter();
  307.         void ObjectLeft();
  308.         void AirElevatorUpdate();
  309.         float GetVerticalMovement();
  310.         bool NeedsSpecialMovement();
  311.         bool CanMove();
  312.         void SpecialMovement(Vector3 movement);
  313.     }
  314. }
Add Comment
Please, Sign In to add comment