Orbit Sim without Physics Engine

Hello, I wanted to thank all of those that help with this question.

I am attempting to make a script that changes a velocity that is tangent to orbit into X and Z velocity components. The code I am using for the X and Z velocity so far is

function Update() {
    R = Mathf.Sqrt((Mathf.Pow(X,2))+(Mathf.Pow(Z,2)));
U = U-dt*G*M*X/Mathf.Pow(R,3);
V = V-dt*G*M*Z/Mathf.Pow(R,3);
X = X+dt*U
Z = Z +dt*V

}

I am trying to make just a single question but if you need more information on what I am trying to do I will gladly give more details.

Your wording doesn't quite tell what you want. And your code is somewhat incomprehensible as posted.

Tangent to orbit? Do you mean tangent to an axis about which you are orbiting? Tangent to a sphere about which you are orbiting? X and Z velocity components relative to what coordinate space?

Velocity? I'll take your word on that. Using single letter variable names without showing what they are or where they come from is completely ambiguous, so I cannot really say for certain what your code is actually doing.

You seem to be calculating a radius with R, assuming X and Z were the difference in position between the center and the object. As you're using radius cubed you must be calculating something about a sphere's volume, but I'm not really sure what good that is doing you.

What I imagine you're trying to do

You have a sphere defined by a radius and some object at some point on this sphere. You wish to move the object about the sphere at some speeds.

Firstly, there's really no point in calculating the radius every frame if this is an actual orbit - so it can even be a set variable or something. If the radius were going to change, then either the orbit is decaying or the object does maintain an oblong spherical orbit and the problem space changes a fair amount.

To solve this problem, you need to define your axes of rotation. Trying to get only two speeds would imply that you are assuming only two axes of rotation. Be careful of gimbal lock.

Let's say we have a fixed axis and a relative axis. Let's say rotating around the center's up and the tangent right direction (Like looking at an L whose vertical is aligned with the center's up). Because we have a fixed point of reference for our relative tangent everywhere but at the poles, this can work, but when you get to the poles of your fixed reference, things get tricky.

//Let's consider our position in terms of U and V coordinates for a sphere.
//Considering this in terms of the one orbiting
var target : Transform;
var radius : float = 10;
var uSpeed : float = 0; //let's use degrees of rotation/s for simplicity
var vSpeed : float = 0; //let's use degrees of rotation/s for simplicity
private var rightAxis : Vector3;
private var forwardAxis : Vector3;

function Start() { //make sure that we're radius away from the center
    if(target) {
        transform.position = Vector3.Normalize(target.position-transform.position)*radius;
        //default tangent to the target up in case we start out looking along +/- up
        forwardAxis = target.forward;
    }
}

function Update() {
    if(target) {
        transform.RotateAround(target.position, target.up, uSpeed * Time.deltaTime);
        var forward : Vector3 = target.position - transform.position;
        if(forward != target.up && forward != -target.up) {
            forwardAxis = forward;
            Vector3.OrthoNormalize(target.up, forwardAxis, rightAxis);
        }
        else {
            //This will assume we're using the right axis from before
            //Without a point of reference, how do we know what's right?
            Vector3.OrthoNormalize(target.up, forwardAxis, rightAxis);
        }
        transform.RotateAround(target.position, rightAxis, vSpeed * Time.deltaTime);
    }
}

Using two relative axes, you have the problem of not having reference axes to orient them with initially. We need to figure out our initial axes and essentially maintain our own transform that is properly aligned with the center of the orbit for the duration of the orbit. Since the description doesn't really indicate how you would want to use it, I don't really know what to recommend as appropriate orienting axes.

Once you have decided on a way to get the axes, it would look something like:

var target : Transform;
var radius : float = 10;
var uSpeed : float = 0; //Degrees of rotation/s
var vSpeed : float = 0; //Degrees of rotation/s
private var upAxis : Vector3;
private var rightAxis : Vector3;

function Start() { //make sure that we're radius away from the center
    if(target) 
        transform.position = Vector3.Normalize(target.position-transform.position)*radius;
}

function Update() {
    if(target) {
        //Calculate the up and right axes
        transform.RotateAround(target.position, upAxis, uSpeed * Time.deltaTime);
        transform.RotateAround(target.position, rightAxis, vSpeed * Time.deltaTime);
    }
}

Also, you will need to clarify what you mean by speed. What is your unit of speed? Is it in degrees or radians about the axis (which will make all orbits using this script with the same speeds the same) or is it in world units along the surface of the sphere per second (which will make all orbits using this script with the same speeds dependent upon the radius)? Bear in mind that radians/second = (distance along the surface/second) / radius, so the conversion can be fairly simple.

