Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using UnityEngine;
- using System.Collections;
- using System.Collections.Generic;
- //This handles the air elevators. With this object players can move vertically and certain objects can float in it
- public class AirElevatorScript : BaseComboInputTriggerableObject
- {
- private const float ClimbSpeed = 5.0f;
- private const float ClimbAcceleration = 10.0f;
- private const float FloatingSpeed = 2.0f;
- private const float FloatDelta = 0.15f;
- private const float DistanceToKeepFromFloor = 0.1f;
- private const float VertialPushForce = 0.025f;
- private static int _linkId;
- [SerializeField]private float _heightElevator = 4.5f;
- [SerializeField]private float _diameter = 2;
- [SerializeField]private ResizableOpenCylinder _cylinder = null;
- [SerializeField]private bool _defaultOn = true;
- [SerializeField]private Renderer _pedestalRenderer = null;
- [SerializeField]private int _indexLinkMaterial = 0;
- private List<AirElevatorObject> _airElevatorObjects=new List<AirElevatorObject>();
- private float _currentHeightElevator = 0;
- private float _growingSpeed = 10.0f;
- private bool _on = false;
- private Coroutine _growingOrShrinking;
- private Coroutine _airElevatorUpdate = null;
- private void Awake()
- {
- //The shader property to make the pedestal show if it is on or off.
- _linkId = Shader.PropertyToID("_Linked");
- //Set the correct start state and height of the elevator
- _on = _defaultOn;
- if(_on)
- {
- _currentHeightElevator = _heightElevator;
- }
- else
- {
- _currentHeightElevator = 0;
- }
- UpdateElevatorHeight();
- }
- private IEnumerator AirElevatorUpdate()
- {
- while (_airElevatorObjects.Count>0)
- {
- yield return new WaitForFixedUpdate();
- for (int i = 0; i < _airElevatorObjects.Count;)
- {
- var airElevatorObject = _airElevatorObjects[i];
- if (airElevatorObject.Rigidbody == null)
- {
- //The object is gone so remove it
- _airElevatorObjects.RemoveAt(i);
- continue;
- }
- float climbAmount = 0;
- bool needsSpecialMovement = false;
- var airElevatorEnabledObject = airElevatorObject.AirElevatorEnabledObject;
- //If object can't move go to the next object
- if (!airElevatorEnabledObject.CanMove())
- {
- i++;
- continue;
- }
- //Update
- airElevatorEnabledObject.AirElevatorUpdate();
- needsSpecialMovement = airElevatorEnabledObject.NeedsSpecialMovement();
- //Get the climbspeed that the object wants
- var wantedClimbSpeed = airElevatorEnabledObject.GetVerticalMovement() * ClimbSpeed;
- var climbCurrentAcceleration = ClimbAcceleration * Time.deltaTime;
- //Calculate the current speed
- var deltaSpeed = wantedClimbSpeed - airElevatorObject.CurrentClimbSpeed;
- if (Mathf.Abs(deltaSpeed) < climbCurrentAcceleration)
- {
- airElevatorObject.CurrentClimbSpeed = wantedClimbSpeed;
- }
- else
- {
- airElevatorObject.CurrentClimbSpeed += climbCurrentAcceleration * Mathf.Sign(deltaSpeed);
- }
- //Calculate the amount the object climbs
- climbAmount += Time.deltaTime * airElevatorObject.CurrentClimbSpeed;
- //Floating calculations
- float previousSinHeight = Mathf.Sin(airElevatorObject.SinTime);
- if (!Mathf.Approximately(airElevatorObject.CurrentClimbSpeed, 0))
- {
- //The object has moved up or down, so the next floating wave should continue on that movement
- if (airElevatorObject.CurrentClimbSpeed > 0) airElevatorObject.SinTime = Mathf.PI;
- else airElevatorObject.SinTime = 0;
- }
- else
- {
- //Get the delta the object has moved in by floating
- airElevatorObject.SinTime += Time.deltaTime*FloatingSpeed;
- var sinHeight = Mathf.Sin(airElevatorObject.SinTime);
- var sinDelta = (sinHeight - previousSinHeight)*FloatDelta;
- climbAmount += sinDelta;
- }
- //Extra forces
- var rigidBody = airElevatorObject.Rigidbody;
- //Drag
- rigidBody.AddForce(-rigidBody.velocity*Time.deltaTime,ForceMode.VelocityChange);
- //Counter gravity
- if (rigidBody.useGravity && !rigidBody.isKinematic)
- {
- //Add reverse gravity to counteract gravity
- rigidBody.AddForce(-Physics.gravity,ForceMode.Acceleration);
- }
- //Check to not go through walls and floors
- RaycastHit hit;
- float originalClimbAmount = climbAmount;
- if (rigidBody.SweepTest(new Vector3(0, climbAmount, 0).normalized, out hit, Mathf.Abs(climbAmount)+DistanceToKeepFromFloor))
- {
- if (hit.rigidbody != null&&!hit.rigidbody.isKinematic)
- {
- //Give a small push to the object that got hit.
- hit.rigidbody.AddForce((new Vector3(0,climbAmount,0)/Time.deltaTime)*VertialPushForce,ForceMode.VelocityChange);
- }
- //Calculate the new climb amount so we don't move through the floor
- climbAmount = (hit.distance-DistanceToKeepFromFloor) * Mathf.Sign(climbAmount);
- }
- //If new climb amount has another direction compared to original climbamount then the climbamount should be 0
- if (Mathf.Sign(originalClimbAmount*climbAmount) < 0) climbAmount = 0;
- if (needsSpecialMovement)
- {
- //This object needs to handle movement on its own.
- airElevatorEnabledObject.SpecialMovement(new Vector3(0,climbAmount,0));
- }
- else
- {
- rigidBody.MovePosition(rigidBody.position + new Vector3(0, climbAmount, 0));
- }
- //Update all the values
- _airElevatorObjects[i] = airElevatorObject;
- i++;
- }
- }
- _airElevatorUpdate = null;
- }
- private IEnumerator GrowOrShrinkAirElevator()
- {
- while (true)
- {
- yield return new WaitForFixedUpdate();
- if (_on)
- {
- //Grow elevator to max height
- _currentHeightElevator+=_growingSpeed*Time.deltaTime;
- if (_currentHeightElevator >= _heightElevator)
- {
- _currentHeightElevator = _heightElevator;
- UpdateElevatorHeight();
- break;
- }
- }
- else
- {
- //Shrink elevator to minimum
- _currentHeightElevator -= _growingSpeed * Time.deltaTime;
- if (_currentHeightElevator < 0)
- {
- _currentHeightElevator = 0;
- UpdateElevatorHeight();
- break;
- }
- }
- UpdateElevatorHeight();
- }
- _growingOrShrinking = null;
- }
- protected override void Triggered(bool positive)
- {
- //Activate or deactivate the air elevator
- if (_defaultOn) positive = !positive;
- _on = positive;
- if (_growingOrShrinking == null)
- {
- _growingOrShrinking = StartCoroutine(GrowOrShrinkAirElevator());
- }
- }
- public void OnTriggerEnter(Collider other)
- {
- //Check if the object is compatible with the air elevator
- var enabledObject = other.GetComponent<IAirElevatorEnabledObject>();
- if (enabledObject != null)
- {
- _airElevatorObjects.Add(new AirElevatorObject(other.attachedRigidbody, enabledObject));
- //If there is no current update running start a new one
- if (_airElevatorUpdate==null)
- {
- _airElevatorUpdate=StartCoroutine(AirElevatorUpdate());
- }
- }
- }
- public void OnTriggerExit(Collider other)
- {
- //Check if the object is compatible with the air elevator
- var airElevatorEnabledObject = other.GetComponent<IAirElevatorEnabledObject>();
- if (airElevatorEnabledObject != null)
- {
- RemoveAirElevatorObject(airElevatorEnabledObject);
- //If there are no objects anymore in the air elevator, then the update can be stopped
- if (_airElevatorObjects.Count == 0&&_airElevatorUpdate!=null)
- {
- StopCoroutine(_airElevatorUpdate);
- _airElevatorUpdate = null;
- }
- }
- }
- private void RemoveAirElevatorObject(IAirElevatorEnabledObject airElevatorEnabledObject)
- {
- for (int i = 0; i < _airElevatorObjects.Count; i++)
- {
- if (_airElevatorObjects[i].AirElevatorEnabledObject != airElevatorEnabledObject) continue;
- _airElevatorObjects[i].AirElevatorEnabledObject.ObjectLeft();
- _airElevatorObjects.RemoveAt(i);
- return;
- }
- }
- //Change how high the elevator can be
- private void UpdateElevatorHeight()
- {
- _cylinder.ChangeHeight(_currentHeightElevator, _diameter);
- //The shader property to make the pedestal show if it is on or off.
- var amount = _currentHeightElevator / _heightElevator;
- _pedestalRenderer.materials[_indexLinkMaterial].SetFloat(_linkId, amount);
- }
- #if UNITY_EDITOR
- public void GenerateElevators()
- {
- var cylinder = GetComponent<ResizableOpenCylinder>();
- //Do checks, because a chance in diameter or height means that the cylinder needs to be regenerated.
- if (!Mathf.Approximately(cylinder.Diameter,_diameter))
- {
- cylinder.Diameter = _diameter;
- }
- if (!Mathf.Approximately(cylinder.Height, _heightElevator))
- {
- cylinder.Height = _heightElevator;
- }
- }
- #endif
- private struct AirElevatorObject
- {
- public AirElevatorObject(Rigidbody rigidbody, IAirElevatorEnabledObject airElevatorEnabledObject)
- {
- Rigidbody = rigidbody;
- CurrentClimbSpeed = 0.0f;
- //Sin start at PI, so it moves down first
- SinTime = Mathf.PI;
- AirElevatorEnabledObject = airElevatorEnabledObject;
- }
- public Rigidbody Rigidbody;
- public float CurrentClimbSpeed;
- public float SinTime;
- public IAirElevatorEnabledObject AirElevatorEnabledObject;
- }
- public interface IAirElevatorEnabledObject
- {
- void ObjectEnter();
- void ObjectLeft();
- void AirElevatorUpdate();
- float GetVerticalMovement();
- bool NeedsSpecialMovement();
- bool CanMove();
- void SpecialMovement(Vector3 movement);
- }
- }
Add Comment
Please, Sign In to add comment