# How am I supposed to timestep this gravitational simulator

The following code is what I use to simulate a particles movement in a gravitational scenario.

The problem is that this simulation needs to work well on devices with different aspect ratios, and different frame rates.

Basically offscreen particles spawn in corners are shot towards the corner of the opposite side. Meanwhile each touch on the screen is a gravitational force attracting the particles to it. The simulation works fine in 30fps, however at other fps' it begins to mess up.

func gravitationalMovement()
{
var c = vv                                          //vv is simply holding the velocity I put it into c to make the code smaller, and debugging easier

let pos = Point(x: particlePosX, y: particlePosY)   //In the real code this isn't that simple but for this questions sake it is

var build = Point()
let array = TB.allFingersDown                       //An array of finger structs for each one on screen

for fing in array                                   //Go through every finger
{
let planet = fing.location
let vector = Math.subtract(pos, planet)         //Vector between particle and finger
let dist = Math.dist2Psq(vector)                //Distance squared
let theta = Math.calculateAngle(vector)

var force = 19920 / dist
let cap = Storage.bounds.tb / 50                //Height / 50
if (force > cap){force = cap}                   //Cap it off so things don't go bonkers

build.x += force * cos(theta)                   //Add the resulting velocity to the one that will hold the additive velocity
build.y += force * sin(theta)
}

c.x += build.x                                      //Add the resulting velocity from all of the fingers to the existing velocity
c.y += build.y

particlePosX += c.x                                 //Add velocity to position
particlePosY += c.y

let drag = pow(1.009, Storage.dtPercC)              //Drag the velocity
c.x /= drag
c.y /= drag

if (isInBoundsPlus() != -1)                         //If out of bounds
{
//Respawn in one of the 4 corners, and get shot out to the opposite corner
let corner = arc4random_uniform(4)              ///0-3
var p2 = Point()
if (corner == 0)
{
//Bottom left
particlePosX = 0
particlePosY = 0
p2 = Point(x: Storage.bounds.rb, y: Storage.bounds.tb)
}
else if (corner == 1)
{
//bottom right
particlePosX = Storage.bounds.rb
particlePosY = 0
p2 = Point(x: 0, y: Storage.bounds.tb)
}
else if (corner == 2)
{
//Top Left
particlePosX = Storage.bounds.lb
particlePosY = Storage.bounds.tb
p2 = Point(x: Storage.bounds.rb, y: 0)

}
else if (corner == 3)
{
//Top Right
particlePosX = Storage.bounds.rb
particlePosY = Storage.bounds.tb
p2 = Point(x: 0, y: 0)
}
let p1 = Point(x: particlePosX, y: particlePosY)

let angle = Math.calculateAngle(p1, p2) + Math.rand2(-0.01, secondNum: 0.01) //Add some variance

let ar = Storage.bounds.rb / Storage.bounds.tb                              //Multiplied by aspect ratio so that the particle has enough speed to get to other corner even if device is wide
let diagonal = (Math.dist2P(p1, p2) / 60) * ar

c.x = diagonal * cos(angle)                                                 //Set the velocity
c.y = diagonal * sin(angle)
}
vv = c                                                                          //Save the velocity to the variable vv
}


I believe the solution is to better timestep this code. I have 2 variables that will help me with this.

1. dt: probably needs no explanation but this is the time between frames
2. Storage.dtPercC: This is the dt percent, which is basically dt / (1 / 60.0). If the simulation runs at an ideal framerate this variable will be 1, however as the fps lowers that number will go up.

Yes I have checked and these number work and are accurate.

The movement is velocity based, each frame the velocity is added to position. The velocity is affected by two forces.

1. Drag
2. The additive force from the fingers
3. Bursting force when a particle spawns in a corner, it must be enough to get it to the other corner, but not too much where the particles skip around gravitation.

So far I have figured out how to make the drag force the same on all devices by doing pow(1.006, Storage.dtPerc) as a devisor to the velocity however I still have two issues.

1. The bursting time stepping, the lower the fps the less likely it is for particles to get to the other corner because of increased drag per frame
2. The velocity from the planets (fingers)

I have tried multiplying numbers by the dt percent, and pow'ing numbers to the dt percent.

My question is where in the simulation do I multiply, divide, or raise a value to the power of dt Percent? I can not figure out where and how this belongs.

• To be honest, I haven't seen the concept of dtPercent before. Usually deltatime is in miliseconds in itself already a decimal measure. What kind of value is dt in your code then? Jul 14 '16 at 8:06
• Really? It has been very useful on simpler simulations. Because let's say you want it to move 10 pixels when fps is 60. Then you just move by 10 * do dtperc. However if something happens that makes the fps 30 then dtpercent is ((1/30)/(1/60)) which is 2. And it will move 20 pixels in one frame instead. Jul 14 '16 at 8:09
• That being said I do have the traditional dt in ms stored. Feel free to use that instead in your solution. Jul 14 '16 at 8:10
• The concept of the dt already takes that into account. So if you have 60fps, dt will be 0.0166. If you run at 30 fps dt will be 0.032. So if you want to move by 10 pixels per second that equals to 10 * dt = 0.16 pixels per frame. In a 30 fps situation that equals to 0.32 pixels per frame meaning in half the number of frames the object has travelled equal distance- which means your objects are framerate independant. Jul 15 '16 at 6:51

Framerate 60 fps: dt will be 0.016 miliseconds with a framerate of 30 this value will be 0.032 miliseconds. Thus have everything based on the dt and scale your simulation units to 'x per second' and things will run framerate independant.