@Luatee It is possible to get a fixed timestep in Codea… If you implement your own physics engine / integration.
Here’s an example of something which uses a fixed timestep. It’s a kind of springy line thing visually, but the code is more generic. I wrote it quite a long time ago from reading this article (so I’ve forgotten how it works exactly). I hope you find it helpful :).
--# Main
-- Timestep
-- Use this function to perform your initial setup
function setup()
integrator = RK4()
parameter.number("force_k",0,50,2)
parameter.number("force_b",0,20,0.5)
tbl = {
position=0,
velocity=0,
force = function(self,t)
local k = force_k
local b = force_b
if CurrentTouch.state == MOVING then
k = 0
end
return -k * self.position - b * self.velocity
end
}
state = integrator:createState(tbl)
prevstate = state
t = 0
dt = 0.1
time = Timestep({integrator=integrator})
txt = ""
end
-- This function gets called once every frame
function draw()
-- This sets a dark background color
background(40, 40, 50)
-- This sets the line thickness
strokeWidth(5)
-- Do your drawing here
local curstate = time:integrate(state)
txt = string.format("%.2f %.2f",curstate.position, curstate.velocity)
local y = HEIGHT/2 + curstate.position
line(0,HEIGHT/2,WIDTH/2,y)
line(WIDTH/2,y,WIDTH,HEIGHT/2)
text(txt, WIDTH/2, HEIGHT/2 + curstate.position)
end
function touched(touch)
local inc
if touch.deltaY < 0 then
-- inc = -inc
end
state.position = state.position + touch.deltaY
-- state.velocity = state.velocity + -touch.deltaY
end
--# RK4
RK4 = class()
local function newstate(state)
state = state or {}
state.position = state.position or 0.0
state.velocity = state.velocity or 0.0
state.momentum = state.momentum or 0.0
state.mass = state.mass or 0.0
state.invmass = state.invmass or 0.0
state.recalculate = function(self)
self.velocity = self.momentum * self.invmass
end
state.force = state.force or function(self,t)
local k = 10
local b = 1
return -k * self.position - b * self.velocity
end
return state
end
local function newderivative()
return { velocity=0.0, force=0.0 }
end
--http://gafferongames.com/game-physics/integration-basics/
-- float accelleration(State state, float t)
local function force(state,t)
return state:force(t)
end
local function derivative(state,t)
local value = newderivative()
value.velocity = state.velocity
value.force = force(state, t)
return value
end
--Derivative evaluate(State initial, float time, float dt, Derivative d)
local function evaluate(initial,t,dt,d)
local state = newstate()
state.position = initial.position + d.velocity * dt
state.velocity = initial.velocity + d.force * dt
state.force = initial.force
return derivative(state,t+dt)
end
local function delta(a,b,c,d)
return 1.0 / 6.0 * (a + 2.0 * (b +c) + d)
end
local function increment(v,d,dt)
return v + d * dt
end
-- void integrate(State state, float t, float dt)
local function integrate(state,t,dt)
local a,b,c,d
a = derivative(state, t)
b = evaluate(state, t, dt * 0.5, a)
c = evaluate(state, t, dt * 0.5, b)
d = evaluate(state, t, dt * 0.5, c)
local dxdt = delta(a.velocity,b.velocity,c.velocity,d.velocity)
local dvdt = delta(a.force,b.force,c.force,d.force)
state.position = increment(state.position, dxdt , dt)
state.velocity = increment(state.velocity, dvdt, dt)
end
function RK4:init()
end
function RK4:createState(state)
return newstate(state)
end
function RK4:integrate(state,t,d)
integrate(state, t, dt)
end
--# Timestep
Timestep = class()
function Timestep:init(tbl)
tbl = tbl or {}
self.integrator = tbl.integrator
self.t = 0.0
self.dt = 0.01
self.curTime = os.clock()
self.acc = 0
end
local function calculateAlpha(alpha, prevstate, curstate)
local state = integrator:createState(curstate)
state.position = state.position * alpha + prevstate.position * (1-alpha)
return state
end
function Timestep:integrate(state)
if self.integrator == nil then return end
local newtime = os.clock()
local frameTime = newtime - self.curTime
self.curTime = newtime
self.acc = self.acc + frameTime
local prevstate = state
while self.acc >= self.dt do
prevstate = self.integrator:createState(state)
self.integrator:integrate(state,t,dt)
self.acc = self.acc - self.dt
self.t = self.t + self.dt
end
local alpha = self.acc / self.dt
return calculateAlpha(alpha,prevstate,state)
end