In Unity, perché l'aggiunta di un Vector2 e un Vector3 è ambigua ma l'assegnazione non lo è?


11

Dati i seguenti due vettori:

Vector3 v3 = Vector3.one;
Vector2 v2 = Vector2.one;

Questa linea è ambigua:

v3 += v2; // Unity reports dimension ambiguity

mentre questo incarico non è:

v3 = v2; // Unity assigns despite different dimensions

Perchè è questo?


Quindi, grazie mille ad Anko e Xavi Montero per le ottime risposte. Cercando di riprodurre il problema mi sono reso conto che la mia domanda dovrebbe essere cambiata. Il fatto sta accadendo quando si assegna un Vector2 a transform.position in modo che transform.position = a + b; dove ENTRAMBE aeb sono Vector2 compilati correttamente e assegna xey! Invece, non funziona quando cambio la linea in transform.position + = a; // oppure b Sto utilizzando Unity 5.0.0f e lo script è collegato a un elemento dell'interfaccia utente (Immagine) che non influisce sul compilatore ma potrebbe essere un'informazione importante per la riproduzione dello scenario.
SteakOverflow

Quindi ragazzi mi dite cosa devo fare. Cambiamo la domanda e le tue risposte di conseguenza o ne inizieremo una nuova?
SteakOverflow

Vector3 + Vector2 e Vector3 + = Vector2 non funzioneranno mai, qualunque cosa tu voglia, perché entrambi possono essere convertiti implicitamente nell'altro ed è necessario eseguire il cast esplicito in base a ciò che vuoi fare. Vector3 = Vector2 funziona perché non c'è ambiguità. Non vedo la necessità di modificare o pubblicare una nuova domanda.

Sto dicendo di cambiare la domanda perché il caso è leggermente diverso da quello che ho descritto, il che potrebbe frenare il flusso della tua risposta.
SteakOverflow

No, non preoccuparti, non si rompe nulla.

Risposte:


12

Messaggio di rilascio completo:

errore CS0121: la chiamata è ambigua tra i seguenti metodi o proprietà: UnityEngine.Vector2.operator +(UnityEngine.Vector2, UnityEngine.Vector2)' andUnityEngine.Vector3.operator + (UnityEngine.Vector3, UnityEngine.Vector3) '

Unity ha fornito un modo per convertire implicitamente a Vector3in Vector2e viceversa. Ciò provoca un'ambiguità nel tuo caso perché è possibile applicare entrambi gli operatori +.

Getta il tuo Vector2a un Vector3esplicito in quell'operazione, in modo che il compilatore sa usare UnityEngine.Vector3.operator +(UnityEngine.Vector3, UnityEngine.Vector3).

Se sei curioso, i documenti di Microsoft per quello specifico errore sono qui .


Modifica dopo la modifica:

Vec3 += Vec2è ambiguo per lo stesso motivo sopra descritto. Immagina di Vec3 += Vec2essere in effetti Vec3 = Vec3 + Vec2. Vec3 + Vec2può produrre sia Vector2e Vector3come la risposta a causa di conversioni implicite, è per questo che è necessario specificare cosa si desidera.

Vec3 = Vec2non è ambiguo perché Vec2 viene convertito implicitamente in a Vector3e quindi assegnato a Vec3 iniziale. Quindi l'intera operazione è davvero Vector3 = Vector3senza che tu debba trasmettere Vector3manualmente Vec2 .


Quindi Unity presume che io voglia che il mio Vector3 xey sia assegnato dal mio Vector2 xey e che la mia z sia impostata su 0f. Giusto?
SteakOverflow

Sì, immagina Vec3 = Vec2 equivalente a Vec3 = (Vector3) Vec2. Non è necessario eseguire il cast manualmente perché in realtà non può essere nient'altro che quello.

Sì, in realtà la mia domanda potrebbe essere intitolata "Perché non ho bisogno di trasmettere a Vector3 quando assegno un Vector2". Non sono il migliore nel nominare e realizzare domande perfette: / Grazie Alex. La mia curiosità è stata (finita) soddisfatta.
SteakOverflow

3

Vorrei rinominare i var (per chiarezza):

Vector3 pos3d = new Vector3 (1f, 2f, 3f);
Vector2 pos2d = new Vector2 (1f, 2f);

Risposta

È a causa della sezione pos3d + pos2ddella linea. Questa parte è davvero ambigua mentre non lo +=è. Vorrei chiarire perché l'uno e perché l'altro.

Analisi 1

In questa linea

transform.position = pos3d + pos2d;

il compilatore tenta innanzitutto di valutare l'espressione pos3d + pos2dprima di procedere, indipendentemente da dove verrà posizionato il risultato.

Per fare ciò, il sistema tenta innanzitutto di trovare qualsiasi funzione statica pubblica che aggiunge un Vector3 più un Vector2, ad esempio questa possibile firma:

public static Vector3 operator +(Vector3 a, Vector2 b);

