在Unity中,为什么要添加一个Vector2和一个Vector3模棱两可,但分配却不是呢?


11

给定以下两个向量:

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

这条线是模棱两可的:

v3 += v2; // Unity reports dimension ambiguity

而该任务不是:

v3 = v2; // Unity assigns despite different dimensions

为什么是这样?


因此,非常感谢Anko和Xavi Montero的出色回答。为了重现问题,我意识到我的问题应该更改。当将Vector2分配给transform.position时,事实发生了,从而transform.position = a + b; 其中a和b均为Vector2都可以正确编译,并且分配x和y!相反,当我将行更改为transform时,它不起作用。//或b我正在使用Unity 5.0.0f,并且脚本已附加到UI元素(图像),这不会影响编译器,但对于您重现场景可能是重要的信息。
SteakOverflow 2015年

所以你们告诉我该怎么办。我们应该相应地更改问题和您的答案,还是应该重新开始?
SteakOverflow 2015年

Vector3 + Vector2和Vector3 + = Vector2将永远无法工作,因为它们都可以隐式转换为另一个,并且您需要根据自己的意愿进行显式转换。Vector3 = Vector2之所以有效,是因为没有歧义。我认为不需要更改或发布新问题。

我说的是要更改问题,因为此案与我描述的情况略有不同,这可能会阻止您回答问题。
SteakOverflow 2015年

不用担心,什么都不会中断。

Answers:


12

完整的问题消息:

错误CS0121:以下方法或属性之间的调用不明确:UnityEngine.Vector2.operator +(UnityEngine.Vector2, UnityEngine.Vector2)' andUnityEngine.Vector3.operator +(UnityEngine.Vector3,UnityEngine.Vector3)'

团结提供了一种隐式转换Vector3Vector2,反之亦然。由于您可以同时使用+运算符,因此这会引起歧义。

在该操作中将您强制Vector2转换为Vector3显式,以便编译器知道使用UnityEngine.Vector3.operator +(UnityEngine.Vector3, UnityEngine.Vector3)

如果你很好奇,微软的特定错误文档是在这里


编辑后进行编辑:

Vec3 += Vec2出于与上述相同的原因,它是模棱两可的。想象一下Vec3 += Vec2事实Vec3 = Vec3 + Vec2。由于隐式转换Vec3 + Vec2可以同时产生Vector2Vector3作为答案,因此这就是为什么您必须指定所需的内容。

Vec3 = Vec2不会有歧义,因为Vec2隐式转换为a Vector3,然后分配给初始Vec3。因此,整个操作实际上Vector3 = Vector3不需要您将Vec2强制转换为Vector3手动操作。


因此,Unity假设我希望从Vector2的x和y中分配我的Vector3的x和y,并将我的z设置为0f。对?
SteakOverflow 2015年

是的,假设Vec3 = Vec2等于Vec3 =(Vector3)Vec2。您不需要手动进行转换,因为在那种情况下,它实际上不能是其他任何东西。

是的,实际上我的问题的标题可能是“分配一个Vector2时为什么不需要强制转换为Vector3”。我在提出和提出完美的问题上不是最好的:/谢谢亚历克斯。我的好奇心得到了(过度)满足。
SteakOverflow 2015年

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转换为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/zh-CN/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 PersonalMonoDevelop-Unit 4.0.1,亚历克斯M.说,该行:

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的观点。


+=也不起作用,它仍然是Vector3+ Vector2。看我的答案。

对,赞成您的,应编辑我的。
哈维·蒙特罗

刚刚编辑以合并您的评论。
哈维·蒙特罗

transform.position + = pos2d正在编译。明天我会更加精确(可能只是版本错误)
SteakOverflow

编辑后,我按顺序迷路了...所以... pos3d += pos2d(根据您编辑的问题)失败了,但是transform.position += pos2d编译了(根据您上面的评论)?似乎奇怪的.positionVector3-不能清楚地看到,如果这就是你的意思是什么。
哈维·蒙特罗
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.