В Unity, почему добавление Vector2 и Vector3 неоднозначно, но назначение не является?

Учитывая следующие два вектора:

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

Эта строка неоднозначна:

v3 += v2; // Unity reports dimension ambiguity

, в то время как это назначение не выполняется:

v3 = v2; // Unity assigns despite different dimensions

Почему это?

10 голосов | спросил SteakOverflow 20 PMpMon, 20 Apr 2015 19:07:57 +030007Monday 2015, 19:07:57

2 ответа


11

Сообщение о полной проблеме:

  

ошибка CS0121: вызов неоднозначен между следующими методами или свойствами: UnityEngine.Vector2.operator +(UnityEngine.Vector2, UnityEngine.Vector2)' and UnityEngine.Vector3.operator + (UnityEngine.Vector3, UnityEngine.Vector3)

Unity предоставил способ неявно преобразовать Vector3 в Vector2 и наоборот. Это вызывает двусмысленность в вашем случае, потому что могут применяться оба оператора +.

Настройте Vector2 на Vector3 явно в этой операции, так что компилятор знает, как использовать UnityEngine.Vector3.operator +(UnityEngine.Vector3, UnityEngine.Vector3).

Если вам интересно, документы Microsoft для этой конкретной ошибки здесь .


Изменить после редактирования:

Vec3 += Vec2 является неоднозначным по той же причине, о которой говорилось выше. Представьте Vec3 += Vec2 на самом деле Vec3 = Vec3 + Vec2. Vec3 + Vec2 может давать как Vector2, так и Vector3 как ответ из-за неявных преобразований, поэтому вам нужно указать, что вы хотите.

Vec3 = Vec2 не является двусмысленным, поскольку Vec2 неявно преобразован в Vector3, а затем назначается начальному Vec3. Таким образом, вся операция действительно Vector3 = Vector3, без необходимости передавать Vec2 в код Vector3 вручную.

ответил 21 AMpTue, 21 Apr 2015 00:59:03 +030059Tuesday 2015, 00:59:03
3

Позвольте мне переименовать vars (для ясности):

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

Ответ

Это из-за раздела pos3d + pos2d строки. Эта часть действительно неоднозначна, а += - нет. Позвольте мне пояснить, почему один и почему другой.

Анализ 1

В этой строке

transform.position = pos3d + pos2d;

компилятор сначала пытается оценить выражение pos3d + pos2d, прежде чем продолжить, независимо от того, где будет размещен результат.

Для этого система сначала пытается найти любую публичную статическую функцию, которая добавляет Vector3 плюс Vector2, например, эту возможную подпись:

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

или, например, эту возможную подпись:

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

Тем не менее, в API нет какой-либо из этих подписей, поэтому компилятор пытается «отличить» параметры от известных подписей.

Затем компилятор находит эти две потенциальные сигнатуры:

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

Они описаны здесь: http://docs.unity3d.com/ScriptReference/Vector3-operator_add.html и здесь: http://docs.unity3d.com/ScriptReference/Vector2-operator_add.html

Итак, есть две возможности:

Так как оба литья возможны, pos2d может быть отброшен в Vector3, а pos3d - castabale в Vector2, тогда компилятор найдет возможные способы скомпилировать один и тот же исходный код (при условии, что будут созданы автоматические скрытые отливки).

Можно либо поместить pos3d в Vector2, либо продолжить вторую подпись, либо либо поместить pos2d в Vector3, либо продолжить первую подпись.

Как сначала оценивается выражение pos3d + pos2d, прежде чем принимать во внимание «где будет применен результат», тогда компилятор не знает что бы вы сделали - как кодер - как это выполнить.

Если вы хотите перейти в 3D, вы можете написать это:

transform.position = pos3d + ( Vector3 )pos2d;

и проблема исчезла, так как теперь ясно: сначала переместите pos2d в другой объект типа Vector3, затем сделайте сумму Vector3 + Vector3. При условии, что существует эта статическая подпись

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

, что он будет использоваться без какой-либо двусмысленности вообще.

Анализ 2

С другой стороны, когда вы делаете

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

нет двусмысленности: первая строка присваивает Vector3 в Vector3 (без сомнений).

Вторая строка эквивалентна

transform.position = transform.position + pos2d;

с особенностью transform.position оценивается только один раз, и поэтому этот тип учитывается, как вы можете видеть на этой странице Microsoft о +=:

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

Кроме того, он говорит: «Оператор + = нельзя перегружать напрямую, но пользовательские типы могут перегружать оператор + (см. оператор)». поэтому мы должны подумать, что код Vector3 +=, как описано в Microsoft, где говорится:

x += y
     

эквивалентно

x = x + y
     

, за исключением того, что x оценивается только один раз. Значение оператора +   зависит от типов x и y (добавление для числовых операндов,   конкатенация для строковых операндов и т. д.).

, поэтому мы можем быть уверены, что второй подход вызывает операнд + класса Vector3, который имеет подпись:

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

, поэтому нет другого способа добиться этого, чемпреобразование pos2d в Vector3 благодаря скрытому скрытому приложению, которое не может быть любой другой формы.

Надеюсь помочь!


Изменить

В Unity 5.0.1f1 Personal с помощью MonoDevelop-Unit 4.0.1, как говорит Алекс М., строки:

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

по-прежнему выполняется ошибка "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)'"

, так что действительно + = использует обе подписи

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

, несмотря на то, что уже знает «где», результат должен быть помещен (я думаю, потому что вывод Vector2 может быть спрятан до места назначения (Vector3), и если этот прилив не был возможен, возможно, компилятор мог бы выбрать один с соответствующим типом вывода).

Спасибо за точку Alex M.

ответил Xavi Montero 21 AMpTue, 21 Apr 2015 01:07:32 +030007Tuesday 2015, 01:07:32

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132