- Home /
Vector3.lerp giving me the incorrect Quaternion
So my code works properly on some containers, but not on all of them and I assume it has something to do with lerping to a negative rotation. It changes my y and z rotation on a whim it seems and I am not sure if there is a way to fix this or not or if there is some trick I am not familiar with. Any help is appreciated. I left a couple of my other attempts out in comments as well near the lerp part.
Here is the trouble object in an example gif: https://gyazo.com/d51a420c4cc909fb8d0436d0abfdf76e
This is my inspector: https://gyazo.com/2968a7ea1ae84230e0078dcf129e4e9f
This is the Heirarchy: https://gyazo.com/0624222d3559cf7b2f8afd1b921388be
Here is a gif of the code working properly (on another object in the same scene) https://gyazo.com/2bf7f8fb95688de7c44a68c66d9b3d20 inspector of object: https://gyazo.com/7a5a3c59bf9b6e9dc9c239fcb70c39d0
I have the following code: (not optimized I know gotta cache those getcomponent calls etc.)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public enum chestState
{
Moving,
Open,
Closed
};
[System.Serializable]
public struct hingedPart
{
public GameObject Pivot; //What we are rotating the lid or whatever is attached as a child to the Pivot.
public Vector3 startingRotation; //starting Rotation
public Vector3 endingRotation; //open Rotation
}
public class LiddedContainer : MonoBehaviour
{
public List<GameObject> containedObjects = new List<GameObject>();
public float openingTime;
public float closingTime;
public AudioClip OpeningSound;
public AudioClip ClosingSound;
public AudioSource asrc;
public bool used = false; //Just for triggering
public chestState curState, lastState;
private float Timer;
private float multiplier; //will store the current multiplier.
public List<hingedPart> hingedParts = new List<hingedPart>();
// Use this for initialization
void Start ()
{
lastState = chestState.Moving;
curState = chestState.Closed;
}
// Update is called once per frame
void Update ()
{
Timer += Time.deltaTime;
if(used)
{
Activate();
}
if (lastState == chestState.Open && curState == chestState.Moving)
{
multiplier = (float)(1 - (Timer / closingTime)); // 1 ---> 0
if (multiplier < 0)
{
lastState = curState;
curState = chestState.Closed;
multiplier = 0;
}
updateParts(multiplier);
}
if (lastState == chestState.Closed && curState == chestState.Moving)
{
multiplier = Timer / openingTime; //0 ---> 1
if (multiplier > 1)
{
lastState = curState;
curState = chestState.Open;
multiplier = 1;
}
updateParts(multiplier);
}
}
void updateParts(float percent)
{
for (int i = 0; i < hingedParts.Count; i++)
{
//Vector3 l = Vector3.Lerp(hingedParts[i].startingRotation, hingedParts[i].endingRotation, percent);
//hingedParts[i].Pivot.transform.rotation = Quaternion.Euler(Vector3.Lerp(hingedParts[i].startingRotation, hingedParts[i].endingRotation, percent));
hingedParts[i].Pivot.transform.eulerAngles = Vector3.Lerp(hingedParts[i].startingRotation, hingedParts[i].endingRotation, percent);
}
}
public void Activate()
{
used = false;
if(curState != chestState.Moving)
{
lastState = curState;
curState = chestState.Moving;
Timer = 0.0f;
}
}
public void OnTriggerEnter(Collider other)
{
grabbableObject grab = other.gameObject.GetComponent<grabbableObject>();
if (grab)
{
// need to add a check if the object is already in the list here...
containedObjects.Add(other.gameObject);
}
}
public void OnTriggerExit(Collider other)
{
grabbableObject grab = other.gameObject.GetComponent<grabbableObject>();
if (grab)
{
containedObjects.Remove(other.gameObject);
}
}
void openContainer()
{
for(int i = 0; i < containedObjects.Count;i++)
{
containedObjects[i].GetComponent<grabbableObject>().isGrabbed = false; //unlocks all contained objects of this container.
}
}
void closeContainer()
{
for (int i = 0; i < containedObjects.Count; i++)
{
containedObjects[i].GetComponent<grabbableObject>().isGrabbed = true; //locks all objects from being grabbed until the container is opened.
}
}
}
So much wrong there. Euler angles will not return what you think it will. Use quaternions for rotation and lerp them. Also, make containedObjects a list of grabbleObject rather than GameObject so you don't need to waste cycles looking for the component each time.
Like I said I know it isn't optimized. The thing is it is a pain to figure out what quaternion you are after it's great for precision, but it is shit in an inspector view. $$anonymous$$aybe a custom inspector with an assign angle button for start and end rotations might work still a pain.
Answer by WarmedxMints · Mar 21, 2019 at 10:23 PM
As I commented, don't use Euler angles to modify rotation. Here is a door script I posted for someone on the unity forums not too long ago. It should work for what you want to do. I would put one on each chest and call its method
using System.Collections;
using UnityEngine;
public class DoorController : MonoBehaviour
{
//What angle to rotate the door by to open it
public Vector3 RotationAmount;
//How long it will take to rotate from open to close
public float DoorRotationTime = 2f;
private Quaternion _startRot;
private Quaternion _endRot;
private Transform _transform;
private Coroutine _doorCoroutine;
private bool _open;
//Testing
private void OnGUI()
{
if(GUI.Button(new Rect(10, 10, 150, 50), "Toggle Door"))
{
ToggleDoor();
}
}
private void Start()
{
_transform = transform;
_startRot = _transform.localRotation;
_endRot = _transform.localRotation * Quaternion.Euler(RotationAmount);
}
//Call this to just toggle the door
public void ToggleDoor()
{
_open = !_open;
ToggleDoor(_open);
}
//Call this to set the door state
public void ToggleDoor(bool open)
{
if(_doorCoroutine != null)
{
StopCoroutine(_doorCoroutine);
}
_open = open;
var targetRot = _open ? _endRot : _startRot;
_doorCoroutine = StartCoroutine(RotateDoor(targetRot));
}
private IEnumerator RotateDoor(Quaternion targetRot)
{
var startRot = transform.localRotation;
var t = 0f;
while (t < 1)
{
_transform.localRotation = Quaternion.Lerp(startRot, targetRot, t);
t += Time.deltaTime / DoorRotationTime;
yield return null;
}
_transform.localRotation = targetRot;
_doorCoroutine = null;
}
}
I'm sure your code works.... probably.... I just wrote a custom inspector to dump the quaternion data for me so I can enter it in manually - which does work using quaternion.lerp(q1,q2, (0...1)). I'll mark this as correct so you get the credit for it, but I have not actually used your code.