o per esempio questa possibile firma:

public static Vector2 operator +(Vector3 a, Vector2 b);

Tuttavia non c'è nessuna di quelle firme nell'API, quindi il compilatore prova a "trasmettere" i parametri a firme conosciute.

Quindi il compilatore trova queste due potenziali firme:

public static Vector3 operator +(Vector3 a, Vector3 b);
public static Vector2 operator +(Vector2 a, Vector2 b);

Questi sono documentati qui: http://docs.unity3d.com/ScriptReference/Vector3-operator_add.html e qui: http://docs.unity3d.com/ScriptReference/Vector2-operator_add.html

Quindi ci sono due possibilità:

Quindi, poiché sono possibili entrambi i casting, pos2d può essere lanciato su un Vector3 e pos3d è castabale in un Vector2, il compilatore trova quindi i modi possibili per compilare lo stesso codice sorgente (a condizione che siano presenti casting nascosti automatici).

È possibile sia lanciare pos3d in Vector2 e procedere con la seconda firma, sia lanciare pos2d in Vector3 e procedere con la prima firma.

Dato che l'espressione pos3d + pos2dviene valutata per prima, prima di prendere in considerazione "dove verrà applicato il risultato", il compilatore non sa quale cast vorresti -come programmatore-vorrebbe che eseguisse.

Se vuoi passare al 3D, puoi scrivere questo:

transform.position = pos3d + ( Vector3 )pos2d;

e il problema è scomparso, come ora è chiaro: prima sposta pos2d in un altro oggetto di tipo Vector3, quindi fai la somma di Vector3 + Vector3. A condizione che sia presente questa firma statica

public static Vector3 operator +(Vector3 a, Vector3 b);

disponibile, quello verrà usato senza alcuna ambiguità.

Analisi 2

D'altra parte, quando lo fai

transform.position = pos3d;
transform.position += pos2d; 

non c'è ambiguità: la prima riga assegna un Vector3 in un Vector3 (senza dubbio).

La seconda riga è equivalente a

transform.position = transform.position + pos2d;

con la particolarità, il file transform.position viene valutato una sola volta, quindi il tipo viene preso in considerazione, come puoi vedere in questa pagina Microsoft +=sull'operatore:

https://msdn.microsoft.com/en-us/library/sa7629ew.aspx

Inoltre dice "L'operatore + = non può essere sovraccaricato direttamente, ma i tipi definiti dall'utente possono sovraccaricare l'operatore + (vedi operatore)." quindi dovremmo pensare che il Vector3's +=operatore agisce come descritto da Microsoft in cui si dice:

x += y

è equivalente a

x = x + y

tranne che x viene valutato solo una volta. Il significato dell'operatore + dipende dai tipi di xey (aggiunta per operandi numerici, concatenazione per operandi stringa e così via).

quindi possiamo essere certi che il secondo approccio invoca l'operando + della Vector3classe, che ha la firma:

public static Vector3 operator +(Vector3 a, Vector3 b);

quindi non c'è altro modo per raggiungere questo obiettivo se non quello di convertire pos2d in un Vector3 grazie a un cast implicito nascosto che non può essere di qualsiasi altra forma.

Spero di aiutare !!


modificare

In Unity 5.0.1f1 Personalcon MonoDevelop-Unit 4.0.1, come dice Alex M., le linee:

transform.position = pos3d;
transform.position += pos2d;

ancora lanciare l'errore "Assets/Scripts/CubeScript.cs(15,27): error CS0121: The call is ambiguous between the following methods or properties: 'UnityEngine.Vector2.operator +(UnityEngine.Vector2, UnityEngine.Vector2)' and 'UnityEngine.Vector3.operator +(UnityEngine.Vector3, UnityEngine.Vector3)'"

quindi davvero + = utilizza entrambe le firme

public static Vector3 operator +(Vector3 a, Vector3 b);
public static Vector2 operator +(Vector2 a, Vector2 b);

indipendentemente dal fatto di sapere già "dove" deve essere posizionato il risultato (immagino perché l'output di un Vector2 è castable alla destinazione (Vector3) e se quel cast non fosse possibile probabilmente, forse, il compilatore sceglierebbe quello con il giusto tipo di uscita).

Grazie per il punto Alex M.


+=non funziona neanche, è ancora un Vector3+ Vector2. Vedi la mia risposta

Giusto, votato tuo, modificherà il mio.
Xavi Montero,

Ho appena modificato per includere il tuo commento.
Xavi Montero,

transform.position + = pos2d sta compilando. Domani sarò più preciso (potrebbe essere solo un bug di versione)
SteakOverflow

Dopo le modifiche mi sono perso nella sequenza ... quindi ... pos3d += pos2d(come da tua domanda modificata) fallisce ma si transform.position += pos2dcompila (come da tuo commento sopra) ?? Sembrerebbe strano come .positionè Vector3- non può chiaramente vedere se è quello che si sta significato.
Xavi Montero,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.