Here is my perfect door script:
//Perfect Door/Chest/DrawBridge Animation Script
//Author: HolyFot
//License: CC0
using UnityEngine;
using System.Collections;
public class Door : MonoBehaviour
{
[SerializeField] public GameObject doorObj;
[SerializeField] public GameObject pivot;
[SerializeField] public bool isBackwards = false;
[SerializeField] private float startY = 0f;
[SerializeField] public float openSpeed = 100f;
[SerializeField] public float targetAngle = 90f;
[SerializeField] public AnimationCurve speedCurve = new AnimationCurve(new Keyframe(0, 0.3f), new Keyframe(0.1f, 0.3f), new Keyframe(0.5f, 1f), new Keyframe(0.9f, 0.3f), new Keyframe(1f, 0.3f));
[SerializeField] public DoorOpenMethod doorOpenType;
public bool isOpen = false;
public bool isTesting = false;
private bool isOpening = false;
private bool isClosing = false;
private Vector3 startPos;
void Awake()
{
if (doorObj == null)
{
Debug.LogWarning("Door Object not set!");
return;
}
if (pivot == null)
{
Debug.LogWarning("Pivot Object not set!");
return;
}
if (doorOpenType == DoorOpenMethod.X_Mode)
{
startY = doorObj.transform.localRotation.eulerAngles.x;
if (isTesting)
Debug.Log("start X: " + startY.ToString());
}
else if (doorOpenType == DoorOpenMethod.Z_Mode)
{
startY = doorObj.transform.localRotation.eulerAngles.z;
if (isTesting)
Debug.Log("start Z: " + startY.ToString());
}
else if (doorOpenType == DoorOpenMethod.Y_Mode)
{
startY = doorObj.transform.localRotation.eulerAngles.y;
if (isTesting)
Debug.Log("start Y: " + startY.ToString());
}
startPos = doorObj.transform.localPosition;
}
void Update()
{
if (isTesting)
{
if (Input.GetKeyDown(KeyCode.F))
{
ToggleDoor();
}
}
}
public void ToggleDoor()
{
if (isOpen)
CloseDoor();
else
OpenDoor();
}
public void OpenDoor()
{
StopDoorAnims();
if (!isBackwards)
StartCoroutine("ForwardDoor2");
else
StartCoroutine("ReverseDoor2");
isOpen = true;
}
public void CloseDoor()
{
StopDoorAnims();
if (!isBackwards)
StartCoroutine("ReverseDoor2");
else
StartCoroutine("ForwardDoor2");
isOpen = false;
}
public void StopDoorAnims()
{
//if (isOpening)
StopCoroutine("ForwardDoor2");
//if (isClosing)
StopCoroutine("ReverseDoor2");
}
private IEnumerator ForwardDoor2()
{
if (doorOpenType == DoorOpenMethod.X_Mode)
{
while (doorObj.transform.localRotation.eulerAngles.x < startY + targetAngle - 1f)
{
float calcSpeed = CalcSpeedRamp2(doorObj.transform.localRotation.eulerAngles.x, startY, startY + targetAngle);
doorObj.transform.RotateAround(pivot.transform.position, Vector3.right, calcSpeed * Time.deltaTime);
if (isTesting)
Debug.Log("Opening.. X: " + doorObj.transform.localRotation.eulerAngles.x.ToString("0.000"));
isOpening = true;
yield return null;
}
doorObj.transform.localEulerAngles = new Vector3(targetAngle, doorObj.transform.localEulerAngles.y, doorObj.transform.localEulerAngles.z);
}
else if (doorOpenType == DoorOpenMethod.Z_Mode)
{
while (doorObj.transform.localRotation.eulerAngles.z < startY + targetAngle - 1f)
{
float calcSpeed = CalcSpeedRamp2(doorObj.transform.localRotation.eulerAngles.z, startY, startY + targetAngle);
doorObj.transform.RotateAround(pivot.transform.position, Vector3.up, calcSpeed * Time.deltaTime);
if (isTesting)
Debug.Log("Opening.. Z: " + doorObj.transform.localRotation.eulerAngles.z.ToString("0.000"));
isOpening = true;
yield return null;
}
doorObj.transform.localRotation = Quaternion.Euler(doorObj.transform.localRotation.eulerAngles.x, doorObj.transform.localRotation.eulerAngles.y, targetAngle);
}
else if (doorOpenType == DoorOpenMethod.Y_Mode) //Rotate around Y
{
while (doorObj.transform.localRotation.eulerAngles.y < startY + targetAngle - 1f)
{
float calcSpeed = CalcSpeedRamp2(doorObj.transform.localRotation.eulerAngles.y, startY, startY + targetAngle);
doorObj.transform.RotateAround(pivot.transform.position, Vector3.left, calcSpeed * Time.deltaTime);
if (isTesting)
Debug.Log("Opening.. Y: " + doorObj.transform.localRotation.eulerAngles.y.ToString("0.000"));
isOpening = true;
yield return null;
}
doorObj.transform.localEulerAngles = new Vector3(doorObj.transform.localEulerAngles.x, targetAngle, doorObj.transform.localEulerAngles.z);
}
isOpening = false;
}
private IEnumerator ReverseDoor2()
{
if (doorOpenType == DoorOpenMethod.X_Mode)
{
while (doorObj.transform.localRotation.eulerAngles.x > startY && doorObj.transform.localRotation.eulerAngles.x < targetAngle + 1f)
{
float calcSpeed = CalcSpeedRamp2(doorObj.transform.localRotation.eulerAngles.x, startY, startY + targetAngle);
doorObj.transform.RotateAround(pivot.transform.position, Vector3.right, -1 * calcSpeed * Time.deltaTime);
if (isTesting)
Debug.Log("Close door X: " + doorObj.transform.localRotation.eulerAngles.x.ToString("0.000"));
isClosing = true;
yield return null;
}
doorObj.transform.localEulerAngles = new Vector3(startY, doorObj.transform.localEulerAngles.y, doorObj.transform.localEulerAngles.z);
doorObj.transform.localPosition = startPos;
}
else if (doorOpenType == DoorOpenMethod.Z_Mode)
{
while (doorObj.transform.localRotation.eulerAngles.z > startY && doorObj.transform.localRotation.eulerAngles.z < targetAngle + 1f)
{
float calcSpeed = CalcSpeedRamp2(doorObj.transform.localRotation.eulerAngles.z, startY, startY + targetAngle);
doorObj.transform.RotateAround(pivot.transform.position, Vector3.up, -1 * calcSpeed * Time.deltaTime);
if (isTesting)
Debug.Log("Close door Z: " + doorObj.transform.localRotation.eulerAngles.z.ToString("0.000"));
isClosing = true;
yield return null;
}
doorObj.transform.localEulerAngles = new Vector3(doorObj.transform.localEulerAngles.x, doorObj.transform.localEulerAngles.y, startY);
doorObj.transform.localPosition = startPos;
}
else if (doorOpenType == DoorOpenMethod.Y_Mode)
{
while (doorObj.transform.localRotation.eulerAngles.y > startY && doorObj.transform.localRotation.eulerAngles.y < targetAngle + 1f)
{
float calcSpeed = CalcSpeedRamp2(doorObj.transform.localRotation.eulerAngles.y, startY, startY + targetAngle);
doorObj.transform.RotateAround(pivot.transform.position, Vector3.left, -1 * calcSpeed * Time.deltaTime);
if (isTesting)
Debug.Log("Close door Y: " + doorObj.transform.localRotation.eulerAngles.y.ToString("0.000"));
isClosing = true;
yield return null;
}
doorObj.transform.eulerAngles = new Vector3(doorObj.transform.rotation.x, startY, doorObj.transform.rotation.z);
doorObj.transform.localPosition = startPos;
}
isClosing = false;
}
private float CalcSpeedRamp(float value, float min, float max)
{
float curr = 1f;
float percent = Mathf.Abs(value) / Mathf.Abs(max - min);
if (percent < 0.3f) //30% speed up
curr = percent * 10f * openSpeed;
else if (percent > 0.7f) //70% slow down
curr = (1f - percent) * 10f * openSpeed; //0.3, 0.2, 0.15, 0.1, 0
else
curr = openSpeed; //Regular Speed
if (curr <= 5f) //1% speed safety
curr = openSpeed * 0.01f;
return curr;
}
private float CalcSpeedRamp2(float value, float min, float max)
{
float curr = 1f;
float percent = Mathf.Abs(value) / Mathf.Abs(max - min);
curr = openSpeed * speedCurve.Evaluate(percent);
return curr;
}
}
public enum DoorOpenMethod
{
Z_Mode,
Y_Mode,
X_Mode
}