Search Unity

Move in a Circle and change position

Discussion in 'Scripting' started by JannikJ, Sep 23, 2017.

  1. JannikJ

    JannikJ

    Joined:
    Jun 22, 2017
    Posts:
    62
    Hi,

    I have a circular motion of an object, and it should change its position to a circle with a bigger radius after pressing a key. The problem is, that it should lerp from the actual position to the new position in the bigger circle (image) and then it should continue with its circulation. Unfortunatley I dont know how to code that.

    Greetings,
    J.

    Code (CSharp):
    1.     public float RotateSpeed = 5f;
    2.     public float Radius;
    3.  
    4.     private Vector2 centre;
    5.     private float angle;
    6.  
    7.     private void Start()
    8.     {
    9.         centre = transform.position;
    10.         Radius = 0.3f;
    11.     }
    12.  
    13.     private void Update()
    14.     {
    15.         if (Input.GetKeyDown (KeyCode.DownArrow)) {
    16.             Radius = 0.5f;
    17.             Vector2 newPos = new Vector2(Mathf.Sin(angle), Mathf.Cos(angle)) * Radius;
    18.             transform.position = Vector3.Lerp (transform.position, newPos, 0.5f);
    19.         }
    20.  
    21.         angle += RotateSpeed * Time.deltaTime;
    22.  
    23.         var offset = new Vector2 (Mathf.Sin (angle), Mathf.Cos (angle)) * Radius;
    24.         transform.position = centre + offset;
    25.     }
     

    Attached Files:

  2. Rob21894

    Rob21894

    Joined:
    Nov 21, 2013
    Posts:
    309
    When performing a Vector3.Lerp it "Lerps" from A to B over a set time (c)

    In your code

    Code (CSharp):
    1. transform.position = Vector3.Lerp (transform.position, newPos, 0.5f);
    You have set it to 0.5, which will automatically set the position to inbetween the current position and the newPos.to achieve a successful lerp you must increase (c) by a time until it reaches 1 (hits your target position) here is an example script of how you can handle the lerp
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class LerpDemonstration : MonoBehaviour
    6. {
    7.  
    8.     public Vector3 targetPos;
    9.     private bool downPressed = false;
    10.  
    11.     public float lerpSpeed;
    12.     // Use this for initialization
    13.     void Start () {
    14.      
    15.     }
    16.  
    17.     // Update is called once per frame
    18.     void Update () {
    19.  
    20.         if (Input.GetKeyDown(KeyCode.DownArrow))
    21.         {
    22.             if (!downPressed)
    23.             {
    24.                 StartCoroutine(DoLerpFunction());
    25.                 downPressed = true;
    26.             }
    27.         }
    28.      
    29.     }
    30.  
    31.     IEnumerator DoLerpFunction()
    32.     {
    33.         downPressed = true;
    34.         float time = 0.0f;
    35.         while (transform.position != targetPos)
    36.         {
    37.             if (time < 1.0f)
    38.             {
    39.                 time += lerpSpeed * Time.deltaTime;// increase time by a set speed * deltatime (gives room to edit to a value you like)
    40.                 transform.position = Vector3.Lerp(transform.position, targetPos, time);
    41.             }
    42.             yield return null;
    43.         }
    44.         downPressed = false;
    45.     }
    46. }
    47.  
    and here is a gif of the result https://gyazo.com/bc93cdd8268c996df8ab0a7786b08367

    The only issue with this code is that you will have to continuously set the Target position after the lerp has been completed, but you can easily edit this for desired results.
     
    Last edited: Sep 23, 2017
    JannikJ likes this.
  3. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Also, in most cases when beginners reach for Lerp, what they really want is Mathf.MoveTowards (or Vector3.MoveTowards or whatever it is they're dealing with).

    In this case, you just want the Radius to MoveTowards the larger radius for a little bit each frame. Here's how I would do it.

    Code (CSharp):
    1.     public float RotateSpeed = 5f;
    2.     public float RadiusChangeSpeed = 0.1f;
    3.     public float TargetRadius = 0.3f;
    4.     private Vector2 centre;
    5.     private float angle;
    6.     private float actualRadius;
    7.    
    8.     private void Start()
    9.     {
    10.         centre = transform.position;
    11.         actualRadius = TargetRadius = 0.3f;
    12.     }
    13.  
    14.     private void Update()
    15.     {
    16.         if (Input.GetKeyDown (KeyCode.DownArrow)) {
    17.             TargetRadius = 0.5f;
    18.         }
    19.         angle += RotateSpeed * Time.deltaTime;
    20.         actualRadius = Mathf.MoveTowards(actualRadius, targetRadius, RadiusChangeSpeed * Time.deltaTime);
    21.         var offset = new Vector2 (Mathf.Sin (angle), Mathf.Cos (angle)) * actualRadius;
    22.         transform.position = centre + offset;
    23.     }
    Note that no coroutine is needed. ;)
     
    JannikJ likes this.
  4. JannikJ

    JannikJ

    Joined:
    Jun 22, 2017
    Posts:
    62
    thanks for your help!:) It works, but if I press a key it should move very fast to the larger radius towards the extended line between the center and the point where I pressed the button (red dotted line in the image). So the rotation should stop while the object moves/lerps and afterwards continue. What is the best way to do that?
     
  5. Rob21894

    Rob21894

    Joined:
    Nov 21, 2013
    Posts:
    309

    You could accomplish this many ways, i recommend looking at working with Quaternions or even using transform.LookAt
     
    JannikJ likes this.
  6. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Simply put the code that advances the angle in an 'if' block, e.g.:

    Code (csharp):
    1. if (actualradius == targetRadius) {
    2.     angle += RotateSpeed * Time.deltaTime;
    3. }
    Now whenever the target radius changes, the angle will stop advancing until the actual radius has caught up.
     
    JannikJ likes this.
  7. JannikJ

    JannikJ

    Joined:
    Jun 22, 2017
    Posts:
    62
    I tried this:
    Code (CSharp):
    1.     public float RotateSpeed = 5f;
    2.     public float RadiusChangeSpeed = 0.2f;
    3.     public float TargetRadius = 0.3f;
    4.     private Vector2 centre;
    5.     private float angle;
    6.     private float actualRadius;
    7.     bool moving = false;
    8.  
    9.     private void Start()
    10.     {
    11.         centre = transform.position;
    12.         actualRadius = TargetRadius = 0.3f;
    13.     }
    14.  
    15.     private void Update()
    16.     {
    17.         if (Input.GetKeyDown (KeyCode.DownArrow)) {
    18.             moving = true;
    19.             TargetRadius = 0.5f;
    20.             StartCoroutine(WaitforLerp());
    21.         }
    22.         if (moving == true) {
    23.             angle += 1 * Time.deltaTime;
    24.             actualRadius = Mathf.MoveTowards (actualRadius, TargetRadius, 2 * Time.deltaTime);
    25.             Debug.Log (Time.deltaTime);
    26.             var offset = new Vector2 (Mathf.Sin (angle), Mathf.Cos (angle)) * actualRadius;
    27.             transform.position = centre + offset;
    28.         }
    29.         if (moving == false) {
    30.             angle += RotateSpeed * Time.deltaTime;
    31.             actualRadius = Mathf.MoveTowards (actualRadius, TargetRadius, RadiusChangeSpeed * Time.deltaTime);
    32.             var offset = new Vector2 (Mathf.Sin (angle), Mathf.Cos (angle)) * actualRadius;
    33.             transform.position = centre + offset;
    34.         }
    35.     }
    36.  
    37.     public IEnumerator WaitforLerp()
    38.     {
    39.         yield return new WaitForSeconds(0.15f);
    40.         moving = false;
    41.     }
    It seems to work, but I think your Method @JoeStrout is better. What do you think?
    And do you have an Idea how I can adjust the speed of the object, so that it is the same for every radius size?