0

I am new to unity and am trying to understand how the code works but am having a problem with my simple project.

I have a Star and a Planet. The planet is a child of the Star like so:

Star¬
   Planet

I added a component C# script to Planet that is meant to make it rotate around the Star. But when i press play the planet is not moving.

This is my script:

using UnityEngine;
using System.Collections;

public class Orbit : MonoBehaviour {

    public float rotateSpeed = 5.0f;
    public float orbitSpeed  = 1.0f;

    private Vector3 pos;

    void Start(){
        //get parent object position
        pos = transform.root.gameOject;
    }

    void Update() {
        // planet to spin on it's own axis
        transform.Rotate (transform.up * rotateSpeed * Time.deltaTime);

        // planet to travel along a path that rotates around the sun
        transform.RotateAround (pos, Vector3.up, orbitSpeed * Time.deltaTime);
    }
}

I am not sure what my mistake is. And am hoping some one can help.

Side question, given i want to eventually have more than one planet, is it efficient to have a component script for every individual planet to rotate or is there a more automative way to do it such as iterate through all the planets in one go?

Unit Version 5.3.2f1

WDUK
  • 1,412
  • 1
  • 12
  • 29
  • simply rotate the star do nothing to the child planet. it will move around. if you want the star to be stationary... simply have an invisible marker called "CenterOfTheSolarSystem", and make the planet a child of that. then simply rotate CenterOfTheSolarSystem and the planet will orbit nicely. regarding the Sun, simply do not make it a child of CenterOfTheSolarSystem, if you want it to not rotate. that's all there is to it – Fattie Apr 04 '16 at 12:10
  • Thats only useful for perfect circles, its far removed from a realistic orbit around a star – WDUK Apr 04 '16 at 19:09
  • at the scale of a computer screen a planetary orbit is precisely circular. as i already explained to you if you additionally want it to go in and out (to show unrealistically exaggerated elliptical motion on that scale) just add another transform for that. or of course, just calculate the position and do it kinematically, not using unity's built-in quaternions – Fattie Apr 04 '16 at 19:33
  • What do you mean by add another transform ? Do you mean move the origin of the orbit so the orbit isn't totally circular? – WDUK Apr 04 '16 at 21:47
  • simply move the "arm" in and out – Fattie Apr 04 '16 at 23:25
  • I can see a difficulty in drawing a line for this orbit using line renderer over using maths. – WDUK Apr 04 '16 at 23:50
  • `LineRenderer` will not help you at all here, I don't think. Drawing lines or any flat feature in Unity is exceptionally difficult. Almost everyone uses **Vectrosity**, you'll probably need to try that – Fattie Apr 05 '16 at 11:53

2 Answers2

4

You should consider oscillation. Whether you use sin or cos does not really matter somehow. You will get the same shape but one will start at 0 as sin(0) = 0 and the other starts at 1 as cos(0) = 1.

One nice feature of sin and cos is that the result is lerping and clamped between -1 and 1. We can get a variable that will constantly go from 1 to -1 and back to 1 and so on.

The following is entirely based on basic trigonometry and unit circle

void Update () 
{
        transform.localPosition= new Vector3(Mathf.Cos (Time.time ),0,Mathf.Sin (Time.time));
}

this is based on the trig equation:

x = cos(2 * pi * k + t)
y = sin(2 * pi * k + t)

The 2 * PI * k part is shorten to Time.time, result is the same, you would only need those for extra precision if you were to reproduce a real situation.

Other case you want to use the full equation is if you need to control the time it takes for a revolution:

 private float twoPi = Mathf.PI * 2f;
 void Update () 
{
        transform.localPosition= new Vector3(Mathf.Cos (twoPi * Time.time ),0,Mathf.Sin (twoPi * Time.time));
}

This will take 1sec to do the full revolution.

When you use Cos for one, you have to use Sin for the other or your object will not spin around the parent.

