Search Unity

Circular movement

Discussion in 'Scripting' started by Crembotz, Oct 23, 2018.

  1. Crembotz

    Crembotz

    Joined:
    May 12, 2018
    Posts:
    18
    Hello everyone

    In my 2D "Endless runner" each wave is consisted of 3 orbs that spawn from either the right or left side of the screen at different y values and meet at a certain random x value. The first orb's velocity is being randomly generated and by using it and the aforementioned common x value, I calculate the exact moment in which the first orb will reach that point, let's call that moment t0. Using the time I calculated, the delay between the launches of sub sequential orbs and their initial position, I calculate the velocity that will make them reach the common x value at the time I calculated, t0, and apply it. Now, let's I'd also like to apply circular motion to one of the orbs I spawned, How can I achieve this while also making sure it will be at the common point at the right time?

    Thank you for your time and help!
     
  2. barskey

    barskey

    Joined:
    Nov 19, 2017
    Posts:
    207
    Note, this might be the long way to do this, but I'll explain my method along the way.Think of it as a free Trig lesson along the way.

    To move in a circle around a fixed point:
    Code (CSharp):
    1. public float angularSpeed = 1f;
    2. public float circleRad = 1f;
    3.  
    4. private Vector2 fixedPoint;
    5. private float currentAngle;
    6.  
    7. void Start ()
    8. {
    9.   fixedPoint = transform.position;
    10. }
    11.  
    12. void Update ()
    13. {
    14.   currentAngle += angularSpeed * Time.deltaTime;
    15.   Vector2 offset = new Vector2 (Mathf.Sin (currentAngle), Mathf.Cos (currentAngle)) * circleRad;
    16.   transform.position = fixedPoint + offset;
    17. }
    To figure out how long it will take to get there, you can divide the length of the arc by the speed (distance divided by disance/sec results in sec). To find the length of the arc, you will need the angle and the radius of your circle. Here's what it looks like:


    Considering you know the start point (where you instantiate) and the end point (where you intersect the other orbs), you know "d" above. If you bisect "d", you get right angles for your triangles shown. Hence you can use trig to figure out the angle "t".

    Sin(t) = (d/2) / r

    Solving for t you would get:

    t = Sin-1((d/2) / r)

    And looking at the diagram:
    angle = 360 - 2 * t

    And now that we have the angle, the length of the arc (thick blue line) is:
    length = (angle / 360) * 2 * PI * r

    Finally, in code:
    Code (CSharp):
    1. float d = Vector2.Distance (startPos, endPos);
    2. float t = Mathf.Asin ((d/2) / circleRad);
    3. float angle = 360 - 2 * t;
    4.  
    5. float arcLength = (angle / 360) * 2 * Mathf.PI * circleRad;
    6.  
    7. float delayTime = arcLength / angularSpeed;
    8.  
    I haven't put any of this in Unity, so I am pretty sure there will be some mistakes. But hopefully there's enough here to figure out what you need?
     
    Last edited: Oct 23, 2018
  3. Crembotz

    Crembotz

    Joined:
    May 12, 2018
    Posts:
    18
    First of all, thank you so much for all the time and effort you put into writing this comment.

    Second, if I understood it correctly, the orb is moving around the middle point of the line that is connecting its initial position with the common point that I generated, which is not the case. Imagine that the center of the circle the orb is rotating on is also moving, and I need to make sure that the X value of the orb's position vector will be the common x value I generated when all the other orbs have already reached that point. I'm also including this gif, to make sure I don't waste anymore of your time. I want the rotating orb's x value to be the common x value I generated when all the other orbs' x value is also that same value.

    Again, thank you so much!
     

    Attached Files:

    Last edited: Oct 23, 2018
  4. barskey

    barskey

    Joined:
    Nov 19, 2017
    Posts:
    207
    I'm sorry, but I don't follow what you want for your end result. Maybe you could show a sketch of start/end positions of each orb?
     
  5. Crembotz

    Crembotz

    Joined:
    May 12, 2018
    Posts:
    18
    Each orb is moving either left or right, each one's y coordinate is constant. By randomizing an X value and the speed of the first orb, I'm able to calculate the time in which it will reach the X value I randomized. Using that time and the X value I generated, I'm able the calculate the velocity of the orbs that will guarantee that they reach that point at the right moment, meaning that they will all share the same X coordinate value at the same time. Now let's I would like an orb to move both in a linear manner and a circular manner(Like seen in the GIF file I uploaded), how can I still make sure it will reach the X value I randomized at the moment the other orbs will be there?

    I hope it's clearer now, thanks again! For Unity forum.gif
     
  6. barskey

    barskey

    Joined:
    Nov 19, 2017
    Posts:
    207
    Let me see if I understand...

    OK, so X is horizontal, Y is vertical, and they are at a fixed height as they move left or right.

    You pick a random X float between the left and right edges of the camera boundaries, and figure out how long it takes for the first orb to reach that point.

    You want all three orbs to be lined up vertically at your randomly picked x value. I think I get it.

    Velocity has two components, X and Y. If you are calculating velocity and setting position manually, you can just ignore the y position of the circular moving orb, and still calculate its x velocity to make sure you set its x velocity so it reaches your vertical alignment point at the correct time. I don't understand the problem you are having.

    Unless you want the bottom of your circular "bounce" to occur when the orb is at that random x position also?

    Edit: Is your "circular movement" just a semi-circle?
     
  7. Crembotz

    Crembotz

    Joined:
    May 12, 2018
    Posts:
    18
    No it's a complete natural circular movement, imagine the orb the circulating around an imaginary point.

    About ignoring the y coordinate, this is the code I'm using on a script that is attached to each orb:
    Code (CSharp):
    1.  void Update()
    2.     {
    3.         if (spawnCircular)
    4.         {
    5.             timeCounter += Time.deltaTime * rb.velocity.x;
    6.             float x = Mathf.Cos(timeCounter) * radius;
    7.             float y = Mathf.Sin(timeCounter) * radius;
    8.             transform.position += new Vector3(x, y);
    9.         }
    10.     }
    I wasn't able to come up with a way to apply circular movement without setting the orb's position manually, so I'm not sure I can do that.

    rb.velocity.x is the velocity that guarantees the orb will intersect with the others vertically, so I could be wrong and what you said is true.

    Either way, I would really appreciate it if you could clear some things up for me.
     
  8. barskey

    barskey

    Joined:
    Nov 19, 2017
    Posts:
    207
    This is why I keep getting confused. In the gif you show an orb "bouncing" as it moves in semi-circles across the scene. This is not how you want your final movement to be?

    Maybe someone else will chime in and can understand more clearly.
     
  9. Crembotz

    Crembotz

    Joined:
    May 12, 2018
    Posts:
    18
    The orb isn't bouncing, it's just that the radius is pretty small...
    i just want to make sure the orbs align vertically even though one of them is also rotating around a certain imaginary point that also moves either left or right. Since in my code I'm setting the position of the circulating orb manually, I'm not quite sure this criteria is met... That's why I'm asking: do they align vertically if I use the code I posted? If they don't, what am I doing wrong?

    Thanks again
     
  10. barskey

    barskey

    Joined:
    Nov 19, 2017
    Posts:
    207
    So you're moving the other two orbs via velocity, and this one via position? Off the top of my head, you might need to rethink how you are moving all the orbs if you need them precisely aligned. How close do you need the alignment to be? Does the y position of the circular-moving orb matter if the x position aligns?
     
  11. Crembotz

    Crembotz

    Joined:
    May 12, 2018
    Posts:
    18
    Do you have any idea how to apply circular motion without manually setting the position vector?

    The y position doesn't matter and as precise as possible...
     
  12. barskey

    barskey

    Joined:
    Nov 19, 2017
    Posts:
    207
    I don't think you can calculate the time needed for the circular-moving orb based on the absolute x position of the orb since it would be a non-linear velocity. But you could calculate the time required for the center of the circle to reach a position, since it is moving with a constant speed.

    I'm just going to think out loud here as I go...

    Thinking locally, the x-position of the orb (relative to its center) is given by cos(angle). In other words, if the orb starts off to the right somewhere off the screen at 0-degrees (which is on the right edge of the circle), its distance to the rendezvous point is given by
    float dist = Mathf.Cos(startAngle) + d - Mathf.Cos(endAngle);
    knowing that as the angle goes past 90, cos becomes negative.In the picture, startAngle is zero.


    So you have the formula for the total distance, and the time you need to get there. You'll need to set an orbit speed (think orbits/sec) and a center-point x velocity (think dist/sec).

    Code (CSharp):
    1. float alignTime; // the time at which the orbs are aligned
    2. Vector3 instantiatePoint; // the instantiation position of the orbit center point
    3. float alignX; // the x-position at which the orbs align
    4. float orbitRadius = 1f; // the radius at which the orb orbits
    5. float orbitSpeed = 1f; // the number of orbits per second
    6.  
    7. float numOrbits = alignTime / orbitSpeed; // the number of orbits it will complete when intersecting
    8. float endAngle = (numOrbits % 1) * 360; // the degrees at this the final orbit intersects the align point
    9.  
    10. float dist = (instantiatePoint.x - alignX) + orbitRadius; // assuming orb starts at zero degrees, three-oclock
    11. float d = dist + Mathf.Cos (endAngle * (Mathf.PI / 180)) - Mathf.Cos (0);
    12. float centerSpeed = d / alignX; // the speed that the center point of the orbit moves
    13.  
    14. void Update ()
    15. {
    16.   float angle = orbitSpeed * Time.deltaTime * 360; // the current angle of orbit
    17.   float orbX = Mathf.Cos (angle * (Mathf.PI / 180)) * orbitRadius; // current local x position of orb
    18.   float orbY = Mathf.Sin (angle * (Mathf.PI / 180)) * orbitRadius; // current local y position of orb
    19.  
    20.   float centerDeltaX = centerSpeed * Time.deltaTime; // current change in position of orbit center
    21.  
    22.   Vector3 pos = new Vector3 (transform.position.x + centerDeltaX + orbX, orbY);
    23.   transform.position = pos;
    24. }
    25.  
    OK, that was waaay too much brain work, so I'm pretty sure I didn't get everything correct. And it's not coded in Unity, so I am not checking my work. Let me know if this helps you progress...
     
  13. Crembotz

    Crembotz

    Joined:
    May 12, 2018
    Posts:
    18
    I see, I'll ty to work something out... Thank you very much for all your help!
     
  14. barskey

    barskey

    Joined:
    Nov 19, 2017
    Posts:
    207
    Did you get this working?

    I was curious how I might do this, so I worked on it a bit in front of Unity and this is what I came up with:


    I made the orb (moon) a child object of a center point game object, and here are the scripts I used. Let me know if you want me to further explain anything if you're still working on it.
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class OrbCenter : MonoBehaviour {
    6.     public AlignPoint alignPoint; // the game object set to the random alignment point
    7.     public GameObject orb; // the orb prefab that will orbit this game object
    8.     public float orbitRadius = 0.5f; // the radius of the orbit
    9.  
    10.     private float alignX;
    11.     private float speed;
    12.     private float timeToAlign;
    13.     private Orbiter moon;
    14.  
    15.     void Start()
    16.     {
    17.         moon = Instantiate(orb, transform.position, Quaternion.identity, transform).GetComponent<Orbiter>(); // make our moon
    18.  
    19.         alignX = alignPoint.xRendezvous; // x point of alignment, from AlingPoint game object
    20.         float d = alignX - transform.position.x - moon.Offset.x; // distance to alignment point
    21.  
    22.         timeToAlign = alignPoint.timeToAlign; // for display text counting down until alignment
    23.         speed = d / alignPoint.timeToAlign; // speed at which center moves (dist / time)
    24.     }
    25.  
    26.     void Update()
    27.     {
    28.         transform.position += new Vector3(Time.deltaTime * speed, 0); // move horizontal
    29.     }
    30. }
    31.  
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Orbiter : MonoBehaviour {
    6.     public int numOrbits; // how many orbits will this complete by time of alignemnt - used to calculate orbit speed
    7.  
    8.     public float currentRadians;
    9.     private float radiansPerSecond;
    10.     private float radius;
    11.     private Vector2 offset;
    12.  
    13.     public Vector2 Offset {
    14.         get
    15.         {
    16.             return new Vector2(Mathf.Cos(currentRadians) * radius, Mathf.Sin(currentRadians) * radius);
    17.         }
    18.     }
    19.  
    20.     void Awake () {
    21.         currentRadians = Random.Range(0, Mathf.PI / 2); // randomize current (starting) angle in radians between 0 and 180 degrees. Other angles might cross alignment point twice
    22.  
    23.         radius = GetComponentInParent<OrbCenter>().orbitRadius; // distance at which to orbit
    24.  
    25.         var speed = numOrbits / GetComponentInParent<OrbCenter>().alignPoint.timeToAlign; // orbital speed in orbits/sec
    26.         radiansPerSecond = 2 * Mathf.PI * speed; // rotational speed in rads/sec
    27.     }
    28.    
    29.     void Update () {
    30.         transform.localPosition = new Vector3(Offset.x, Offset.y);
    31.         currentRadians += radiansPerSecond * Time.deltaTime;
    32.     }
    33. }
    34.  
     
  15. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    I always cheat when it comes to rotational movement. Put an empty GameObject at the center point of the circle. Then parent the circular object to the center point. Rotate the circle. And boom, perfect circular movement at whatever speed you like.
     
  16. Crembotz

    Crembotz

    Joined:
    May 12, 2018
    Posts:
    18
    First of all sorry for taking so long to respond and thank you so much for the taking the time to do all of this.
    Second, I've been trying to implement everything that you've posted here in my project, which means changing the time these commands are being executed, for example not executing them in the Awake function due to reliance on variables. For some reason, I'm unable to get the same results that you got with these changes so I gotta find some time to figure out what I'm doing cause it's really bugging me :p
    Anyway thanks again and I'll keep you posted...