1

I'm new to C# and Unity, and here I am tweaking and creating my first minigame.

Here is the problem:
I've got a little cube, that moves. I've implemented a method that checks the next position before making a move. The method receives as parameters the current cube position, and the direction:

 public bool okToMove(Transform playerCurrentPosition , int directionIndex)
{
   Transform playerNextPosition = playerCurrentPosition;

   playerNextPosition.Translate(toDirection(directionIndex));

    if (playerNextPosition.position.x > 1 ||
        playerNextPosition.position.x < -1 ||
        playerNextPosition.position.y > 1 ||
        playerNextPosition.position.y < -1)
        return false;
    else
        return true;
    }

Then, I call the method

public void movePlayer(int directionIndex)
{
    if (  okToMove(gameObject.transform, directionIndex) )
        transform.Translate(toDirection(directionIndex));

}

The problem is that the cube makes 2 moves at once. This is because of

transform.Translate(toDirection(directionIndex));

and

playerNextPosition.Translate(toDirection(directionIndex));

that is called from okToMove method. Unity or C# sees playerNextPosition as the real cube, and not somekind of temporary copy that only exists inside the method.

So why is my gameObject.transform being passed as a reference and not by value? How can I make it work?

Thanks in advance and sorry for my noobiness.

3 Answers3

1

You are passing reference to Transform and then moving it with translate in "okToMove", best way is to make a copy of Vector3, just change your "okToMove" like this.

public bool okToMove(Transform playerCurrentPosition , int directionIndex){
    Vector3 playerNextPosition = playerCurrentPosition.position;

    playerNextPosition += toDirection(directionIndex);

    if (playerNextPosition.x > 1 ||
        playerNextPosition.x < -1 ||
        playerNextPosition..y > 1 ||
        playerNextPosition.position.y < -1)
        return false;
    else
    return true;
}

Transform is component attached to each gameObject and it holds values for position, rotation and scale, so your "playerCurrentPosition" is not copy of position but rather reference to Transform (not a copy).

Neven Ignjic
  • 678
  • 5
  • 13
  • This is definitely the better approach. I create a member variable in situations like these so that the same object is being used on each call, rather than creating a new object, in this case the Vector3. Odds are you won't notice a performance impact, but I figure when you're making a game you really want to make every line of code count. – Eraph Aug 23 '15 at 23:49
  • 1
    If you copy and destroy "ghost" object every frame, trust me, you will feel the impact greatly on mobiles, to that point that the fps drops from 30 to unplayable just because of that method (I speak from experience) . If you don't know what object pooling is, I recommend you read about it, the whole point of it is to avoid instantiating and destroying objects. – Neven Ignjic Aug 23 '15 at 23:55
0

Create a new GameObject that is a copy of yours original, and use its transform to make your calculations. (This answer is originally from the Unity forums). The official documentation tells me you can use Object.Instantiate to create a clone of a GameObject.

In C#, objects have always their reference passed as value, so simply reassign won't do it. See this related question.

Community
  • 1
  • 1
Mephy
  • 2,978
  • 3
  • 25
  • 31
  • That is not really optimized way to do this, you need to instantiate GameObject and then later destroy (which in Unity is really expensive to do), we only care about it's position so it's enough to just copy position to new Vector3. – Neven Ignjic Aug 23 '15 at 23:05
  • @NevenIgnjic is some cases (not this one in particular) you may need the entire transform. Also, I did not say it was the most performant solution, and this solution's performance is already discussed in the provided link: "it has no collider, mesh renderer or anything like that, so it's actually a pretty lightweight and invisible object.". – Mephy Aug 23 '15 at 23:08
  • That makes it much easier since it's lightweight, but it all depends how often will this method run, copying it's position to Vector3 is the most cheapest solution, but in some cases you really do need entire transform (to avoid doing all that physics and math that Unity already did for us) – Neven Ignjic Aug 23 '15 at 23:11
-1

Objects in C# are passed by reference. If you want to copy an object, implement the ICloneable interface which has the method Clone(). You will need to copy the object yourself and return it from this method.

etcetera
  • 45
  • 3
  • 2
    The reference is passed by value, not by reference. More info here http://stackoverflow.com/questions/8708632/passing-objects-by-reference-or-value-in-c-sharp – Jeroen Vannevel Aug 23 '15 at 23:08