-1
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class MoveAbleButtonSystem : MonoBehaviour
{
    public Transform ObjectToMove;
    public bool moveLeft = true;
    public bool moveRight = false;
    public float SpeedToMove = 1f;

    private bool pressed = false;
    public float minZ = 0f;
    public float maxZ = 0f;

    void OnMouseDown()
    {
        pressed = true;
    }

    void OnMouseUp()
    {
        pressed = false;
    }

    void Update()
    {
        Transform T = ObjectToMove.transform;

        if (pressed && moveLeft)
        {
            T.Translate(Vector3.forward * SpeedToMove * Time.deltaTime, Space.World);
        }else
        if(pressed && moveRight)
        {
            T.Translate(Vector3.back * SpeedToMove * Time.deltaTime, Space.World);
        }

        if(T.position.z > maxZ)
        {
            T.position.z = maxZ;
        }

    }
}

Assets\Scripts\MainMenu\MoveAbleButtonSystem.cs(42,13): error CS1612: Cannot modify the return value of 'Transform.position' because it is not a variable

I dont get why I cannot change the position. All I want to do is for the ObjectToMove to move until it passes a certain point, after what it is not supposed to move anymore. Using Clamp provides the same error.

Lexus
  • 49
  • 6
  • 4
    You can't just set x, y, or z, because the type of `position` is an immutable vector3 struct; you can assign a new vector to `position` though. – Mathieu Guindon Jan 18 '23 at 12:38
  • 1
    `Transform.position` is a struct return from a property getter, which means that a COPY of the position is returned. Attempting to change the data in the copy will have no effect on the original, so the compiler doesn't allow it. – Matthew Watson Jan 18 '23 at 12:38
  • Compiler would allow it though, if the struct were mutable. Problem is that x, y, z members have no setter at all. – Mathieu Guindon Jan 18 '23 at 12:40
  • @MathieuGuindon The `vector3` class in Unity [is NOT immutable](https://docs.unity3d.com/ScriptReference/Vector3-x.html). See the sample code in the link where the 'x' field is modified. – Matthew Watson Jan 18 '23 at 12:44
  • Probably a duplicate of https://stackoverflow.com/questions/14945118/cant-change-structs-members-value-inside-generic-collections#answer-14958238 – Matthew Watson Jan 18 '23 at 12:59
  • And this: https://answers.unity.com/questions/1078528/cannot-modify-the-return-value-of-transformpositio.html – Matthew Watson Jan 18 '23 at 13:00
  • @MatthewWatson interesting, assumptions shattered! – Mathieu Guindon Jan 18 '23 at 15:15

4 Answers4

4

The following simplified example demonstrates the same compile error:

public class Program
{
    public static void Main()
    {
        var container = new Container();
        container.Property.Value = 1; // Error CS1612 - Cannot modify the return value of 'Container.Property' because it is not a variable
    }
}

public struct Item
{
    public int Value;
}

public class Container
{
    public Item Property { get; set; }
}

This is the issue you're seeing. It's happening because the Container.Property property is returning a copy of a value type, in this case struct Item.

Because this is a copy of the item stored in Container and not the item itself, changing the copy's properties cannot have any visible effect because the value returned from the property is not stored anywhere - no variable is assigned from it.

Therefore the compiler gives an error, to avoid misleading and useless code.

The documentation for Error CS1612 explains all this in detail.

Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
1

Others - and the error documentation - already explained the issue and the why in detail.

But in terms of a solution for your issue you would go e.g.

// Get copy of current position
var position = T.position;

if(position.z > maxZ)
{
    // modify the copy
    position.z = maxZ;
}

// assign back / apply modified value
T.position = position;

You could even combine and simplify it a lot by doing e.g.

public enum MoveDirection
{    
    Left,
    Right
}

public MoveDirection direction;

void Update()
{
    if(pressed)
    {
        var T = ObjectToMove.transform;
        var position = T.position;

        var multiplier = direction == MoveDirection.Left ? 1 : -1;
        position.z = Mathf.Clamp(position.z + SpeedToMove * Time.deltaTime * multiplier);
 
        T.position = position;
    }
}
    
derHugo
  • 83,094
  • 9
  • 75
  • 115
0

As pointed in the comments from Mathieu and Matthew, position is a struct field of the calss Transform and due to this reason you can not change its fields like this. If you want to understand why this is not working imagine that Unity's Transform and position objects look something like this:

struct Position
{
    public int x;
    public int y;
    public int z;
}

class Transform
{
    public Position _position;
    public Position position 
    {
        get
        {
            return _position;
        }
        set
        {
            _position = value;
        }
    }
}

When you write T.position.z the position part is actually a value copy of the original T's position variable returned by the property getter. So by changing the copy of position you will not get the desired effect of updating the T.position's z field. Due to this reason C# it trying to help you by throwing an error in order to prevent a bug that is very hard to identify.

dimitar.d
  • 645
  • 1
  • 6
  • 18
-3

You can not change the individual components of a Vector3. To do this, you will have to change all the components. i.e :

if (T.position.z > maxZ)
{
    T.position = new Vector3(T.position.x, T.position.y, maxZ)
}
Obscure021
  • 181
  • 13
  • You *can* change the individual components of a `Vector3` [as shown in sample code in the actual documentation](https://docs.unity3d.com/ScriptReference/Vector3-x.html). What you *can't* do is directly change the fields/properties of a `struct` returned from a property. – Matthew Watson Jan 18 '23 at 12:56