Why do we use the "new" keyword when initialising a Vector3, but not an integer?

Viewed 851

Why is it then if I were to initialise a string or an integer I could simply do this:

int number = 1;
string word = "word";

But if I want to initialise a Vector3 then I have to do:

Vector3 coordinate = new Vector3(1f,1f,1f);

The context to this is that I was creating a pretty large array and had to write out new Vector3... every time and it got pretty tedious:

Vector3[,] coordsList = new Vector3[11, 11]
{
    {new Vector3(-1.32f,1.32f), new Vector3(-1.08f,1.32f), new Vector3(-0.84f,1.32f), new Vector3(-0.6f,1.32f), new Vector3(-0.36f,1.32f), new Vector3(-0.12f,1.32f), new Vector3(0.12f,1.32f), new Vector3(0.36f,1.32f), new Vector3(0.6f,1.32f), new Vector3(0.84f,1.32f), new Vector3(1.08f,1.32f) },
    {new Vector3(-1.32f,1.08f), new Vector3(-1.08f,1.08f), new Vector3(-0.84f,1.08f), new Vector3(-0.6f,1.08f), new Vector3(-0.36f,1.08f), new Vector3(-0.12f,1.08f), new Vector3(0.12f,1.08f), new Vector3(0.36f,1.08f), new Vector3(0.6f,1.08f), new Vector3(0.84f,1.08f), new Vector3(1.08f,1.08f) },
    {new Vector3(-1.32f,0.84f), new Vector3(-1.08f,0.84f), new Vector3(-0.84f,0.84f), new Vector3(-0.6f,0.84f), new Vector3(-0.36f,0.84f), new Vector3(-0.12f,0.84f), new Vector3(0.12f,0.84f), new Vector3(0.36f,1.32f), new Vector3(0.6f,0.84f), new Vector3(0.84f,0.84f), new Vector3(1.08f,0.84f) },
    {new Vector3(-1.32f,0.60f), new Vector3(-1.08f,0.60f), new Vector3(-0.84f,0.60f), new Vector3(-0.6f,0.60f), new Vector3(-0.36f,0.60f), new Vector3(-0.12f,0.60f), new Vector3(0.12f,0.60f), new Vector3(0.36f,0.60f), new Vector3(0.6f,0.60f), new Vector3(0.84f,0.60f), new Vector3(1.08f,0.60f) },
    {new Vector3(-1.32f,0.36f), new Vector3(-1.08f,0.36f), new Vector3(-0.84f,0.36f), new Vector3(-0.6f,0.36f), new Vector3(-0.36f,0.36f), new Vector3(-0.12f,0.36f), new Vector3(0.12f,0.36f), new Vector3(0.36f,0.36f), new Vector3(0.6f,0.36f), new Vector3(0.84f,0.36f), new Vector3(1.08f,0.36f) },
    {new Vector3(-1.32f,0.12f), new Vector3(-1.08f,0.12f), new Vector3(-0.84f,0.12f), new Vector3(-0.6f,0.12f), new Vector3(-0.36f,0.12f), new Vector3(-0.12f,0.12f), new Vector3(0.12f,0.12f), new Vector3(0.36f,0.12f), new Vector3(0.6f,0.12f), new Vector3(0.84f,0.12f), new Vector3(1.08f,0.12f) },
    {new Vector3(-1.32f,-0.12f), new Vector3(-1.08f,-0.12f), new Vector3(-0.84f,-0.12f), new Vector3(-0.6f,-0.12f), new Vector3(-0.36f,-0.12f), new Vector3(-0.12f,-0.12f), new Vector3(0.12f,1.32f), new Vector3(0.36f,-0.12f), new Vector3(0.6f,-0.12f), new Vector3(0.84f,-0.12f), new Vector3(1.08f,-0.12f) },
    {new Vector3(-1.32f,-0.36f), new Vector3(-1.08f,-0.36f), new Vector3(-0.84f,-0.36f), new Vector3(-0.6f,-0.36f), new Vector3(-0.36f,-0.36f), new Vector3(-0.12f,-0.36f), new Vector3(0.12f,-0.36f), new Vector3(0.36f,-0.36f), new Vector3(0.6f,-0.36f), new Vector3(0.84f,-0.36f), new Vector3(1.08f,-0.36f) },
    {new Vector3(-1.32f,-0.6f), new Vector3(-1.08f,-0.6f), new Vector3(-0.84f,-0.6f), new Vector3(-0.6f,-0.6f), new Vector3(-0.36f,-0.6f), new Vector3(-0.12f,-0.6f), new Vector3(0.12f,-0.6f), new Vector3(0.36f,-0.6f), new Vector3(0.6f,-0.6f), new Vector3(0.84f,-0.6f), new Vector3(1.08f,-0.6f) },
    {new Vector3(-1.32f,-0.84f), new Vector3(-1.08f,-0.84f), new Vector3(-0.84f,-0.84f), new Vector3(-0.6f,-0.84f), new Vector3(-0.36f,-0.84f), new Vector3(-0.12f,-0.84f), new Vector3(0.12f,-0.84f), new Vector3(0.36f,-0.84f), new Vector3(0.6f,-0.84f), new Vector3(0.84f,-0.84f), new Vector3(1.08f,-0.84f) },
    {new Vector3(-1.32f,-1.08f), new Vector3(-1.08f,-1.08f), new Vector3(-0.84f,-1.08f), new Vector3(-0.6f,-1.08f), new Vector3(-0.36f,-1.08f), new Vector3(-0.12f,-1.08f), new Vector3(0.12f,-1.08f), new Vector3(0.36f,-1.08f), new Vector3(0.6f,-1.08f), new Vector3(0.84f,-1.08f), new Vector3(1.08f,-1.08f) },
};

