2011-12-10 15 views
6

Il mio problema è che voglio essere in grado di ruotare un cilindro 9 volte. 360/9 è 40 quindi tutto quello che dovrei fare è ruotare di 40 gradi 9 volte. Questo non funziona comunque come quando ruoto il cilindro per la prima volta invece di 40 gradi ruota di 39,99 gradi. Questo succede anche ad altre rotazioni.Rotazione dell'oggetto Unità che ruota al valore errato

Sto ruotando facendo questo.

if(Input.GetKeyUp("i")) 
     transform.GetChild(m_Section).Rotate(0,40.0f,0); 

Ho unità versione 3.4 non è professionale e sto codificando in C#.

Qualsiasi aiuto apprezzato come ho appena iniziato a provare a imparare l'unità.

risposta

1

Unity3D memorizza le rotazioni in una rappresentazione matematica piuttosto astratta denominata quaternion. La trasformazione da e verso gli angoli di Eulero (ciò che si vede nell'editor di Unity) comporta una cascata di funzioni trigonometriche e quindi è soggetta a errori di arrotondamento, specialmente per il tipo di float semplice.

Per aggirare questo problema nel proprio caso, si consiglia di archiviare l'oggetto Quaternion iniziale prima di iniziare a ruotare e impostarlo alla fine del processo. Qualche pseudo-codice:

public class RotationController : MonoBehaviour { 
    Quaternion rotationAtStart; 
    int numOfRotations = 0; 

    void rotate() { 
     numOfRotations++; 
     if (numOfRotations == 1) { 
      rotationAtStart = transform.rotation; 
     } else if (numOfRotations < 9) { 
      transform.Rotate (new Vector3 (0,40.0f,0)); 
     } else if (numOfRotations == 9) { 
      transform.rotation = rotationAtStart; 
     } 
    } 
    void Update() { 
     if (numOfRotations < 9) { 
      rotate(); 
     } 
    } 
} 

La particolare situazione a 360 ° rende questo approccio stabile. Per meno di 360 ° devi vivere con piccoli errori di arrotondamento. In questo caso, suggerirei di calcolare il quaternione di riferimento Quaternion.RotateTowards e impostarlo nell'ultimo passaggio analogico al caso 360.

Un'altra cosa utile per voi sono Animations. È possibile definire un'animazione come graduale o con passaggi discreti e chiamare semplicemente GameObject.animation.Play("MyRotation") se si preme "i". Usa un AnimationEvent alla fine per essere informato quando l'animazione è terminata.

E infine Mathf contiene una funzione Approximately che si occupa del problema dell'imprecisione in virgola mobile.

+0

Se ho usato un'animazione come da te suggerito vorrei che cambiare gli oggetti asse locale o se è solo ruotare l'oggetto? – Dave

+0

Si animano i membri della trasformazione dell'oggetto di gioco. transform.rotation è negli angoli di Eulero – Kay

+0

Grazie per il vostro aiuto. È più un modo per aggirare il problema che una soluzione. Non sarei in grado di dire se (transform.eulerAngles.y == 40.0f) perché sebbene ruoti verso un risultato più accurato ci sono ancora degli errori. Non ho ancora provato il suggerimento di animazione, ma lo farò solo ora. – Dave

0

Date un'occhiata alla risposta di Kungfoomanin this post, ha descripes il problema con la rotazione oltre 90 gradi o 90 gradi, così come 270 gradi. Fornisce un'estensione che calcola sempre il pendente corretto dello Quaternion per il valore che si desidera impostare. Date un'occhiata qui:

using UnityEngine; 
using System.Collections; 

public class ExtensionVector3 : MonoBehaviour { 

    public static float CalculateEulerSafeX(float x){ 
     if(x > -90 && x <= 90){ 
      return x; 
     } 

     if(x > 0){ 
      x -= 180; 
     } else { 
      x += 180; 
     } 
     return x; 
    } 

    public static Vector3 EulerSafeX(Vector3 eulerAngles){ 
     eulerAngles.x = CalculateEulerSafeX(eulerAngles.x); 
     return eulerAngles; 
    } 
} 

E ho usato in questo modo:

Quaternion newQuat = m_directionalLight.transform.rotation; 
Vector3 nL = new Vector3(ExtensionVector3.CalculateEulerSafeX(xNewValueLight), 
         0, 
         0); 
newQuat.eulerAngles = nL; 

m_directionalLight.transform.rotation = 
    Quaternion.Lerp(m_directionalLight.transform.rotation, 
        newQuat, 
        Time.deltaTime); 
Problemi correlati