Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Vector3.MoveTowards not reaching the extent of the target vector3?

Discussion in 'Scripting' started by polypixeluk, Sep 11, 2020.

  1. polypixeluk

    polypixeluk

    Joined:
    Jul 18, 2020
    Posts:
    53
    I'm trying to scale an object up and down while also moving it along an offset axis.
    I thought I had it working but now that I've come back to change the Min/Max size values I realize the MoveTowards only goes between 1 and 2 when it scales. The offset works fine. Can anyone explain my problem?

    Code (CSharp):
    1. public class Glob : MonoBehaviour
    2. {
    3.     //References
    4.     public GameObject sphere;
    5.     public GameObject pivot;
    6.  
    7.     public bool isScaling = false;
    8.     private bool scaleUp = true;
    9.     public Vector3 maxSize = new Vector3 (3f,3f,3f);
    10.     public Vector3 minSize = new Vector3(0.5f, 0.5f, 0.5f);
    11.  
    12.     private float targetOffset;
    13.     private float maxOffset = 1.5f;
    14.     private float speed = 2f;
    15.  
    16.     private void Awake()
    17.     {
    18.         isScaling = false;
    19.  
    20.     }
    21.  
    22.     void Update()
    23.     {
    24.         //print("SphereScaleZ: " + sphere.transform.localScale.z);
    25.         //print("OffsetZ: " + sphere.transform.localPosition.z);
    26.         if (isScaling)
    27.         {
    28.             if (scaleUp)
    29.             {
    30.            
    31.                 if(sphere.transform.localScale.x <= maxSize.x)
    32.                 {
    33.                     targetOffset = maxOffset;
    34.                     StartCoroutine(SetTransform(maxSize, targetOffset));
    35.  
    36.                 }
    37.                 if (sphere.transform.localScale.x >= maxSize.x)
    38.                 {
    39.                     scaleUp = false;
    40.                 }
    41.                
    42.             }
    43.             else
    44.             {
    45.                 if (sphere.transform.localScale.x >= minSize.x)
    46.                 {
    47.                     targetOffset = 0f;
    48.                     StartCoroutine(SetTransform(minSize, targetOffset));
    49.  
    50.                 }
    51.                 if (sphere.transform.localScale.x <= minSize.x)
    52.                 {
    53.                     scaleUp = true;
    54.                 }            
    55.             }
    56.         }      
    57.     }  
    58.  
    59.     public void StopScaling()
    60.     {
    61.         isScaling = false;
    62.     }
    63.  
    64.     IEnumerator SetTransform(Vector3 size, float offset)
    65.     {
    66.         sphere.transform.localScale = Vector3.MoveTowards(sphere.transform.localScale, size, Time.deltaTime * speed);
    67.         sphere.transform.localPosition = Vector3.MoveTowards(sphere.transform.localPosition, new Vector3 (sphere.transform.localPosition.x, sphere.transform.localPosition.y, offset), Time.deltaTime * speed);
    68.  
    69.         yield return new WaitForSeconds(0);
    70.     }
    71.  
    72. }
    73.  
     
  2. Zer0Cool

    Zer0Cool

    Joined:
    Oct 24, 2014
    Posts:
    203
    One hint:
    Your usage of the couroutine makes no sense this way.
    Either you make the scaling in the couroutine or the update method. At the moment the scaling is happening inside the Update method.

    If you want to use the coroutines for this job you have to code a loop inside the coroutine and check if the coroutine is done with the scaling (this ends the loop)
    Code (CSharp):
    1.  
    2. IEnumerator ScaleTransform(Vector3 size)
    3.   {
    4.      isScaling = true;
    5.      while (Vector3.Distance(sphere.transform.localScale, size) < 0.001f)
    6.      {
    7.         sphere.transform.localScale = Vector3.MoveTowards(sphere.transform.localScale, size, Time.deltaTime * speed);
    8.         yield return null;
    9.      }
    10.      scaleDirection = !scaleDirection; // toggle the scaling direction
    11.      isScaling = false; // the scaling is finished
    12.   }
    13.  
    Additionally i would make then 2 coroutines, one for scaling and one for the translation.

    Here's the fitting Update method (for doing the scaling):
    Code (CSharp):
    1. public bool isScaling = false;
    2. private bool scaleDirection = true;
    3.  
    4. void Update()
    5.   {
    6.     if (!isScaling)
    7.       {  
    8.          if (scaleDirection) StartCoroutine(ScaleTransform(maxSize));
    9.          else StartCoroutine(ScaleTransform(minSize));            
    10.       }
    11. }
     
    Last edited: Sep 11, 2020
    PraetorBlue likes this.
  3. polypixeluk

    polypixeluk

    Joined:
    Jul 18, 2020
    Posts:
    53
    Hey, thanks for your response. I've been trying to get your solution to work for me but the sphere doesn't scale. I just see the isScaling bool toggling on and off very quickly. I changed a few of the names of things to try to make it easier to understand for myself and I've wrapped the Update stuff in an if statement so I can toggle the effect on and off but other than that I think I've written what was suggested.
    Code (CSharp):
    1. public class Glob : MonoBehaviour
    2. {
    3.     //References
    4.     public GameObject sphere;
    5.     public GameObject pivot;
    6.  
    7.     public bool doScale;
    8.     public bool isScaling;
    9.     public Vector3 maxSize;
    10.     public Vector3 minSize;
    11.  
    12.     private float targetOffset;
    13.     private float maxOffset = 1.5f;
    14.     private float speed = 1f;
    15.  
    16.     public bool scaleUp = true;
    17.  
    18.     private void Start()
    19.     {
    20.         doScale = true;
    21.         isScaling = false;
    22.         maxSize = new Vector3(3f, 3f, 3f);
    23.         minSize = new Vector3(0.5f, 0.5f, 0.5f);
    24.      
    25.     }
    26.  
    27.     void Update()
    28.     {
    29.         if (doScale == true)
    30.         {
    31.             if (!isScaling)
    32.             {
    33.                 if (scaleUp) StartCoroutine(ChangeSize(maxSize));
    34.                 else StartCoroutine(ChangeSize(minSize));
    35.             }
    36.         }          
    37.     }
    38.  
    39.     IEnumerator ChangeSize(Vector3 targetSize)
    40.     {
    41.         isScaling = true;
    42.  
    43.         while (Vector3.Distance(sphere.transform.localScale, targetSize) < 0.001f)
    44.         {
    45.             sphere.transform.localScale = Vector3.MoveTowards(sphere.transform.localScale, targetSize, Time.deltaTime * speed);
    46.             yield return null;
    47.         }
    48.         scaleUp = !scaleUp; // toggle the scaling direction
    49.         isScaling = false; // the scaling is finished
    50.     }
    51.  
    52.  
    53. }
    54.  
    Note: I'm manually toggling the doScale bool from the inspector when running the game to test.
     
    Last edited: Sep 14, 2020
  4. Zer0Cool

    Zer0Cool

    Joined:
    Oct 24, 2014
    Posts:
    203
    Sorry here the direction of the comparison was wrong. The value "0.001f" describes the
    threshold at which distance the vectors be considered the same:
    Code (CSharp):
    1. while (Vector3.Distance(sphere.transform.localScale, targetSize) > 0.001f)
     
    Last edited: Sep 14, 2020
  5. polypixeluk

    polypixeluk

    Joined:
    Jul 18, 2020
    Posts:
    53
    I should have clocked that! Thanks.

    I've now got both the offset position and scale working as separate coroutines. I've set the offset to match the difference between the min and max scale and made sure that the sphere starts at min scale with no offset. The speed is also the same for both the offset and the scale yet they don't finish at the same time. Can anyone explain why that is? I would have thought if the speed and distance were the same then the time of arrival would be in sync.

    Here's my code.
    Code (CSharp):
    1. public class Glob : MonoBehaviour
    2. {
    3.     //References
    4.     public GameObject sphere;
    5.     public GameObject pivot;
    6.  
    7.     public bool doScale;
    8.     public bool isScaling;
    9.     private Vector3 maxSize;
    10.     private Vector3 minSize;
    11.  
    12.     private float maxOffset;
    13.     private float speed;
    14.  
    15.     public bool scaleUp = true;
    16.  
    17.     private void Start()
    18.     {
    19.         doScale = false;
    20.         isScaling = false;
    21.         maxSize = new Vector3(8f, 8f, 8f);
    22.         minSize = new Vector3(4f, 4f, 4f);
    23.         maxOffset = 4f;
    24.         speed = 5f;
    25.  
    26.     }
    27.  
    28.     void Update()
    29.     {
    30.         if (doScale == true)
    31.         {
    32.             if (!isScaling)
    33.             {
    34.                 if (scaleUp)
    35.                 {
    36.                     StartCoroutine(ChangeSize(maxSize));
    37.                     StartCoroutine(ChangeOffset(maxOffset));
    38.                 }
    39.                 else {
    40.                     StartCoroutine(ChangeSize(minSize));
    41.                     StartCoroutine(ChangeOffset(0f));
    42.                 }        
    43.             }
    44.         }
    45.     }
    46.  
    47.     public void ToggleGlobTransform()
    48.     {
    49.         doScale = false;
    50.         StopAllCoroutines();
    51.     }
    52.  
    53.     IEnumerator ChangeSize(Vector3 targetSize)
    54.     {
    55.         isScaling = true;
    56.  
    57.         while (Vector3.Distance(sphere.transform.localScale, targetSize) > 0.001f)
    58.         {
    59.             sphere.transform.localScale = Vector3.MoveTowards(sphere.transform.localScale, targetSize, Time.deltaTime * speed);
    60.             yield return null;
    61.         }
    62.         scaleUp = !scaleUp; // toggle the scaling direction
    63.         isScaling = false; // the scaling is finished
    64.     }
    65.  
    66.     IEnumerator ChangeOffset(float targetOffset)
    67.     {  
    68.         while (Vector3.Distance(sphere.transform.localPosition, new Vector3 (sphere.transform.localPosition.x, sphere.transform.localPosition.y, targetOffset)) > 0.001f)
    69.         {
    70.             sphere.transform.localPosition = Vector3.MoveTowards(sphere.transform.localPosition, new Vector3(sphere.transform.localPosition.x, sphere.transform.localPosition.y, targetOffset), Time.deltaTime * speed);
    71.             yield return null;
    72.         }  
    73.     }
    74. }