One of the features I need to implement is to smoothly change the fill/stroke color of a polygon, like this:
A manual approach
In order to better understand the mechanics, I built my own fading PoC.
First, one would need to build the polygon:
hud = display.newGroup()
-- Build the text layer
score = display.newText{ text = "Level: " .. name .. " - ("
.. "11".. " groups)",
font = "scene/game/font/Mecha.ttf",
fontSize = "32" }
snap(score, "topcenter", 8)
-- Build the background
hudBG = display.newRoundedRect(score.x, score.y,
score.width+64, score.height+32,
8)
hudBG.fill = {0,0,0}
-- Build the view
hud:insert(scene.hudBG)
hud:insert(scene.score)
view:insert(hud)
In this particular case, I have a text field and a rounded rectangle beneath it. the hud
group contains both in the right order.
Once the components have been created, we build the function to be called each frame:
hudBG.iterator = 100
hudBG.lastTime = getTimer()
hudBG.enterFrame = function(self)
local curTime = getTimer()
local dt = curTime-self.lastTime
dt = dt / 1000
self.lastTime = curTime
if(self.iterator > 0) then
-- print(1.0/dt)
self.iterator = self.iterator - 1
self.fill={1-self.iterator/100.0, 0,0}
end
end
The idea is to only perform the loop once, for the first 100 frames. As you can see, the dt
velue does not yet enter into play so, the dransition from black to red is not perfectly smooth.
Now, all we need to do is to register the function with the frame event:
Runtime:addEventListener( "enterFrame", hudBG )
Once we do this, the rectangle fades from black to red in 100 frames. At 60fps, this would mean approximately 1.5 seconds.
Constant speed
As mentioned above, the speed of changing the colors is not constant. If e.g. we have a longer delay between frames, there's going to be jitter and the time in which we'll make the transition will vary. To improve this, we put dt
in play:
hudBG.iterator = 300
hudBG.duration = hudBG.iterator / 60.0 -- duration
hudBG.progress = hudBG.duration -- decreasing progress
hudBG.isActive = true
hudBG.lastTime = nil
hudBG.enterFrame = function(self)
local curTime = getTimer()
if (self.lastTime == nil) then
self.lastTime = curTime
end
local dt = curTime-self.lastTime
dt = dt / 1000
self.lastTime = curTime
if(self.duration >= 0 and self.isActive) then
self.progress = self.progress - dt
if (self.progress < 0) then
self.progress = 0
self.isActive = false
end
-- print(1.0/dt)
self.fill={1-self.progress/self.duration,0,0}
end
end
This is a bit verbose, but following components can be identified easily:
.duration
field which represents the duration in seconds at 60fps.progress
the decreasing value. It will decrease withdt
each framecurtime
and.lastTime
are used to compute thedt
(delta) between framesif (self.duration ...)
block performing:.progress
update- activation logic
- the actuall logic (changing the fill colour)
As mentioned above, this variant provides a constant speed of change and better control.
Its downside is the estra values and adding the logic of converting the dt
into something meaningful.
HTH,
Member discussion: