Дозвольте мені перейменувати значення 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 - кастабале в 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 і 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), і якби цей виступ не був можливим, можливо, компілятор обрав би той, з відповідним тип виходу).
Дякую за бал Алекс М.