You can add distance to spread the planet apart from the star:

private float twoPi = Mathf.PI * 2f;
[SerializeField]private float amplitude = 2.0f;
void Update()
{
    float x = amplitude * Mathf.Cos (twoPi * Time.time );
    float z = amplitude * Mathf.Sin (twoPi * Time.time );
    transform.localPosition= new Vector3(x,0,z);
}

All spinning items will rotate at the same frequency of 1 so you should be able to provide different frequencies to each planet:

private float twoPi = Mathf.PI * 2f;
[SerializeField]private float amplitude = 2.0f;
[SerializeField]private float frequency = 2.0f;
void Update()
{
    float x = amplitude * Mathf.Cos (twoPi * Time.time * frequency);
    float z = amplitude * Mathf.Sin (twoPi * Time.time * frequency);
    transform.localPosition= new Vector3(x,0,z);
}

if you give different frequencies to x and z within the same object, the child will not spin entirely around but will have a horseshoe shape. Frequency could be assimilated to speed as it will define how fast one full revolution is performed.

You can then fully control the period (this is the math term for speed), a period is the time between two peaks on the sinusoidal (the movement can be flattened to a sinusoidal, two actually, x and z). The relation between frequency and period is

frequency = 1 / period;

So the greater the frequency, the shorter the period. If you want your revolution to take 2sec => frequency = 1 / 2 => 0.5. If you need 2 minutes, frequency is always in seconds so 120sec => frequency = 1 / 120 = 0.0083f;

All your planet will rotate at the same position around the star, that is they will all start from left or right so you can apply a phase. This is the k from the initial equation and it is not multiplied but added:

private float twoPi = Mathf.PI * 2f;
[SerializeField] private float amplitude = 2.0f;
[SerializeField] private float periodInSec = 120;
private float frequency = 2.0f;
[SerializeField] private float phase = 0.5f;

void Start()
{
    frequency = 1 / periodInSec;
}
void Update()
{
    float x = amplitude * Mathf.Cos (twoPi * Time.time * frequency + phase);
    float z = amplitude * Mathf.Sin (twoPi * Time.time * frequency + phase);
    transform.localPosition= new Vector3(x,0,z);
}

And if you need to provide an elliptic shape (which is the case of most astres), you simply give a different amplitude to x and z:

[SerializeField]private float amplitudeX = 2.0f;
[SerializeField]private float amplitudeZ = 3.0f;
[SerializeField] private float periodInSec = 120;
private float frequency = 2.0f;
[SerializeField] private float phase = 0.5f;
void Start()
{
    frequency = 1 / periodInSec;
}
void Update()
{
    float x = amplitudeX * Mathf.Cos (twoPi * Time.time * frequency + phase);
    float z = amplitudeZ * Mathf.Sin (twoPi * Time.time * frequency + phase);
    transform.localPosition= new Vector3(x,0,z);
}

If you need to have many planets around one star and you want the planet to move on all three axis. That is, one spin "flat" while another one spin with a rotation, the easiest is to make the planet a child of a star child.

-Star
    -Container
        -Earth
    -Container
        -March

The containers are at (0,0,0) and you can give each container a different rotation and the child planet will rotate on its own ellipse around the star. Just make sure they don't collide, billions of lives at stake.

Everts
  • 10,408
  • 2
  • 34
  • 45
  • Thanks for this, this will take some time to digest. I am curious though if i wanted a system where you set a time for 1 full orbit, say i wanted a object to take 2 minutes to rotate can this be factored in to your approach ? – WDUK Mar 09 '16 at 20:36
  • I would suggest to read it again, I added details on your issue. – Everts Mar 09 '16 at 20:59
  • Thank you i will test around with this in unity and see how it goes ! :) – WDUK Mar 09 '16 at 21:43
-1

public Vector3 pos and then Drag the Star in the Inspector. much easier.

Aizen
  • 1,807
  • 2
  • 14
  • 28