+= is ambiguous on operands of type Vector2 or Vector3

I am getting the exception += is ambiguous on operands of type Vector2 or Vector3. Why is that?

Transform transObj = new Transform();
transObj.position += Vector2.up*2;

This is essentially the same as: t.position = t.position + Vector2.up * 2; where the types in play are <Vector3> = <Vector3> + <Vector2>
There are implicit conversions available to the compiler, Vector3 to Vector2 (z is discarded) and Vector2 to Vector3 (z is 0). The compiler doesn’t prioritize either implicit conversion, so it’s ambiguous whether you want the expression to be evaluated using Vector3 operands or Vector2 operands. You need to fix this by deciding which type you want to go with, then cast the operand which is not of that type to the desired type, e.g. if you wanted to do Vector3 addition you would do t.position + (Vector3)(Vector2.up * 2). In this case, since you’re using a compound assignment (+=), you would have no choice but to change Vector2.up * 2 to (Vector3)(Vector2.up * 2), or more succinctly just use Vector3.up * 2.

2 Likes

I am working on a 2D project. Isn’t the transform class the only way to get the position, scale and rotation of the object?
Also, I want Vector2.
I tried
transObj.position = (Vector2)transObj + (Vector2.up2);, and I got cannot convert UnityEngine.Transform to UnityEngine.Vector2.
I also tried
transObj.position = transObj + (Vector3.up
2);
but I got + cannot be applied to Transform and Vector3.
Shouldn’t this be viable since they both have xyz?
How do move an object with Vector2?

Even in a 2D project all position coordinates in Unity are 3D. For positions you want to be dealing with Vector3 as all game object positions are technically in 3d.

A UnityEngine.Transform isn’t a Vector3. You want the Transform.position property of a transform in order to add other Vector3 values to it.

Ergo:

transObj.position = transObj.position + (Vector3.up * 2);
1 Like

then what is the use of Vector2 then?
Also, your suggestion worked, but I got the exception Transform() is inaccessible due to access level.
But I gave it public and placed it at the enclosing scope of the class. Shouldn’t all functions have access to it since it is in the class enclosing scope?
public Transform transObj = new Transform();

For any situation where a third dimension is not needed. A lot of the 2D specific API will take a Vector2, such Rigidbody2D.AddForce. You would use it for general 2d calculations as well. Just all game object positions are in 3D.

Also side note:

You should never instantiate a component via new().

3 Likes

To add on, (by this I mean add words, I don’t know if it adds clarity but I hope so :p), 2D things piggyback on the Transform component, which is only capable of storing 3-dimensional position. There is also technically RectTransform which uses 2D coordinates, but this is specifically used for UI development with UGUI, and is derived from Transform anyway so it inherits the underlying 3-dimensional coordinates anyway.

There’s an example in the “Ruby’s Adventure” Unity Learn project that shows modifying the Transform in a 2D style project. This shows an alternative way to do this, which is to use a Vector2 local variable as an intermediary when working with an object’s position.
The original code is:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RubyController : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
       
    }

    // Update is called once per frame
    void Update()
    {
        Vector2 position = transform.position;
        position.x = position.x + 0.1f;
        transform.position = position;
    }
}

In your case, it would be something like this:

Vector2 position = transObj.position;
transObj.position = position + Vector2.up * 2;

Here, since the local variable position is itself a Vector2, the compiler has no trouble deciding how to add the two expressions together as they’re Vector2, for which the binary addition operator is defined and requires no implicit conversions, meaning it’s the best candidate. That expression is then implicitly converted to Vector3 for assignment to Transform.position using the implicit Vector2 to Vector3 casting operator.

The point here is that Transform.position is a Vector3 property, and while it is normal / expected to use Vector2 for 2D projects, you should be mindful of the fact that the underlying position will always be Vector3, and decide where you want to hand-off things between Vector2 and Vector3 variables. You can choose to use a local Vector2 variable like Vector2 pos = t.position (uses implicit cast), or cast transform.position to Vector2 like (Vector2)t.position (explicit cast) to add / subtract another Vector2.

1 Like

Also, your suggestion worked, but I got the exception Transform() is inaccessible due to access level.
But I gave it public and placed it at the enclosing scope of the class. Shouldn’t all functions have access to it since it is in the class enclosing scope?
public Transform transObj = new Transform();

Transform is a Component, and these should never be created with new X() as Spiney said. You either assign a reference to it in the Inspector in the Unity Editor, or use code to retrieve an appropriate component with GetComponent (from Component.GetComponent or GameObject.GetComponent).
Remove the = new Transform() initializer from the field declaration, and instead choose one of the above ways to assign the field.

If you want to refer to the Transform of the GameObject that your script is already on, then you can just use the transform property of Component from the script instead of using a separate variable. Otherwise, assignment via the Inspector is the way to go.

2 Likes

I did it but it says that object reference is required for non-static field.
public Transform transObj = GameObject.GetComponent(typeof(Transform)) as Transform;
Isn’t this an object reference?

GameObject.GetComponent and Component.GetComponent are instance methods, meaning you need to have an existing object to call the methods on. For example, someExistingGameObjectVariable.GetComponent<Transform>() and someExistingComponentVariable.GetComponent<Transform>(). I just mentioned the methods that way because that’s a normal way to describe the method and what type it’s on.

Can we clarify something? Are you trying to get the Transform for the GameObject that your script is on? In that case, you can just use transform, like in the RubyController code example above (you can also say GetComponent<Transform>() inside the script, which calls the GetComponent instance method on the component itself, but is pointless because the transform property is already available). If not, GetComponent won’t be much help if you don’t already have a reference to the GameObject whose Transform you want. In that case, you should use the Inspector to assign the right object.-,Object%20reference%20fields,-As%20well%20as) (see the “Object reference fields” section).

No you’re accessing the GameObject type. This is not the same as having a reference to an actual instance of an object of type GameObject.

You can see in the code Spymaster posted from Ruby how they access the transform of the same game object. Every component has access to the transform of the game object they’re on, so it’s just accessed via transform, akin to doing this.transform.

Given all these questions I would probably spend some time learning the basics of Unity and coding: https://learn.unity.com/pathway/junior-programmer

2 Likes

thank you, i got it