Why do I need to move target position into new Vector3, and can not use the Vector3 that holds the target position directly?

With the help of a script I found on here, I was able to move a butterfly sprite to a new random location. However, I need to first load the x and y values of the new location Vector3 into another Vector3.x and .y, otherwise it does not work. Logically I would think that I can use directly the randomly defined targetPosition Vector3. I would like to understand what is wrong in my logic.

I have the 2 scripts below. Script 1 works, but is not logical to me. Script 2 should work in my opinion but does not.

The way it works:
I have a butterfly sprite in my world
At Start, I select a random point on a sphere and make this my targetPosition
Then in Update, I check the current location of the butterfly and move it towards the targetPosition.
In script 1 this works but I first put the random target location into Vector3 targetPos and then assign targetPos.x to targetPosition.x and same for y.
In script 2 I put the random location directly into targetPoistion and looking at the debug.log, the x and y values are not zero.

Could someone please explain what is wrong in my logic of script 2 and explain how I should move my butterfly properly to the targetPosition?


using UnityEngine;
using System.Collections;

public class ButtMove : MonoBehaviour {

private Vector3 targetPosition;
private Vector3 targetPos;

public void Start(){
	**Vector3 targetPos = transform.position + Random.insideUnitSphere * 10;**   
	**targetPosition.x = targetPos.x;**
	**targetPosition.y = targetPos.y;**
	**targetPosition.z = 0f;**
	Debug.Log ("targetposition = " + targetPosition.x + " - " + targetPosition.y);

public void Update(){
	float speed = 2;		//move towards targetPosition with this speed

	Vector3 currentPosition = this.transform.position;		//position of butterfly
	//Debug.Log ("currentposition= " + currentPosition);
	//first, check to see if we're not yet close to the target
	if (Vector3.Distance (currentPosition, targetPosition) > .1f) { 
		Vector3 directionOfTravel = targetPosition - currentPosition;
		//now normalize the direction, since we only want the direction information
		directionOfTravel.Normalize ();
		//scale the movement on each axis by the directionOfTravel vector components
		this.transform.Translate (
			(directionOfTravel.x * speed * Time.deltaTime),
			(directionOfTravel.y * speed * Time.deltaTime),
			(directionOfTravel.z * speed * Time.deltaTime),


Script2 only difference to script 1 is in Start():

public void Start(){
	**Vector3 targetPosition = transform.position + Random.insideUnitSphere * 10;   
	targetPosition.z = 0f;**
	Debug.Log ("targetposition = " + targetPosition.x + " - " + targetPosition.y);

Well, if the code is exactly as you wrote it your problem is that you define a new local variable inside Start with the same name as your member variable of the class.

So instead of:

Vector3 targetPosition = transform.position + Random.insideUnitSphere * 10;

you have to use

targetPosition = transform.position + Random.insideUnitSphere * 10;

To answer the question about modifying transform’s position: you cannot directly assign .z of transform.position, because Vector3 is a struct and .position is a property.

Here is an example to demonstrate how writing fields and properties works with structs and classes:

public class FieldAndPropertyModify : MonoBehaviour
    private Vector3 structField;
    private Vector3 StructProperty { get; set; }

    private MyVector classField;
    private MyVector ClassProperty { get; set; }

    private void Start()
        structField.z = 3f; // fine
        // StructProperty.z = 3f; ** NOT fine **

        classField.z = 3f; // fine
        ClassProperty.z = 3f; // fine

    private class MyVector { public float z; }

Firstly, struct is a value type. This means it returns a copy when you read it:

Vector3 first = new Vector3(1, 2, 3);
Vector3 second = first;
second.z = 10f;
Debug.Log(first.z); // 3f

Secondly, accessing StructProperty returns a copy. While I used a { get; set; } shorthand, here is what the compiler “sees”:

private Vector3 _structProperty;
private Vector3 StructProperty { get { return _structProperty; } set { _structProperty = value; } }

So when you read transform.position (which is a get method), you receive a copy of Vector3. You can then modify this struct to your needs. Then you pass it back into transform.position (which is a set method with a value parameter), which stores a copy again. But accessing .z from reading a property simply accesses the value of the copy and assigning a new value to it that just gets “lost” makes no sense.

See Bunny83’s answer for the issue in the source code itself.

Edit: rewrote and scrapped incorrect info, thanks Bunny83