ใน 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.position + = a; // หรือ b ฉันใช้ Unity 5.0.0f และสคริปต์ถูกแนบกับองค์ประกอบ UI (รูปภาพ) ซึ่งไม่ส่งผลกระทบต่อคอมไพเลอร์ แต่อาจเป็นข้อมูลสำคัญสำหรับคุณในการจำลองสถานการณ์
SteakOverflow

ดังนั้นพวกคุณบอกฉันว่าจะทำอย่างไร เราจะเปลี่ยนคำถามและคำตอบของคุณตามนั้นหรือเราจะเริ่มใหม่?
SteakOverflow

Vector3 + Vector2 และ Vector3 + = Vector2 จะไม่ทำงานไม่ว่าคุณจะต้องการอะไรเพราะทั้งคู่สามารถถูกแปลงเป็นปริยายและอีกอันหนึ่งและคุณจำเป็นต้องร่ายอย่างชัดเจนตามสิ่งที่คุณต้องการ Vector3 = Vector2 ทำงานเพราะไม่มีความกำกวม ฉันไม่เห็นความจำเป็นในการเปลี่ยนแปลงหรือโพสต์คำถามใหม่

ฉันกำลังจะเปลี่ยนคำถามเพราะกรณีนี้แตกต่างจากที่ฉันอธิบายเล็กน้อยซึ่งอาจทำให้คำตอบของคุณหยุดชะงัก
SteakOverflow

ไม่ต้องกังวลไม่มีอะไรแตก

คำตอบ:


12

ข้อความปัญหาเต็ม:

ข้อผิดพลาด CS0121: การโทรไม่ชัดเจนระหว่างวิธีการต่อไปนี้หรือคุณสมบัติ: UnityEngine.Vector2.operator +(UnityEngine.Vector2, UnityEngine.Vector2)' andUnityEngine.Vector3.operator + (UnityEngine.Vector3, UnityEngine.Vector3) '

ความสามัคคีจัดเตรียมวิธีในการแปลงVector3a Vector2และในทางกลับกันโดยปริยาย สิ่งนี้ทำให้เกิดความกำกวมในกรณีของคุณเนื่องจากสามารถใช้ทั้ง + ตัวดำเนินการ

โพลล์ของคุณVector2ไปอย่างชัดเจนในการดำเนินงานที่เพื่อให้คอมไพเลอร์รู้กับการใช้งานVector3UnityEngine.Vector3.operator +(UnityEngine.Vector3, UnityEngine.Vector3)

ถ้าคุณอยากรู้เอกสารไมโครซอฟท์สำหรับข้อผิดพลาดเฉพาะที่นี่


แก้ไขหลังจากแก้ไข:

Vec3 += Vec2ไม่ชัดเจนด้วยเหตุผลเดียวกันกับที่อธิบายไว้ข้างต้น ลองนึกภาพอยู่ในความเป็นจริงVec3 += Vec2 สามารถให้ผลลัพธ์ทั้งสองและเป็นคำตอบเนื่องจากการแปลงโดยนัยนั่นคือเหตุผลที่คุณต้องระบุสิ่งที่คุณต้องการVec3 = Vec3 + Vec2Vec3 + Vec2Vector2Vector3

Vec3 = Vec2ไม่คลุมเครือเพราะ Vec2 ถูกแปลงโดยนัยเป็น a Vector3และจากนั้นกำหนดให้กับ Vec3 เริ่มต้น ดังนั้นการดำเนินการทั้งหมดเป็นจริงVector3 = Vector3โดยที่คุณไม่ต้องแปลง Vec2 ไปเป็นVector3ด้วยตนเอง


ดังนั้น Unity จึงถือว่าฉันต้องการให้ x และ y ของ Vector3 ถูกกำหนดจาก x และ y ของ Vector2 ของฉันและ z ของฉันตั้งค่าเป็น 0f ขวา?
SteakOverflow

ใช่ลองนึกภาพ Vec3 = Vec2 ที่เทียบเท่ากับ Vec3 = (Vector3) Vec2 คุณไม่จำเป็นต้องร่ายด้วยตนเองเพราะมันไม่ได้เป็นอย่างอื่นนอกจากในกรณีนั้น

ใช่คำถามของฉันอาจมีชื่อว่า "ทำไมฉันไม่ต้องส่งไปที่ Vector3 เมื่อกำหนด Vector2" ฉันไม่ใช่คนที่เก่งที่สุดในการตั้งคำถามและตั้งคำถามที่สมบูรณ์แบบ: / ขอบคุณอเล็กซ์ ความอยากรู้ของฉันได้รับความพึงพอใจ (มากกว่า)
SteakOverflow

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ได้รับการประเมินครั้งแรกก่อนที่จะพิจารณา "โดยที่ผลลัพธ์จะถูกนำไปใช้" ดังนั้นคอมไพเลอร์ไม่ทราบว่าจะใช้ cast ใด - เช่น coder - เพื่อให้มันทำงานได้

หากคุณต้องการเลื่อนไปสู่ ​​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's +=ผู้ประกอบการทำหน้าที่ตามที่อธิบายไว้โดยไมโครซอฟท์ที่จะกล่าวว่า:

x += y

เทียบเท่ากับ

x = x + y

ยกเว้นว่า x ถูกประเมินเพียงครั้งเดียว ความหมายของตัวดำเนินการ + ขึ้นอยู่กับประเภทของ x และ y (นอกจากนี้สำหรับตัวถูกดำเนินการตัวเลขการต่อข้อมูลสำหรับตัวถูกดำเนินการสตริงและอื่น ๆ )

ดังนั้นเราจึงมั่นใจได้ว่าวิธีที่สองจะเรียกใช้ + operand ของ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.


+=ไม่ได้ทำงานอย่างใดอย่างหนึ่งก็ยังคงเป็น+Vector3 Vector2ดูคำตอบของฉัน

ถูกต้องโหวตแล้วของคุณจะแก้ไขของฉัน
Xavi Montero

เพิ่งแก้ไขเพื่อรวมความคิดเห็นของคุณ
Xavi Montero

transform.position + = pos2d กำลังรวบรวม พรุ่งนี้ฉันจะแม่นยำมากขึ้น (อาจเป็นเพียงข้อผิดพลาดรุ่น)
SteakOverflow

หลังจากการแก้ไขฉันหายไปตามลำดับ ... ดังนั้น ... pos3d += pos2d(ตามคำถามที่คุณแก้ไข) ล้มเหลว แต่transform.position += pos2dคอมไพล์ (ตามความคิดเห็นของคุณด้านบน) ?? จะดูแปลก ๆ เหมือนที่.positionเป็นVector3- ไม่สามารถดูได้อย่างชัดเจนว่านั่นคือสิ่งที่คุณมีความหมาย
Xavi Montero
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.