This is an age old “issue” that for some reason keeps on coming back and bugging me, and I know others have wondered about this aswell, and that is: “is there any way we can manipulate transform vectors like ‘position’, ‘rotation’, and ‘scale’ without having to manually get the original vector, set it to a new value, and then re-set the original transform vector? Which feels like a real pain every time”.
TLDR:
// Can we turn
Vector3 newPosition = transform.position;
newPosition.x += 1;
transform.position = newPosition;
// Into something like this?
position.x += 1;
The answer is a definite yes! But I’m intrigued to know what your thoughts are on this as a concept / solution. Here is an example class named “TransformVector”, in it’s constructor it takes the transform of a game object, and the transform type (either position, rotation, or scale), and then you can access this object’s x, y and z values just like a stand alone vector, and it will automagically update the appropriate transform values for you behind the scenes:
using UnityEngine;
public class TransformVector
{
// Enum for the different transform types
public enum TransformTypes { Position, Rotation, Scale }
// The transform type
public TransformTypes transformType;
// Reference to the objects transform
public Transform transform;
// Floats for the transform vector
public float x { get { return get().x; } set { set(value); } }
public float y { get { return get().y; } set { set(null, value); } }
public float z { get { return get().z; } set { set(null, null, value); } }
public float xy { set { set(value, value); } }
public float xz { set { set(value, null, value); } }
public float yz { set { set(null, value, value); } }
public float xyz { set { set(new Vector3(value, value, value)); } }
/// <summary>
/// Constructor
/// </summary>
/// <param name="transform"></param>
/// <param name="transformType"></param>
public TransformVector(Transform transform, TransformTypes transformType)
{
this.transform = transform;
this.transformType = transformType;
}
/// <summary>
/// Get the transform vector
/// </summary>
/// <returns>Vector3 of this transform type</returns>
public Vector3 get()
{
switch (transformType) {
case TransformTypes.Position: return transform.position;
case TransformTypes.Rotation: return transform.eulerAngles;
case TransformTypes.Scale: return transform.localScale;
default: return Vector3.zero;
}
}
/// <summary>
/// Set the transform vector
/// </summary>
/// <param name="value"></param>
public void set(Vector3 value)
{
switch (transformType) {
case TransformTypes.Position: transform.position = value; break;
case TransformTypes.Rotation: transform.eulerAngles = value; break;
case TransformTypes.Scale: transform.localScale = value; break;
}
}
/// <summary>
/// Set the transform vector with nullable floats
/// </summary>
/// <param name="_x"></param>
/// <param name="_y"></param>
/// <param name="_z"></param>
public void set(float? _x = null, float? _y = null, float? _z = null)
{
Vector3 v = get();
if (_x != null) v.x = (float)_x;
if (_y != null) v.y = (float)_y;
if (_z != null) v.z = (float)_z;
set(v);
}
/// <summary>
/// Translate the transform vector
/// </summary>
/// <param name="value"></param>
public void translate(Vector3 value)
{
switch (transformType) {
case TransformTypes.Position: transform.Translate(value); break;
case TransformTypes.Rotation: transform.Rotate(value); break;
case TransformTypes.Scale: transform.localScale += value; break;
}
}
/// <summary>
/// Translate the transform vector
/// </summary>
/// <param name="_x"></param>
/// <param name="_y"></param>
/// <param name="_z"></param>
public void translate(float _x, float _y = 0, float _z = 0)
{
translate(new Vector3(_x, _y, _z));
}
/// <summary>
/// Implicit conversion to Vector3
/// </summary>
/// <param name="transformVector"></param>
public static implicit operator Vector3(TransformVector transformVector)
{
return transformVector.get();
}
/* Operator overloads
-------------------------------*/
public static TransformVector operator +(TransformVector a, Vector3 b)
{
a.set(a + b);
return a;
}
public static TransformVector operator -(TransformVector a, Vector3 b)
{
a.set(a - b);
return a;
}
public static TransformVector operator *(TransformVector a, Vector3 b)
{
a.set(a * b);
return a;
}
public static TransformVector operator /(TransformVector a, Vector3 b)
{
a.set(a / b);
return a;
}
}
Now I can already hear a few questions some may have about this, and one is that now we have to add our TransformVector to our game object which takes up extra lines anyway, eg:
// TransformVector fields
TransformVector position;
TransformVector rotation;
TransformVector scale;
// GameObject's Awake method
void Awake()
{
// Set transform vectors
position = new TransformVector(transform, TransformVector.TransformTypes.Position);
rotation = new TransformVector(transform, TransformVector.TransformTypes.Rotation);
scale = new TransformVector(transform, TransformVector.TransformTypes.Scale);
}
But now we can access any of the properties and manipulate them on a nice single line, like so:
// GameObject's Update method
void Update()
{
// Update transform value with TransformVector
position.x += Time.deltaTime;
scale.xy = Mathf.Sin(Time.time);
rotation.xyz += Time.deltaTime;
}
The other way could be creating something like a “TransformVectors” Component MonoBehaviour that has position, rotation, and scale TransformVector’s built in, and then can be accessed through the gameObject that way, like:
// Somewhere in a game object's Update method
transformVectors.position.x += Time.deltaTime;
Just out of interest though, what do you think of this approach, and have you got any thoughts on this?
One final thing is that of course you could add extension methods to all GameObject’s with something like:
// Extension method for changing x position of a game object
public static void SetXPosition(this GameObject gameObject, float x)
{
Vector3 position = gameObject.transform.position;
position.x = x;
gameObject.transform.position = position;
}
But you can see how quickly this gets messy, as you may want to add, multiply, divide, or set multiple parts of a vector in one go etc, and then you have to add all of those for rotation and scale also, so I personally don’t really feel comfortable with this solution, but maybe you guys have some thoughts or better ways of doing this.
I really do understand that this isn’t the “world’s worst problem” but was just messing about in Unity and trying some things to see what feels the most comfortable solution! Would be interesting to hear your thoughts