It is currently March 28th, 2024, 9:19 pm

Animation using .lua ?

Discuss the use of Lua in Script measures.
User avatar
kyriakos876
Posts: 919
Joined: January 30th, 2017, 2:01 am
Location: Greece

Animation using .lua ?

Post by kyriakos876 »

Hello, I was wondering if it possible to animate stuff using lua... for example:

I have this meter:

Code: Select all

[Red]
Meter=Image
SolidColor=255,0,0
X=#XVar#
Y=#YVar#
W=20
H=20
DynamicVariables=1
LeftMouseUpAction=[!CommandMeasure "MeasureLua" "Animate()"]
and this .lua script.

Code: Select all

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.
User avatar
jsmorley
Developer
Posts: 22628
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: Animation using .lua ?

Post by jsmorley »

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.
User avatar
kyriakos876
Posts: 919
Joined: January 30th, 2017, 2:01 am
Location: Greece

Re: Animation using .lua ?

Post by kyriakos876 »

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?
User avatar
balala
Rainmeter Sage
Posts: 16110
Joined: October 11th, 2010, 6:27 pm
Location: Gheorgheni, Romania

Re: Animation using .lua ?

Post by balala »

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:

Code: Select all

[Rainmeter]
Update=-1

[Variables]
Y1=0
Z1=100
U1=[!UpdateMeasure "MeasureSlide1"][!UpdateMeter "MeterMonitor"][!Redraw]
U2=[!UpdateMeasure "MeasureSlide2"][!UpdateMeter "MeterMonitor"][!Redraw]

[MeasureSlide1]
Measure=Plugin
Plugin=ActionTimer
Group=Sliders
ActionList1=Repeat Up,20,11
Up=[!SetVariable Y1 "(Clamp((#Y1#+1),0,10))"]#U1#
DynamicVariables=1

[MeasureSlide2]
Measure=Plugin
Plugin=ActionTimer
Group=Sliders
ActionList1=Repeat Up,100,21
Up=[!SetVariable Z1 "(Clamp((#Z1#-5),0,110))"]#U2#
DynamicVariables=1

[MeterMonitor]
Meter=String
X=0
Y=0
Padding=15,5,15,5
FontColor=220,220,220
SolidColor=0,0,0,150
FontSize=14
FontFace=Segoe UI
StringStyle=BOLD
StringAlign=LEFT
AntiAlias=1
Text=Y: #Y1##CRLF#Z: #Z1#
DynamicVariables=1
LeftMouseUpAction=[!CommandMeasure "MeasureSlide1" "Execute 1"][!CommandMeasure MeasureSlide2 "Execute 1"]
User avatar
kyriakos876
Posts: 919
Joined: January 30th, 2017, 2:01 am
Location: Greece

Re: Animation using .lua ?

Post by kyriakos876 »

balala wrote:Yep, it is. In such cases you have to just write a test code, to check what's going on:

Code: Select all

[Rainmeter]
Update=-1

[Variables]
Y1=0
Z1=100
U1=[!UpdateMeasure "MeasureSlide1"][!UpdateMeter "MeterMonitor"][!Redraw]
U2=[!UpdateMeasure "MeasureSlide2"][!UpdateMeter "MeterMonitor"][!Redraw]

[MeasureSlide1]
Measure=Plugin
Plugin=ActionTimer
Group=Sliders
ActionList1=Repeat Up,20,11
Up=[!SetVariable Y1 "(Clamp((#Y1#+1),0,10))"]#U1#
DynamicVariables=1

[MeasureSlide2]
Measure=Plugin
Plugin=ActionTimer
Group=Sliders
ActionList1=Repeat Up,100,21
Up=[!SetVariable Z1 "(Clamp((#Z1#-5),0,110))"]#U2#
DynamicVariables=1

[MeterMonitor]
Meter=String
X=0
Y=0
Padding=15,5,15,5
FontColor=220,220,220
SolidColor=0,0,0,150
FontSize=14
FontFace=Segoe UI
StringStyle=BOLD
StringAlign=LEFT
AntiAlias=1
Text=Y: #Y1##CRLF#Z: #Z1#
DynamicVariables=1
LeftMouseUpAction=[!CommandMeasure "MeasureSlide1" "Execute 1"][!CommandMeasure MeasureSlide2 "Execute 1"]

It needs to be in a different measure though, right?
User avatar
balala
Rainmeter Sage
Posts: 16110
Joined: October 11th, 2010, 6:27 pm
Location: Gheorgheni, Romania

Re: Animation using .lua ?

Post by balala »

kyriakos876 wrote:It needs to be in a different measure though, right?
The two actions of the ActionTimer plugin? Obviously in different measures, but I don't think this would be a problem.
User avatar
kyriakos876
Posts: 919
Joined: January 30th, 2017, 2:01 am
Location: Greece

Re: Animation using .lua ?

Post by kyriakos876 »

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 :D

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 :17good
User avatar
balala
Rainmeter Sage
Posts: 16110
Joined: October 11th, 2010, 6:27 pm
Location: Gheorgheni, Romania

Re: Animation using .lua ?

Post by balala »

kyriakos876 wrote: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.
While in most cases we do so, this isn't absolutely needed, as you can see, sometimes other approaches exist.
User avatar
khanhas
Posts: 40
Joined: October 26th, 2016, 5:00 pm

Re: Animation using .lua ?

Post by khanhas »

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:

Code: Select all

[Rainmeter]
Update=2000

[Script]
Measure = script
ScriptFile = Script.lua

[ShapeMeter]
Meter = Shape
Shape = Rectangle 0,0,300,300 | StrokeWidth 0
LeftMouseUpAction = !CommandMeasure Script "runAnimation()"

script.lua

Code: Select all

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.