- Home /
Moving in a circle around a parent
Ok so what I am trying to do is make my object transform in a circle around it's parent, I don't need the object doing it to route and if possible I don't want it to route at all. Is there way to change my current code below so it will use it's parent as the centre of the circle. I am using unity 2D. Also please be as simple as possible and explain step by step so I can understand what is happening and why.
using UnityEngine;
using System.Collections;
public class circular : MonoBehaviour {
public float radius = 2f; //Distance from the center of the circle to the edge
public float currentAngle= 0f; //Our angle, this public for debugging purposes
private float speed = 0f; //Rate at which we'll move around the circumference of the circle
public float timeToCompleteCircle = 1.5f; //Time it takes to complete a full circle
// Use this for initialization
void Start () {
}
void Awake(){
speed = (Mathf.PI * 2) / timeToCompleteCircle;
}
// Update is called once per frame
void Update () {
speed = (Mathf.PI * 2) / timeToCompleteCircle; //For level design purposes
currentAngle += Time.deltaTime * speed; //Changes the angle
float newX = radius * Mathf.Cos (currentAngle);
float newY = radius * Mathf.Sin (currentAngle);
transform.position = new Vector3 (newX, newY, transform.position.z);
}
}
Answer by Harinezumi · Apr 13, 2018 at 11:48 AM
You can do 2 things: either use transform.localPosition
, or add transform.parent.position
to the calculation. Something like this:
// first approach
transform.localPosition = new Vector3(newX, newY, 0);
// local position is relative to the parent, so it will always move around the parent, and you don't even have to modify z
// note that if the parent rotates, this object will also rotate with it!
// second approach
Vector3 newPosition = transform.parent.position + new Vector3(newX, newY, 0);
newPosition.z = transform.position.z; // if you want to keep the same world space z position...
transform.position = newPosition;
// world space position is absolute, so it will ignore some rotations of the parent
EDIT: In case you want multiple objects to circle around another one, dividing the circle into equal parts, you can do the following:
// put this script on the object around which other objects orbit
public class OrbitParent : MonoBehaviour {
[SerializeField] private Orbiter orbiterPrefab = null; // assign to this a prefab of your object that will orbit
[SerializeField] private float orbitingSpeed = 1; // number of circles per second an orbiting object makes
private List<Orbiter> orbiters = new List<Orbiter>();
private float elapsedTime = 0;
private void Update () {
elapsedTime += Time.deltaTime;
float currentAngle = orbitingSpeed * elapsedTime;
for (int i = 0; i < orbiters.Count; ++i) {
orbiters[i].UpdateOrbit(currentAngle, i, orbiters.Count);
}
}
public void AddOrbiter () {
Orbiter newOrbiter = Instantiate(orbiterPrefab, transform); // create new orbiting object as child of this object
orbiters.Add(newOrbiter); // store orbiter so it can be updated
}
public void RemoveOrbiter () {
Orbiter lastOrbiter = orbiters[orbiters.Count - 1];
orbiters.RemoveAt(orbiters.Count - 1];
Destroy(lastOrbiter.gameObject);
}
}
// put this script on the orbiting object prefab
public class Orbiter : MonoBehaviour {
public void UpdateOrbiter(float baseAngle, int index, int total) {
float currentAngle = baseAngle + (index / (total - 1.0f) * 2 * Mathf.PI;
float x = Mathf.Cos(currentAngle);
float y = Mathf.Sin(currentAngle);
transform.localPosition = new Vector3(x, y, 0);
}
}
Thank you so much I can't believe how hard it was just get such a simple answer, thank you.
If it's alright I have a few other things to ask I checked both of them and the second approach does the same thing, but the radius of the circle is bigger is that just because it is on the world space and not local?
And second what would I do if I have multiple children as they all start in the same position and move together so there is no difference regardless of how many. Is there a way for me to make it so all children start off in different positions relevant to each other.
I'm glad I could help.
For the questions, I believe in the second case gives you a different radius, because the parent has a scale different from (1, 1, 1) - the scale of the parent modifies the local position. (But I'm not 100% sure this is the cause, it might be something else).
About the various objects to start at positions relative to each other, if I understand it correctly, you would like them to be divided equally along the circle. In this case, add 2 * $$anonymous$$athf.PI / (indexOfObject / (numberOfObjects - 1.0f)
to the currentAngle
of each object.
But you will have to update the time for all the objects together, otherwise they will start to not keep the distance. So one thing you can do is that the object that spawns the circling objects keeps the time ( currentTime += Time.deltaTime * speed
) and the number of circling objects, and the circling objects get the currentTime
and the number of objects from it, so they get automatically updated. Something like this:
currentAngle = controller.GetCurrentTime() + 2 * $$anonymous$$athf.PI * (myIndex / controller.GetNumberOfCirclingObjects() - 1.0f);
The controller should also assign to each object its index. Also note that currentTime
is actually not time, but a base angle, and speed
is angular speed.
Yeah you are right about the scaling the change happens because my scaling is set to 0.5.
As for the rest you are right about that being what I want and please bear with me to make sure I got it right.
So currentAngle which was currentAngle += Time.deltaTime * speed;
becomes Time.deltaTime * speed 2 * $$anonymous$$athf.PI / (indexOfObject / (numberOfObjects - 1.0f)
Though I need to add something in between the speed and 2, or replace the speed with the 2. Also there are an odd number of brackets that give me the unexpected symbol error.
The next bit I am more confused about by controller do you mean to make a another script with a index/list that spawns/stores the objects like this public GameObject[] Index;
and then applies a currentTime
variable. I get it, but I just can't seem to figure out where I should put it in my code and what order.
Sorry my knowledge of coding structure is just horrible, from what I can understand your telling me to store the objects into an index where currentTime is applied to each this makes it so they update together moving from there starting positions while keeping a set distance apart and all this is done by a a new controller script. Is my interpretation of what is being said.
I've tried adding in the code you put, but I am obviously missing something as it just gives me errors.
Great solution. Do you know how I would go about increasing the radius or distance from the transform to rotate around?
Just multiply the Vector3 with a float radius value just before assigning it.