1
\$\begingroup\$

How can I check whether Vector3 and Quaternion are not "null"?

I have a saving system and didn't have a vector and quaternion value before.

Now I've added a Vector3 and Quaternion value into the saving system, so the new save file should have a Vector3 and Quaternion value.

I need to check whether the vector and quaternion values are present in the save file, but I can't use != null, cause it's a struct, so it can't be null.

So how can I check whether the value exists or not?

position != Vector3.zero , Rotation != Quaternion.identity

Is this the right way to do it?

\$\endgroup\$
1
  • \$\begingroup\$ if(x == null) is the check to see if x is null. Your code snippet is checking to see if a position is zero or the rotation is the identity, which is not the same thing as checking for null. Null means 'unassigned value'. \$\endgroup\$
    – Pikalek
    Commented Oct 1, 2022 at 15:19

2 Answers 2

2
\$\begingroup\$

If a struct type has not been given any particular value, it will usually default to a special value helpfully called default. (Though it's possible the file loading code you use does something different — you haven't shown us, so I'm assuming it's following standard C# convention).

The members of default will each hold the value corresponding to the default of their respective types: 0 for numbers, false for booleans, null for reference types, etc.

So you can check:

if (!position.Equals(default)) {/*...*/}

if (rotation != default) {/*...*/}

For a Vector3, the default value is the same as Vector3.zero, ie. (0, 0, 0), just less typing, and a bit more explicit that you're checking if it's a default value not looking for a deliberately-set value of zero.

But that highlights a bit of an issue with this code: it won't distinguish between loading an item for which no position was set, versus loading an item that was set to (0, 0, 0) deliberately.

If that distinction is important for your loading logic, then as others have suggested, you may want to change the declaration of your variable to:

[SerializeField]
Vector3? position;

This makes it a "nullable" struct — it's still a value type, but it gains an extra flag that tracks whether a value has been set.

You can check this with:

if (!position.HasValue) {/*...*/}

or, for convenience, position == null translates to this for nullable types.

Then, to access the Vector3 contents, you'd write position.Value.

You'll note that I used the .Equals() method instead of == above. That's because the equality operator for Vector3 has a built-in tolerance, so a vector very close to zero but not actually zero will return true if you compare it to a zero vector with ==. The .Equals() method only returns true for an exact match.

For quaternions, you have a somewhat easier time, in that any valid quaternion will have a non-zero value. ie. Quaternion.Dot(rotation, rotation) should be close to 1.0 — even for Quaternion.identity, which is (0, 0, 0, 1) (in x, y, z, w order).

So if you ever read an all-zero quaternion (like default), you can be sure that was not a deliberately set value, and needs to be overridden.

The difference between an all-zero quaternion and a valid one is much larger than the tolerance used in the == operator, so you don't strictly need the .Equals() method in this case.

\$\endgroup\$
0
\$\begingroup\$

You can use

Quaternion? rotation = null; Vector3? position = null;

then you can check if the value exit in savefile

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .