Reputation: 110
Ok, I need the transforms divided into specific groups randomly rotating between given angles only on the local x axis. I don't understand Quaternions
and transform.localEulerAngles
seems to only work with angles in <0, 360> range. All my angle boundaries are in <-180, 180>.
It all seems to work for a while and then the rotations get stuck around 90 and -90 for some reason...
Here's the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//this is the editor interface into which I input the demands
[System.Serializable]
struct Transform_Angle_VP
{
public float angle1;
public float angle2;
public float max_speed;
public Transform[] transforms;
}
public class LeftCollectionDarkMovement : MonoBehaviour {
public float speed_change;
[SerializeField] Transform_Angle_VP[] transform_Angles;
Dictionary<Transform, float[]> TransAngs = new Dictionary<Transform, float[]>();
// Use this for initialization
void Awake()
{
//rewrite transforms and their angle limits into dictionary to keep seperate track of each
foreach (Transform_Angle_VP T_A_VP in transform_Angles)
{
foreach (Transform trans in T_A_VP.transforms)
{
///float[0:min_angle, 1:max_angle, 2:target_angle, 3:current_speed, 4:target_speed, 5:max_speed]
TransAngs[trans] = new float[] { T_A_VP.angle1, T_A_VP.angle2, Random.Range(T_A_VP.angle1, T_A_VP.angle2), 0, Random.Range(T_A_VP.max_speed / 5, T_A_VP.max_speed), T_A_VP.max_speed };
}
}
}
// Update is called once per frame
void Update () {
float dt = Time.deltaTime;
foreach(Transform trans in TransAngs.Keys)
{
var parameters = TransAngs[trans];
//move speed towards target
parameters[3] = Mathf.Min(parameters[4], parameters[3] + dt * speed_change);
//translate localEulerAngles to negatives if needed
var rot_x = trans.localEulerAngles.x;
if (rot_x > 180) rot_x -= 360;
//calculate rotation of target
var target_rot = Mathf.MoveTowards(rot_x, parameters[2], parameters[3] * dt);
target_rot -= rot_x;
//apply rotation
trans.localEulerAngles += new Vector3(target_rot, 0, 0);
//if at target : choose new target and speed
rot_x = trans.localEulerAngles.x;
if (rot_x > 180) rot_x -= 360;
if (Mathf.Abs(rot_x - parameters[2]) < 1)
{
parameters[2] = Random.Range(parameters[0], parameters[1]);
parameters[4] = Random.Range(parameters[5]/5, parameters[5]);
}
}
}
}
Upvotes: 2
Views: 1691
Reputation: 561
The documentation on localEulerAngles states that they should not be incremented and that Transform.Rotate
should be used instead. The reason for this that Unity uses quaternions internally and converts to Euler angles on request. You should not rely on localEulerAngles
to return consistent values as they are not the underlying representation. In fact localEulerAngles
is often not equal to what is shown in the inspector.
localEulerAngles
tends to switch between two different representations of the rotation at the +-90 degree mark. This is why the rotation gets stuck there.
Instead i would suggest storing the current rotation in your parameters and then update it accordingly. This way you have a value you can rely on and can use any range of angles you desire.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//this is the editor interface into which I input the demands
[System.Serializable]
struct Transform_Angle_VP
{
public float angle1;
public float angle2;
public float max_speed;
public Transform[] transforms;
}
public class LeftCollectionDarkMovement : MonoBehaviour
{
public float speed_change;
[SerializeField] Transform_Angle_VP[] transform_Angles;
Dictionary<Transform, float[]> TransAngs = new Dictionary<Transform, float[]>();
// Use this for initialization
void Awake()
{
//rewrite transforms and their angle limits into dictionary to keep seperate track of each
foreach (Transform_Angle_VP T_A_VP in transform_Angles)
{
foreach (Transform trans in T_A_VP.transforms)
{
///float[0:min_angle, 1:max_angle, 2:target_angle, 3:current_speed, 4:target_speed, 5:max_speed, 6: current_rotation]
TransAngs[trans] = new float[] { T_A_VP.angle1, T_A_VP.angle2, Random.Range(T_A_VP.angle1, T_A_VP.angle2), 0, Random.Range(T_A_VP.max_speed / 5, T_A_VP.max_speed), T_A_VP.max_speed, 0 };
}
}
}
// Update is called once per frame
void Update()
{
float dt = Time.deltaTime;
foreach (Transform trans in TransAngs.Keys)
{
var parameters = TransAngs[trans];
//move speed towards target
parameters[3] = Mathf.Min(parameters[4], parameters[3] + dt * speed_change);
//calculate rotation of target
var target_rot = Mathf.MoveTowards(parameters[6], parameters[2], parameters[3] * dt);
target_rot -= parameters[6];
//apply rotation
trans.Rotate(Vector3.right, target_rot, Space.Self);
parameters[6] += target_rot;
if (Mathf.Abs(parameters[6] - parameters[2]) < 1)
{
parameters[2] = Random.Range(parameters[0], parameters[1]);
parameters[4] = Random.Range(parameters[5] / 5, parameters[5]);
}
}
}
}
Upvotes: 1