@Slim, @backslider
To move entities smoothly over time (frame rate independent), you could use my Tween library.
This could be added directly into the '2DEntitySystem' if you want (if backslider is interested), or used by itself manually.
(Keep in mind this was designed for 3D, for 2D, just ignore the 'z' component.)
Also, this could be used for rotation and scale (and colour if you want).
Here's how you use it:
GLOBAL twn_player AS TTween
GLOBAL player_x%, player_y%
FUNCTION Player_TweenSet: new_x%, new_y%
LOCAL tp[] AS TTween_Point
DIM tp[2]
tp[0].Set( 0, TWEEN_TYPE_CUBIC_INOUT, player_x, player_y, 0) // Start pos
tp[1].Set(1.0, TWEEN_TYPE_CUBIC_INOUT, new_x, new_y, 0) // End pos
twn_player.New(3000, TRUE) // Total time should be 3 seconds, and Repeat this movement forever (TRUE)
twn_player.PathAdd(tp[0])
twn_player.PathAdd(tp[1])
ENDFUNCTION
FUNCTION GameLoop:
WHILE gameIsPlaying
twn_player.Update()
player_x = twn_player.value.x
player_y = twn_player.value.y
DRAWSPRITE sp_player, player_x, player_y
IF twn_player.status = TWEEN_FINISHED
// Tween has finished (but this is setup to run forever, so this will never be called in this instance)
ENDIF
WEND
ENDFUNCTION
Here's the 'Tween Path' library:
//==============================================================================
// T w e e n P a t h
//==============================================================================
//------------------------------------------------------------------ S t a t u s
CONSTANT TWEEN_OFF = 1
CONSTANT TWEEN_RUNNING = 2
CONSTANT TWEEN_FINISHED = 3
//--------------------------------------------------------- T w e e n P o i n t
TYPE TTween_Point
p AS TVector
t
transition%
FUNCTION Set: time#, transition%, x, y, z
self.t = time
self.transition = transition
self.p.Set(x, y, z)
ENDFUNCTION
FUNCTION SetV: time#, transition%, v AS TVector
self.t = time
self.transition = transition
self.p = v
ENDFUNCTION
ENDTYPE
TYPE TTween
status%
duration
time
b_autoreset% = FALSE
value AS TVector
path[] AS TTween_Point
FUNCTION New: duration, auto_reset%=FALSE
self.duration = duration
self.status = TWEEN_RUNNING
self.time = 0
self.b_autoreset = auto_reset
self.value.Set(0,0,0)
DIM self.path[0]
ENDFUNCTION
FUNCTION Start:
self.value = self.path[0].p
ENDFUNCTION
FUNCTION Reset:
self.time = 0
self.status = TWEEN_RUNNING
ENDFUNCTION
FUNCTION IsRunning%:
IF self.status = TWEEN_RUNNING THEN RETURN TRUE
RETURN FALSE
ENDFUNCTION
FUNCTION Update:
LOCAL t
LOCAL v AS TVector
IF self.status <> TWEEN_RUNNING THEN RETURN
INC self.time, _timer
IF self.time >= self.duration
IF self.b_autoreset
DEC self.time, self.duration
ELSE
self.time = self.duration
self.status = TWEEN_FINISHED
ENDIF
ENDIF
t = self.time / self.duration
IF BOUNDS(self.path[], 0) > 0
PathCalc(t)
ENDIF
ENDFUNCTION
FUNCTION PathAdd: pp AS TTween_Point
DIMPUSH self.path[], pp
ENDFUNCTION
FUNCTION PathCalc: t
LOCAL px%, ix%, jx%, p_last%
LOCAL points[] AS TVector
self.value.Set(0, 0, 0)
DIM points[4]
p_last = BOUNDS(self.path[], 0) - 1
px = -1
IF p_last = 0 THEN px = 0 // One point? Return first point
IF t = 0 THEN px = 0 // Very start? Return first point
IF t >= 1.0 THEN px = p_last // Very end? Return last point
IF px <> -1
self.value = self.path[px].p
RETURN
ENDIF
px = PathFindIndex(t)
IF px >= 0
ix = 0
FOR jx = px - 2 TO px + 1
IF jx < 0 // Index before first point? Set to first point
points[ix] = self.path[0].p
ELSEIF jx > p_last // Index beyond last point? Set to last point
points[ix] = self.path[p_last].p
ELSE // Else set to actual point
points[ix] = self.path[jx].p
ENDIF
INC ix
NEXT
TweenTransition_SetVector(self.value, points[1], points[2], self.path[px].transition, (t - self.path[px-1].t) / (self.path[px].t - self.path[px-1].t))
ELSE
self.value = self.path[0].p
ENDIF
ENDFUNCTION
FUNCTION PathFindIndex%: t
LOCAL px%
FOR px = 1 TO BOUNDS(self.path[], 0) - 1
IF self.path[px].t >= t THEN RETURN px
NEXT
RETURN BOUNDS(self.path[], 0) - 1 // Default :: Return last point
ENDFUNCTION
ENDTYPE
// TVector TYPE used above
//------------------------------------------------------------------ V e c t o r
TYPE TVector
x
y
z
FUNCTION Set%: x, y, z
self.x = x
self.y = y
self.z = z
ENDFUNCTION
ENDTYPE
And here's the 'Tween Easing' library:
//==============================================================================
// T w e e n E a s i n g
//==============================================================================
//---------------------------------------------- T r a n s i t i o n T y p e s
CONSTANT TWEEN_TYPE_LINEAR = 1
CONSTANT TWEEN_TYPE_SPRING = 2
CONSTANT TWEEN_TYPE_BOUNCE = 3
CONSTANT TWEEN_TYPE_QUAD_IN = 5
CONSTANT TWEEN_TYPE_QUAD_OUT = 6
CONSTANT TWEEN_TYPE_QUAD_INOUT = 7
CONSTANT TWEEN_TYPE_CUBIC_IN = 8
CONSTANT TWEEN_TYPE_CUBIC_OUT = 9
CONSTANT TWEEN_TYPE_CUBIC_INOUT = 10
CONSTANT TWEEN_TYPE_QUART_IN = 11
CONSTANT TWEEN_TYPE_QUART_OUT = 12
CONSTANT TWEEN_TYPE_QUART_INOUT = 13
CONSTANT TWEEN_TYPE_QUINT_IN = 14
CONSTANT TWEEN_TYPE_QUINT_OUT = 15
CONSTANT TWEEN_TYPE_QUINT_INOUT = 16
CONSTANT TWEEN_TYPE_SINE_IN = 17
CONSTANT TWEEN_TYPE_SINE_OUT = 18
CONSTANT TWEEN_TYPE_SINE_INOUT = 19
CONSTANT TWEEN_TYPE_EXPO_IN = 20
CONSTANT TWEEN_TYPE_EXPO_OUT = 21
CONSTANT TWEEN_TYPE_EXPO_INOUT = 22
CONSTANT TWEEN_TYPE_CIRC_IN = 23
CONSTANT TWEEN_TYPE_CIRC_OUT = 24
CONSTANT TWEEN_TYPE_CIRC_INOUT = 25
CONSTANT TWEEN_TYPE_BACK_IN = 26
CONSTANT TWEEN_TYPE_BACK_OUT = 27
CONSTANT TWEEN_TYPE_BACK_INOUT = 28
//============================================================================
// T R A N S I T I O N S (Easing Curves)
//============================================================================
FUNCTION Tween_Get: transition_type%, p1, p2, time
LOCAL p
SELECT transition_type
CASE TWEEN_TYPE_LINEAR; p = TweenTransition_Linear (p1, p2, time)
CASE TWEEN_TYPE_SPRING; p = TweenTransition_Spring (p1, p2, time)
CASE TWEEN_TYPE_BOUNCE; p = TweenTransition_Bounce (p1, p2, time)
CASE TWEEN_TYPE_QUAD_IN; p = TweenTransition_QuadIn (p1, p2, time)
CASE TWEEN_TYPE_QUAD_OUT; p = TweenTransition_QuadOut (p1, p2, time)
CASE TWEEN_TYPE_QUAD_INOUT; p = TweenTransition_QuadInOut (p1, p2, time)
CASE TWEEN_TYPE_CUBIC_IN; p = TweenTransition_CubicIn (p1, p2, time)
CASE TWEEN_TYPE_CUBIC_OUT; p = TweenTransition_CubicOut (p1, p2, time)
CASE TWEEN_TYPE_CUBIC_INOUT; p = TweenTransition_CubicInOut(p1, p2, time)
CASE TWEEN_TYPE_QUART_IN; p = TweenTransition_QuartIn (p1, p2, time)
CASE TWEEN_TYPE_QUART_OUT; p = TweenTransition_QuartOut (p1, p2, time)
CASE TWEEN_TYPE_QUART_INOUT; p = TweenTransition_QuartInOut(p1, p2, time)
CASE TWEEN_TYPE_QUINT_IN; p = TweenTransition_QuintIn (p1, p2, time)
CASE TWEEN_TYPE_QUINT_OUT; p = TweenTransition_QuintOut (p1, p2, time)
CASE TWEEN_TYPE_QUINT_INOUT; p = TweenTransition_QuintInOut(p1, p2, time)
CASE TWEEN_TYPE_SINE_IN; p = TweenTransition_SineIn (p1, p2, time)
CASE TWEEN_TYPE_SINE_OUT; p = TweenTransition_SineOut (p1, p2, time)
CASE TWEEN_TYPE_SINE_INOUT; p = TweenTransition_SineInOut (p1, p2, time)
CASE TWEEN_TYPE_EXPO_IN; p = TweenTransition_ExpoIn (p1, p2, time)
CASE TWEEN_TYPE_EXPO_OUT; p = TweenTransition_ExpoOut (p1, p2, time)
CASE TWEEN_TYPE_EXPO_INOUT; p = TweenTransition_ExpoInOut (p1, p2, time)
CASE TWEEN_TYPE_CIRC_IN; p = TweenTransition_CircIn (p1, p2, time)
CASE TWEEN_TYPE_CIRC_OUT; p = TweenTransition_CircOut (p1, p2, time)
CASE TWEEN_TYPE_CIRC_INOUT; p = TweenTransition_CircInOut (p1, p2, time)
CASE TWEEN_TYPE_BACK_IN; p = TweenTransition_BackIn (p1, p2, time)
CASE TWEEN_TYPE_BACK_OUT; p = TweenTransition_BackOut (p1, p2, time)
CASE TWEEN_TYPE_BACK_INOUT; p = TweenTransition_BackInOut (p1, p2, time)
ENDSELECT
RETURN p
ENDFUNCTION
FUNCTION TweenTransition_SetVector: v AS TVector, v1 AS TVector, v2 AS TVector, transition_type%, time
v.x = Tween_Get(transition_type, v1.x, v2.x, time)
v.y = Tween_Get(transition_type, v1.y, v2.y, time)
v.z = Tween_Get(transition_type, v1.z, v2.z, time)
ENDFUNCTION
// Transition :: L i n e a r
FUNCTION TweenTransition_Linear: p1, p2, t
t = Math_Clamp01(t)
RETURN p1 + ((p2 - p1) * t)
ENDFUNCTION
// Transition :: S p r i n g
FUNCTION TweenTransition_Spring: p1, p2, t
t = Math_Clamp01(t)
t = (QSIN(t * PI * (0.2 + 2.5 * t * t * t)) * POW(1.0 - t, 2.2) + t) * (1.0 + (1.2 * (1.0 - t)))
RETURN p1 + (p2 - p1) * t
ENDFUNCTION
// Transition :: B o u n c e
FUNCTION TweenTransition_Bounce: p1, p2, t
t = Math_Clamp01(t)
DEC p2, p1
IF t < (1.0 / 2.75)
RETURN p2 * (7.5625 * t * t) + p1
ELSEIF t < (2.0 / 2.75)
DEC t, (1.5 / 2.75)
RETURN p2 * (7.5625 * t * t + 0.75) + p1
ELSEIF t < (2.5 / 2.75)
DEC t, (2.25 / 2.75)
RETURN p2 * (7.5625 * t * t + 0.9375) + p1
ELSE
DEC t, (2.625 / 2.75)
RETURN p2 * (7.5625 * t * t + 0.984375) + p1
ENDIF
ENDFUNCTION
// Transition :: Q u a d
FUNCTION TweenTransition_QuadIn: p1, p2, t
t = Math_Clamp01(t)
DEC p2, p1
RETURN p2 * t * t + p1
ENDFUNCTION
FUNCTION TweenTransition_QuadOut: p1, p2, t
t = Math_Clamp01(t)
DEC p2, p1
RETURN -p2 * t * (t - 2.0) + p1
ENDFUNCTION
FUNCTION TweenTransition_QuadInOut: p1, p2, t
t = t / 0.5
DEC p2, p1
IF t < 1.0 THEN RETURN p2 / 2.0 * t * t + p1
DEC t
RETURN -p2 / 2.0 * (t * (t - 2.0) - 1.0) + p1
ENDFUNCTION
// Transition :: C u b i c
FUNCTION TweenTransition_CubicIn: p1, p2, t
t = Math_Clamp01(t)
DEC p2, p1
RETURN p2 * t * t * t + p1
ENDFUNCTION
FUNCTION TweenTransition_CubicOut: p1, p2, t
t = Math_Clamp01(t)
DEC t
DEC p2, p1
RETURN p2 * (t * t * t + 1.0) + p1
ENDFUNCTION
FUNCTION TweenTransition_CubicInOut: p1, p2, t
t = t / 0.5
DEC p2, p1
IF t < 1.0 THEN RETURN p2 / 2.0 * t * t * t + p1
DEC t, 2.0
RETURN p2 / 2.0 * (t * t * t + 2.0) + p1
ENDFUNCTION
// Transition :: Q u a r t
FUNCTION TweenTransition_QuartIn: p1, p2, t
t = Math_Clamp01(t)
DEC p2, p1
RETURN p2 * t * t * t * t + p1
ENDFUNCTION
FUNCTION TweenTransition_QuartOut: p1, p2, t
t = Math_Clamp01(t)
DEC t
DEC p2, p1
RETURN -p2 * (t * t * t * t - 1.0) + p1
ENDFUNCTION
FUNCTION TweenTransition_QuartInOut: p1, p2, t
t = t / 0.5
DEC p2, p1
IF (t < 1.0) THEN RETURN p2 / 2.0 * t * t * t * t + p1
DEC t, 2.0
RETURN -p2 / 2.0 * (t * t * t * t - 2.0) + p1
ENDFUNCTION
// Transition :: Q u i n t
FUNCTION TweenTransition_QuintIn: p1, p2, t
t = Math_Clamp01(t)
DEC p2, p1
RETURN p2 * t * t * t * t * t + p1
ENDFUNCTION
FUNCTION TweenTransition_QuintOut: p1, p2, t
t = Math_Clamp01(t)
DEC t
DEC p2, p1
RETURN p2 * (t * t * t * t * t + 1) + p1
ENDFUNCTION
FUNCTION TweenTransition_QuintInOut: p1, p2, t
t = t / 0.5
DEC p2, p1
IF (t < 1.0) THEN RETURN p2 / 2.0 * t * t * t * t * t + p1
DEC t, 2.0
RETURN p2 / 2.0 * (t * t * t * t * t + 2.0) + p1
ENDFUNCTION
// Transition :: S i n e
FUNCTION TweenTransition_SineIn: p1, p2, t
DEC p2, p1
RETURN -p2 * QCOS(t / 1.0 * (PI / 2.0)) + p2 + p1
ENDFUNCTION
FUNCTION TweenTransition_SineOut: p1, p2, t
DEC p2, p1
RETURN p2 * QSIN(t / 1.0 * (PI / 2.0)) + p1
ENDFUNCTION
FUNCTION TweenTransition_SineInOut: p1, p2, t
DEC p2, p1
//RETURN -p2 / 2.0 * (QCOS(PI * t / 1.0) - 1.0) + p1
RETURN QSIN(t * 360.0) * (p2/2.0) + p1 + (p2/2.0)
ENDFUNCTION
// Transition :: E x p o
FUNCTION TweenTransition_ExpoIn: p1, p2, t
DEC p2, p1
RETURN p2 * POW(2.0, 10.0 * (t / 1.0 - 1.0)) + p1
ENDFUNCTION
FUNCTION TweenTransition_ExpoOut: p1, p2, t
DEC p2, p1
RETURN p2 * (-POW(2.0, -10 * t / 1.0) + 1.0) + p1
ENDFUNCTION
FUNCTION TweenTransition_ExpoInOut: p1, p2, t
t = t / 0.5
DEC p2, p1
IF (t < 1.0) THEN RETURN p2 / 2.0 * POW(2.0, 10.0 * (t - 1.0)) + p1
DEC t
RETURN p2 / 2.0 * (-POW(2.0, -10.0 * t) + 2.0) + p1
ENDFUNCTION
// Transition :: C i r c
FUNCTION TweenTransition_CircIn: p1, p2, t
t = Math_Clamp01(t)
DEC p2, p1
RETURN -p2 * (SQR(1.0 - t * t) - 1.0) + p1
ENDFUNCTION
FUNCTION TweenTransition_CircOut: p1, p2, t
t = Math_Clamp01(t)
DEC t
DEC p2, p1
RETURN p2 * SQR(1.0 - t * t) + p1
ENDFUNCTION
FUNCTION TweenTransition_CircInOut: p1, p2, t
t = t / 0.5
DEC p2, p1
IF (t < 1.0) THEN RETURN -p2 / 2.0 * (SQR(1.0- t * t) - 1.0) + p1
DEC t, 2.0
RETURN p2 / 2.0 * (SQR(1.0 - t * t) + 1.0) + p1
ENDFUNCTION
// Transition :: B a c k
FUNCTION TweenTransition_BackIn: p1, p2, t
LOCAL s = 1.70158;
t = Math_Clamp01(t)
DEC p2, p1
RETURN p2 * t * t * ((s + 1.0) * t - s) + p1
ENDFUNCTION
FUNCTION TweenTransition_BackOut: p1, p2, t
LOCAL s = 1.70158
t = Math_Clamp01(t) - 1.0
DEC p2, p1
RETURN p2 * (t * t * ((s + 1) * t + s) + 1.0) + p1
ENDFUNCTION
FUNCTION TweenTransition_BackInOut: p1, p2, t
LOCAL s = 1.70158
DEC p2, p1
t = t / 0.5
IF t < 1
s = s * 1.525
RETURN p2 / 2.0 * (t * t * ((s + 1.0) * t - s)) + p1
ENDIF
DEC t, 2
s = s * 1.525
RETURN p2 / 2.0 * (t * t * ((s + 1.0) * t + s) + 2.0) + p1
ENDFUNCTION
I hope this works as cut/pasted, and I included all referenced code (such as the TVector type, etc).
I had to remove some extra code that was experimental.
This was for tweening along a *curved* path using a Cosine curve, such as:
//Beizer Curving Tween w/ Source: http://www.reflektions.com/miniml/template_permalink.asp?id=271
FUNCTION TweenTransition_Cosine: p0, p1, p2, p3, t
LOCAL a0, a1, a2, a3, t2
t2 = t * t
a0 = p3 - p2 - p0 + p1
a1 = p0 - p1 - a0
a2 = p2 - p0
a3 = p1
RETURN (a0 * t * t2 + a1 * t2 + a2 * t + a3)
ENDFUNCTION