What your question title says

You say you're trying to make this a single question (which may not be the best way to go, but whatever), and you title the question "orbit sim without physics engine", so I imagine that means that your description might be the smaller part of an attempt to do this without using Unity's physics engine.

The thing to consider with a physics sim is that you can have any number of bodies acting upon each other if you like. In Newtonian Physics, all bodies have gravity which is a constant force relative to the masses of two object and the distance, acting upon both objects. Let's ignore the more complex curving of space-time in general relativity as well as the general effects of magnetism for our purposes. With this Newtonian description, we can consider that everything in orbit was given an initial velocity large enough not to be pulled towards that which they orbit (decaying orbit) and yet not a velocity so large that they would leave the orbit (escape velocity). The balance of speed and gravitation in this sim which allows something to orbit is actually a fairly fine line.

Simple Newtonian gravity. Newton's 1st Law:

var fudgeFactor : float = 1; //This is the effect of gravity
private var bodies : Transform[];

function Start() {
    bodies = GameObject.FindGameObjectsWithTag("Gravitational Body");
}

//You may want to add stuff to check for nulls
function Update() {
    var forces : Vector3[] = new Array();
    //Calculate all of the forces each body has on one another
    for(i = 0; i < bodies.length - 1; i++) { //all but the last element
        var mass1 : float = bodies[j].GetComponent(massScript).mass;
        var position1 : Vector3 = bodies*.position;*
 *for(j = i + 1; j < bodies.length; j++) { //every other element*
 *var mass2 : float = bodies[j].GetComponent(massScript).mass;*
 *var direction : Vector3 = (bodies[j].position - position1);*
 *//you could do more math and/or use magnitude in stead of magnitude squared*
 _var force : float = mass1 * mass2 * fudgeFactor / direction.magnitude;_
 *direction.Normalize();*
 <em>forces _+= direction * force;_</em>
 <em>_forces[j] -= direction * force;_</em>
 _*}*_
 _*}*_
 _*for(i = 0; i < bodies.length; i++) {*_
 <em>_var script : massScript = bodies*.GetComponent(massScript);*_</em>
 <em><em>_script.gravityForce = forces*;*_</em></em>
 <em><em>_*//Some calculation will have to be done to preserve momentum still*_</em></em>
 <em><em>_*}*_</em></em>
<em><em>_*}*_</em></em>
<em><em>_*```*_</em></em>
<em><em>_*<p>massScript</p>*_</em></em>
<em><em>_*```*_</em></em>
<em><em>_*var mass : float = 1.0;*_</em></em>
<em><em>_*var gravityForce : Vecotor3;*_</em></em>
<em><em>_*function LateUpdate () {*_</em></em>
 <em><em><em>_transform.Translate(gravityForce * Time.deltaTime);_</em></em></em>
<em><em>_*}*_</em></em>
<em><em>_*```*_</em></em>
<em><em>_*<p>To simply translate the physics-based gravity script linked above, you could do something like:</p>*_</em></em>
<em><em>_*```*_</em></em>
<em><em>_*var range : float = 30.0;*_</em></em>
<em><em>_*var mass : float = 1.0;*_</em></em>
<em><em>_*var gravityForce : Vecotor3;*_</em></em>
<em><em>_*private var bodies : Transform[];*_</em></em>
<em><em>_*function Start() {*_</em></em>
 <em><em>_*bodies = GameObject.FindGameObjectsWithTag("Gravitational Body");*_</em></em>
<em><em>_*}*_</em></em>
<em><em>_*function Update () {*_</em></em>
 <em><em>_*for(var body : Transform in bodies) {*_</em></em>
 <em><em>_*if(body != transform &&*_</em></em>
 <em><em><em>_(body.position-transform.position).sqrMagnitude <= range * range) {_</em></em></em>
 <em><em>_*var offset : Vector3 = (transform.position - body.position);*_</em></em>
 <em><em>_*var mag: float = offset.magnitude;*_</em></em>
 <em><em><em>_body.gravityForce += (offset/mag/mag * mass);_</em></em></em>
 <em><em>_*}*_</em></em>
 <em><em>_*}*_</em></em>
<em><em>_*}*_</em></em>
<em><em>_*function LateUpdate () {*_</em></em>
 <em><em><em>_transform.Translate(gravityForce * mass * Time.deltaTime);_</em></em></em>
<em><em>_*}*_</em></em>
<em><em>_*```*_</em></em>
<em><em>_*<p>Note that this is pretty much the same as the one preceding it, but it only acts upon objects within radius and since it happens on every object, it needs to iterate through every other object, and it uses a slightly different equation for the forces.</p>*_</em></em>