I'm really struggling to find any examples of Lerp usage and how to move objects around. Has anyone got good examples or point to docs that have sprites moving around utilising the lerp function?
My implementions seem to over shoot, stutter or never get there. Feels very basic so sorry for asking, but moving sprites smoothly seems like something that should be covered somewhere‽
Here's a simple implementation using a class. You can of course have this logic outside the sprite too.
You need a couple of variables:
Position before the movement.
Target position.
Normalized transition progress, aka "t".
Your class could then look something like this:
class('GamePiece', {
startPos= playdate.geometry.vector2D.new(0, 0),
targetPos = playdate.geometry.vector2D.new(0, 0),
transition = 0.0
}).extends(playdate.graphics.sprite)
GamePiece:init()
...
end
GamePiece:startMovingTo(x, y)
-- Update starting position
self.startPos.x = self.x
self.startPos.y = self.y
-- Set target
self.targetPos.x = x
self.targetPos.y = y
-- Reset transition
self.transition = 0.0
end
GamePiece:update()
-- Only advance if we haven't reached the target yet
local shouldMove = self.x ~= self.targetPos.x and self.y ~= self.targetPos.y
if shouldMove then
-- Move towards the target.
-- Note that this example will reach the destination in fixed time, but is framerate dependent.
self.transition = math.min(self.transition + 0.1, 1.0)
if self.transition >= 1.0 then
-- We have reached the target
end
-- Move the sprite.
-- You can also easily replace lerp with one of the easingFunctions.
self:moveTo(
math.lerp(self.startPos.x, self.targetPos.x, self.transition),
math.lerp(self.startPos.y, self.targetPos.y, self.transition)
)
end
end
GamePiece:draw()
...
end
You would then call e.g. knight:startMovingTo(200, 160) and the sprite would reach the new position in 10 frames.
Thanks @outgunned ! I like the class extension idea! I went a made something work well enough after I posted this and got this below. I wanted it to use deltatime.... ANDDDDDD I thought maybe timers would work... so this is what i got:
function lerp(a, b, t)
return math.ceil(a * (1 - t) + b * t)
end
-- start = {x,y}, end = {x,y}
-- return {x,y}
function lerpVector(xyStart, xyEnd, time)
return {
x = lerp(xyStart[1],xyEnd[1], time),
y = lerp(xyStart[2],xyEnd[2], time)
}
end
function lerpTimer(timer, from, to, spriteObj)
-- get new position for this frame
local newPos = lerpVector(
from,
to,
timer.value
)
-- actually move the sprite
spriteObj:moveTo(newPos.x, newPos.y)
end
local t = playdate.timer.new(1000, 0, 1, pd.easingFunctions.outQuad)
t.updateCallback = function(timer)
lerpTimer(
timer,
{ fromSprite.x, fromSprite.y },
{ toPos.x, toPos.y },
fromSprite
)
end
fromSprite.t = t
My hope was I could reuse timers to strta new movement... but would have loved the above to be much more succinct