Search Unity

Showcase Snippet to directly set values of transform.position

Discussion in 'Scripting' started by Tobogganeer, Feb 2, 2023.

  1. Tobogganeer

    Tobogganeer

    Joined:
    Sep 12, 2022
    Posts:
    2
    Hey folks,
    Everyone who's spent some time in Unity knows that you can't do this:
    transform.position.y += 15;

    To get around this, I have been using extension methods for the longest time, but this still isn't pretty:
    transform.position = transform.position.WithY(transform.position.y + 15);

    Today, I thought about a simple workaround: A sort of wrapper class for the position.
    You can use it like this:
    transform.PositionMut().y += 15;

    Here is the code that makes this possible:
    Code (CSharp):
    1. public static class TransformExtensions
    2. {
    3.     // Mut for mutable
    4.     public static MutPosition PositionMut(this Transform t)
    5.     {
    6.         return new MutPosition(t, false);
    7.     }
    8.  
    9.     public static MutPosition LocalPositionMut(this Transform t)
    10.     {
    11.         return new MutPosition(t, true);
    12.     }
    13. }
    14.  
    15. public class MutPosition
    16. {
    17.     Transform t;
    18.     bool local;
    19.  
    20.     public MutPosition(Transform t, bool local)
    21.     {
    22.         this.t = t;
    23.         this.local = local;
    24.     }
    25.  
    26.     public float x
    27.     {
    28.         get
    29.         {
    30.             return local ? t.localPosition.x : t.position.x;
    31.         }
    32.         set
    33.         {
    34.             if (local) t.localPosition = t.localPosition.WithX(value);
    35.             else t.position = t.position.WithX(value);
    36.         }
    37.     }
    38.  
    39.     public float y
    40.     {
    41.         get
    42.         {
    43.             return local ? t.localPosition.y : t.position.y;
    44.         }
    45.         set
    46.         {
    47.             if (local) t.localPosition = t.localPosition.WithY(value);
    48.             else t.position = t.position.WithY(value);
    49.         }
    50.     }
    51.  
    52.     public float z
    53.     {
    54.         get
    55.         {
    56.             return local ? t.localPosition.z : t.position.z;
    57.         }
    58.         set
    59.         {
    60.             if (local) t.localPosition = t.localPosition.WithZ(value);
    61.             else t.position = t.position.WithZ(value);
    62.         }
    63.     }
    64.  
    65.     // Use these to chain calls together
    66.     public MutPosition X(float x)
    67.     {
    68.         this.x = x;
    69.         return this;
    70.     }
    71.  
    72.     public MutPosition Y(float y)
    73.     {
    74.         this.y = y;
    75.         return this;
    76.     }
    77.  
    78.     public MutPosition Z(float z)
    79.     {
    80.         this.z = z;
    81.         return this;
    82.     }
    83.  
    84.     // Use this to set multiple in one call, i.e transform.PositionMut().XYZ(y: 0, z: 15);
    85.     public MutPosition XYZ(float? x = null, float? y = null, float? z = null)
    86.     {
    87.         this.x = x ?? this.x;
    88.         this.y = y ?? this.y;
    89.         this.z = z ?? this.z;
    90.         return this;
    91.     }
    92. }
    It could be improved with more methods, and I am certain performance compared to just assigning a temporary variable is horrid, but it's a proof of concept.

    That's about all, hope somebody can make use of this!
     
  2. LethalGenes

    LethalGenes

    Joined:
    Jan 31, 2023
    Posts:
    69
    The reason you can’t add to the Euler struct is because of the built in a wrapper will automatically attempt to wrap the result before returning it. It will wrap it for specific use in a quaternion.

    However, you can wrap it yourself by setting it as you have figured out (most people can’t and won’t even try). At greater than 359 you can reset to zero, for as long as your value is set to the Euler angle specified it will never automatically wrap using the Euler structs interior return logic. This allows you to have a rotational system that is more logical to a 360* math set protractor.
     
  3. RadRedPanda

    RadRedPanda

    Joined:
    May 9, 2018
    Posts:
    1,648
    I usually just do
    transform.position += Vector3.up * 15;
     
    TzuriTeshuba likes this.
  4. Tobogganeer

    Tobogganeer

    Joined:
    Sep 12, 2022
    Posts:
    2
    True, the example I used wasn't fantastic. Something more complex, like
    transform.position.x *= 2;
    would have more utility here. Or, for example,
    transform.position.y = 0;
    . In these scenarios, it still isn't much more beneficial over using an extension method like
    transform.position = transform.position.Flat();

    Code (CSharp):
    1. public static Vector3 Flat(this Vector3 vector)
    2. {
    3.     return new Vector3(vector.x, 0f, vector.z);
    4. }
    , etc etc. More proving that something I didn't think would be possible is, in a hacky workaround-ish way.
     
    RadRedPanda likes this.