Unity Transform случайное вращение между определенными углами - PullRequest
2 голосов
/ 11 марта 2019

Хорошо, мне нужны преобразования, разделенные на определенные группы, случайно вращающиеся между заданными углами только на локальной оси x .Я не понимаю, Quaternions и transform.localEulerAngles, кажется, работают только с углами в диапазоне <0, 360>.Все мои угловые границы находятся в <-180, 180>.Кажется, все работает какое-то время, а затем повороты вращаются вокруг 90 и -90 по какой-то причине ...

Вот код:

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]);            
            }
        }
    }
}

1 Ответ

1 голос
/ 12 марта 2019

Документация по localEulerAngles гласит, что их не следует увеличивать и вместо них следует использовать Transform.Rotate. Причиной этого является то, что Unity использует кватернионы внутри себя и по запросу конвертирует в углы Эйлера. Вы не должны полагаться на localEulerAngles, чтобы возвращать согласованные значения, поскольку они не являются базовым представлением. На самом деле localEulerAngles часто не совпадает с показанным в инспекторе.

localEulerAngles имеет тенденцию переключаться между двумя различными представлениями вращения на отметке + -90 градусов. Вот почему вращение застревает там.

Вместо этого я бы предложил сохранить текущее вращение в ваших параметрах, а затем обновить его соответствующим образом. Таким образом, вы получаете значение, на которое можете положиться, и можете использовать любой диапазон углов, который пожелаете.

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]);
            }
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...