function Animate()
for i = 1, 100 do
SKIN:Bang(string.format('!WriteKeyValue Variables XVar "%s"', i))
SKIN:Bang('!Update')
SKIN:Bang('!Redraw')
end
end
This obviously doesn't work because it's doing the for loop with no delay between passes. I saw this note in the docs as well Note: The !Delay bang in Rainmeter is not supported in Lua. and not being Master in lua, I'm not sure how to approach this, or even if it's possible to begin with.
I want to do this because I can't have 2 ActionTimer lists running in the same time, and in a skin I'm working with this needs to be possible. I've managed to find some ghetto alternative that works, but I don't like it and I was hoping to make it simpler.
There is really no way to do animations in Lua, since the way Lua works with Rainmeter is that Rainmeter in effect passes control over to the Lua script, which is executed in full and then returns control back to Rainmeter. So anything you do in a Lua script will happen in the course of one update of the Lua measure. For example, if you change the value of something in Rainmeter from 0 to 1 to 2 to 3 in a loop in Lua, Rainmeter will see all of the changes, but all at once. All you will see is that the value is 3. Another example is to use Lua to move a meter from X=20 to 21 to 22 in a loop in Lua. All the skin will see is that X=22.
That is why any kind of "sleep" you try to put into a loop can only do harm by "blocking" and delaying the return to Rainmeter, while not bringing any benefit at all. Any skin updates or redraws or anything else that you do in a loop will be stacked up by the Lua, with the skin simply frozen and waiting, and then all executed at once, when control is returned to the skin. Rainmeter can do 100 "redraws" very quickly indeed, but the first 99 of them are a waste of resources.
The long and the short of it is that the only way to to animations in Rainmeter is to either set a very low Update rate on the skin, so the skin cycles through the update loop very quickly, or to use the ActionTimer plugin to force certain things to happen faster than the overall skin update rate.
That's not to say that Lua can't play a role in animations, as you could have an ActionTimer measure that hammers !UpdateMeasure at a Lua measure very quickly, or uses Inline Lua section variables, to have the Lua do some value-added processing you need on each logical "frame" of the animation. But the control of the animation, the rate at which things happen, must be managed by Rainmeter, not Lua.
Oh so you can't animate with lua alone, but you can use lua to help... I see... This doesn't solve my problem though, it being that I can't have more than 1 ActionTimer list running the same time in the same config. Is this impossible with today's capabilities of Rainmeter?
kyriakos876 wrote:Oh so you can't animate with lua alone, but you can use lua to help... I see... This doesn't solve my problem though, it being that I can't have more than 1 ActionTimer list running the same time in the same config. Is this impossible with today's capabilities of Rainmeter?
Yep, it is. In such cases you have to just write a test code, to check what's going on:
balala wrote:The two actions of the ActionTimer plugin? Obviously in different measures, but I don't think this would be a problem.
Well yea... some things are obvious to some, while unknown to others
I always used to pack every ActionList in the same measure until now that I needed to have more than one List play at the same time. Thanks! That saved me a lot of mess
Here is my approach using !Delay bang and Lua. It doesn't require low Update or using ActionTimer but still achieves smooth animation.
The trick is recursively calling animation run function but via !CommandMeasure bang after a !Delay bang. By doing this way, Rainmeter could wait amount of time then calculate and set new value for meter.
Skin INI:
local timing = 0
local maxTime = 50
function runAnimation()
timing = timing + 1
if (timing > 0 and timing < maxTime) then
-- You can apply any animation easing function.
-- Here I'm using sin function:
local factor = math.sin(timing / maxTime * math.pi /2)
-- Moving right 300px:
SKIN:Bang("!SetOption", "ShapeMeter", "X", factor * 300)
SKIN:Bang("!UpdateMeter", "ShapeMeter")
SKIN:Bang("!Redraw")
-- Call runAnimation via bang after a delay:
SKIN:Bang('[!Delay 8][!CommandMeasure Script "runAnimation()"]')
else
timing = 0
end
end
Here is just a simple example that moves only one meter. If you're planing on using it on various meters, do rewrite it more universally for all meters and options. And only calls !UpdateMeter one time per meter and !Redraw one time per chain of animation.