But yet it would have been considerably easier had it been an array of integers? What is it about a Vector3 that requires this new keyword that an integer or a string does not.

4 Answers
Vector3[][] list = new (float x, float y)[][]
{
    new[] { (1.5f, 3.4f), (1.5f, 6.8f) },
    new[] { (1.5f, 3.4f), (1.5f, 6.8f) },
    new[] { (1.5f, 3.4f), (1.5f, 6.8f) },
    new[] { (1.5f, 3.4f), (1.5f, 6.8f) },
}.Select(r => r.Select(v => new Vector3(v.x, v.y)).ToArray()).ToArray();

You could use Value Tuples (now supported in the latest version of Unity 2018.3) to construct your data in a readable and less tedious way - then you can use Select to transform these into Vector3s.

I think most of the comments adequately cover your questions about the hows and whys of the new keyword here.

The reason that the Vector3 requires the new keyword is that a Vector3 is a struct built into Unity, so every time you use the new keyword, you are making a new instance of a Vector3 struct, whereas with a string or an int, these basic data types are from C#.

Hope this helps explain the difference!

Based on the recent comments I would like to propose this solution (via an extension method).

var list  = new (float X, float Y, float Z)[2, 2]
{
    {(-1.32f, 0f, 1.32f), (-1.32f, 0f, 1.32f)},
    {(-1.32f, 0f, 1.32f), (-1.32f, 0f, 1.32f)}
};

Vector3[,] coordsList = list.ToVector3();

and then you could use an Extension method...

public static class Vector3Extensions
{
    public static Vector3[,] ToVector3(this (float X, float Y, float Z)[,] value)
    {
        int columnCount = value.GetUpperBound(0);
        int rowCount = value.GetLength(0);
        
        var result = new Vector3[rowCount, columnCount];
        for (int i = 0; i < rowCount; i++)
        {
            for (int j = 0; j < columnCount; j++)
            {
                var tuple = ((float X, float Y, float Z))value.GetValue(i, j);
                result[i, j] = tuple.ToVector3();
            }
        }
        
        return result;
    }
    
    public static Vector3 ToVector3(this (float X, float Y, float Z) value)
    {
        return new Vector3(value.X, value.Y, value.Z);
    }
}

Certainly, the original solution would be more efficient, but I was unaware that you were using a struct from Unity at the time. However, this solution still attempts to solve the same problem of readability and repetitive code.


Original Post

I will assume that the objective of your question is to do about readability and refactoring repetitive code. You could use tuples alongside implicit operators to make it a bit more like what you want....

public class Vector3
{
    public Vector3(float x, float y)
    {
        this.X = x;
        this.Y = y;
    }
    
    public float X { get; set; }
    public float Y { get; set; }
    
    public static implicit operator (float X, float Y)(Vector3 value)
    {
        return (value.X, value.Y);
    }

    public static implicit operator Vector3 ((float X, float Y) value)
    {
        return new Vector3(value.X, value.Y);
    }
}

then you can construct it like so...

Vector3[,] coordsList  = new Vector3[2, 2]
{
    {(-1.32f,1.32f), (-1.32f,1.32f)},
    {(-1.32f,1.32f), (-1.32f,1.32f)}
};

Your coords are an XY-mirrored grid, which means you only have about 6 unique values. However, to make things easier, we'll keep track of the negative ones as well.

float[] values = new float[] { 
    1.32f,  1.08f,  0.84f,  0.6f,  0.36f,  0.12f, 
   -0.12f, -0.36f, -0.6f, -0.84f, -1.08f, -1.32f };

Now use a nested for-loop to populate your coords array:

Vector3[,] coordsList = new Vector3[11,11];

void Init() { 

    for ( int x = 0; x < coordsList.GetLength(0); x++) {
        for ( int y = 0; y < coordsList.GetLength(1); y++ ) {
            coordsList[x, y] = new Vector3(-values[x], values[y]);
        }
    }
}

If you want to maintain disparate coordinates (ie, not grid-mapped) then there are other means of forming the input data, but the conversion to Vector3 is not going to change much at all.

Related