Opening door script in C#
Hey there guys , here is the code i'm using. This is launched with a input getkey down and my problem is that when I am near the door and press "F" it just bulges forward a few degrees and then it stops, pressing F again makes it go back to the original position and its this forever, what is the correct way to make the animation of the rotation go through smoothly?
Thanks
{
var target = Quaternion.Euler (0, doorOpenAngle, 0);
var target1 = Quaternion.Euler (0, doorCloseAngle, 0);
Vector3 PlayerPosition = GameObject.Find ("Player").transform.position;
Vector3 DoorPosition = this.transform.position;
if(Vector3.Distance(PlayerPosition, DoorPosition) < 5f) {
if(door_Open == false) {
door_Open = true;
transform.localRotation = Quaternion.Slerp (transform.localRotation, target, Time.deltaTime * doorAnimSpeed);
}else if(door_Open == true) {
door_Open = false;
transform.localRotation = Quaternion.Slerp (transform.localRotation, target1, Time.deltaTime * doorAnimSpeed);
}
}
}
Hi, the fault is in logic - when the door is closed, you rightfully say to open it, but immediately in the next frame you say, in the else if part, to close it :-) I just figured one way to do this: Opening with a button object (assign the doors to object "door"):
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class OpenDoor : $$anonymous$$onoBehaviour
{
// Smothly open a door
float smooth = 2.0f;
float DoorOpenAngle = 90.0f;
private bool open = false;
private Vector3 defaultRot;
private Vector3 openRot;
public Transform door;
void Start()
{
defaultRot = door.eulerAngles;
openRot = new Vector3(defaultRot.x, defaultRot.y + DoorOpenAngle, defaultRot.z);
}
void On$$anonymous$$ouseDown()
{
open = !open;
}
void Update()
{
Debug.Log(open);
if (open)
{
//Open door
door.eulerAngles = Vector3.Slerp(door.eulerAngles, openRot, Time.deltaTime * smooth);
}
else
{
//Close door
door.eulerAngles = Vector3.Slerp(door.eulerAngles, defaultRot, Time.deltaTime * smooth);
}
}
}
Answer by zharik86 · Feb 08, 2015 at 07:22 PM
I think, you must change you logic for open door. For example, in your code you press key and first frame you open door on same degree and change status as "open". In second frame you close door, and change status as "close", and etc. See simple example below write (write on CSharp):
public float doorOpenAngle = 90.0f;
public float doorCloseAngle = 0.0f;
public float doorAnimSpeed = 2.0f;
private Quaternion doorOpen = Quaternion.identity;
private Quaternion doorClose = Quaternion.identity;
private Transform playerTrans = null;
public bool doorStatus = false; //false is close, true is open
private bool doorGo = false; //for Coroutine, when start only one
void Start() {
doorStatus = false; //door is open, maybe change
//Initialization your quaternions
doorOpen = Quaternion.Euler (0, doorOpenAngle, 0);
doorClose = Quaternion.Euler (0, doorCloseAngle, 0);
//Find only one time your player and get him reference
playerTrans = GameObject.Find ("Player").transform;
}
void Update() {
//If press F key on keyboard
if (Input.GetKeyDown(KeyCode.F) && !doorGo) {
//Calculate distance between player and door
if (Vector3.Distance(playerTrans.position, this.transform.position) < 5f) {
if (doorStatus) { //close door
StartCoroutine(this.moveDoor(doorClose));
} else { //open door
StartCoroutine(this.moveDoor(doorOpen));
}
}
}
}
public IEnumerator moveDoor(Quaternion dest) {
doorGo = true;
//Check if close/open, if angle less 4 degree, or use another value more 0
while (Quaternion.Angle(transform.localRotation, dest) > 4.0f) {
transform.localRotation = Quaternion.Slerp(transform.localRotation, dest, Time.deltaTime * doorAnimSpeed);
//UPDATE 1: add yield
yield return null;
}
//Change door status
doorStatus = !doorStatus;
doorGo = false;
//UPDATE 1: add yield
yield return null;
}
But maybe, better use Animation Component and create animation for door or use only one angle without quaternions. Desion more. I hope that it will help you.
A clean script with your code returns me this , now im not really used to quaternions in general so i have really no idea how to use them properly... I would have guessed it would be easy just to rotate the Y but i would guess not , have any idea how to fix that?
Assets/Scripts/door.cs(40,28): error CS0161: `door.moveDoor(UnityEngine.Quaternion)': not all code paths return a value
@Gascon Oh, sorry, in Coroutine must add yield return. I update my answer. If you want create rotate door, sing only one y-angle and you need help, just write me.
Pretty neat works like a charm, now thats its working i feel more at ease to tweak it to my likings , Thanks!
Hey, i am also trying to get a decent door script. I tried your example @zharik86. But when i play it says
"NullReferenceException: Object reference not set to an instance of an object OpenDoorBasic.Update () (at Assets/OpenDoorBasic.cs:30)"
So what am i doing wrong? It's attacked to the Hinge of the main door.
@PandoWooSetti rename your first person controller or third person controller GameObject to "Player". This should fix your problem.
Answer by Johnz1234 · Feb 08, 2015 at 07:37 PM
https://www.youtube.com/watch?v=vfL7kQeZtic here is a tutorail video :D hope it helps
Answer by holyfot · Oct 07, 2020 at 09:44 AM
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
}
im testing this, but door start rotating and never stop xD ok, i found the problem, instead of check rotation.z i need to check the rotation axis used. now works, thanks for sharing