Page 1 of 2

Moving graphical interface

Posted: Tue Oct 25, 2011 10:58 pm
by Skylark
There are a bunch of useful applications of being able to depict motion with interface elements. While I don't believe labels, gauges, and other such things were never meant to be used as such, I've tried moving them around rapidly to simulate motion. However even on a fast computer I start running into problems refreshing their position quickly enough to maintain a good illusion of motion. I was wondering if anyone had any good workarounds / knew of faster graphical API. Even something as simple as a moving rectangle would do. Thanks for reading.

Edit: Meant to stick this in a different board, my bad. While I'm at it:

Is there a way to make gauges vertical?

Re: Moving graphical interface

Posted: Wed Oct 26, 2011 12:56 am
by Oneymus
I suppose it would be most helpful to have some concrete examples of what you're trying to accomplish.

Currently, I have a package that can dynamically update the sizes of 4 (technically 5, but one's virtual) labels as I resize the Mudlet window. These labels occupy the border space surrounding the main console, calculated with every update call. It works flawlessly, and I experience no discernible, detrimental slowdown (offline testing).

Perhaps there is an issue with the manner in which you update your label positions? With more details, we can work through this.

Also, there is no other API. Are you using Geyser? Geyser wraps around the raw Mudlet API; I have not used Geyser much, but I can't imagine it would add too much overhead.

Gauges: I'm not sure if there's a pre-baked Gauge function for vertical gauges, but it's fairly simple. The trick is just in moving the gauge appropriately.
Code: [show] | [select all] lua
-- Helps to have these defined outside of the creation functions, so they can be referenced.
label = {
    x = 0,
    y = 0,
    width = 50,
    height = 100
}

-- Background. Not necessary, but looks nicer. Is static.
createLabel( "gauge_back", label.x, label.y, label.width, label.height, 1 )
setBackgroundColor( "gauge_back", 50, 50, 50, 255 )

-- This is the actual gauge. Resized.
createLabel( "gauge_front", label.x, label.y, label.width, label.height, 1 )
setBackgroundColor( "gauge_front", 200, 200, 200, 255 )

-- We create this so the text doesn't move, even as we update the size of
-- the front gauge.
createLabel( "gauge_text", label.x, label.y, label.width, label.height, 0 )
-- Make it transparent so we can see the gauges beneath.
setBackgroundColor( "gauge_text", 0, 0, 0, 0 )
-- Or however you record your stats...
echo( "gauge_text", string.format( "%d/%d", stat.current, stat.max ) )

function updateGauges ()
    local gauge_percent = stat.current / stat.max
    local new_height = label.height * gauge_percent
    local new_y = label.y + (label.height - new_height)
    -- First we resize the gauge...
    resizeWindow( "gauge_front", label.width, new_height )
    -- Now we move the window, if want it to empty downward.
    -- If you want it to empty upward, then omit the movement.
    moveWindow( "gauge_front", label.x, new_y )
    -- Echo the new stats.
    echo( "gauge_text", string.format( "%d/%d", stat.current, stat.max ) )
end
This was written off the cuff, though tested. Should be taken as educational, rather than functional. These gauges could be made prettier using Stylesheets, but this works.

Re: Moving graphical interface

Posted: Wed Oct 26, 2011 2:15 am
by Skylark
Thanks for the response. I won't be able to give you the code I used or run more tests until tomorrow when I get back to my computer, but here's what I was doing.

In IRE games there are a lot of balances being used simultaneously (salve, herb, etc). I wrote a guitar hero-esque interface that created a relationship between pixels and time (easy to understand visually). So I had a thin, wide label at the bottom of this interface that represented the present. When a balance was used (say, sipping an elixir), a label would be created a distance above the 'now' point proportional to how long it would take to regain the balance. I then used a timer to call an update function that moved the label down one increment. It became very obvious that I was getting some slowdown because the moving label was hitting the zero point significantly after it should have.

I added a counter to the timer and used it to get data on the slowdown, measuring how many times the timer managed to fire before the duration of the balance was up. If everything was working, it should have been the number I determined earlier in the script. For example, running it at 30fps, the timer was set to fire every .033ms. Over a time of 4.5 seconds it should have fired close to 135 times. However, in practice it was only updating the label's position 95-97 times in 4.5 seconds, resulting in the label being significantly out of position. I tried this technique at varying FPS, going as far down as 10fps, and while the slowdown decreased it never completely disappeared.

I did something similar with Gauges and encountered the same issue. The only difference was that I updated the gauges instead of moving them.

Re: Moving graphical interface

Posted: Wed Oct 26, 2011 2:49 am
by Vadi
What you're looking at are animations. There've been several things for that - http://www.youtube.com/watch?v=Sa0_W9AAQJI (I -think- you might find code for those on Aetolian forums), http://www.youtube.com/watch?v=SoAyIqQW2sY, and look around the forums as well. I made an animations demo somewhere that used all 3 possible methods of rendering - either using a permanent timer (I believe this was the most efficient, but I don't remember for sure - so check that animations demo and try), pre-creating tempTimers for every frame that there'll be, or using a recursive tempTimer (that creates the next in itself).

It'd be great to have something standardized and included in Mudlet by default if you can work it out.

Re: Moving graphical interface

Posted: Wed Oct 26, 2011 3:30 am
by Skylark
Sweet, thanks. I'll let you know what I come up with. My coding skills are pretty much just the result of messing around in Lua, though, so be warned that anything I produce will be pretty ungainly.

Re: Moving graphical interface

Posted: Wed Oct 26, 2011 3:36 am
by Oneymus
I tried to find those demos, Vadi. Are they on the wiki, by chance? If not, it'd be a good place for them if you find them.

Re: Moving graphical interface

Posted: Wed Oct 26, 2011 3:41 am
by Vadi
No, here on forums

Re: Moving graphical interface

Posted: Wed Oct 26, 2011 4:36 am
by Skylark

Re: Moving graphical interface

Posted: Wed Oct 26, 2011 7:14 pm
by Skylark
Alright, I didn't have nearly as much time today as I'd hoped, but I got some stuff done. I took Vadi's demo as a base and made it a little more general, creating an animateWindow() function that allows you to designate start & finish coordinates, fps, and duration. A couple issues and thoughts.

As vadi mentioned earlier, polluting the GUI is kind of an issue. Currently the function adds the permanent timers to a folder named "Animation Timers" which should keep it somewhat under control. However, I'm not sure how to create said folder without doing it manually. If you want to test it out you'll need to create the folder yourself or edit the function.

Before creating the timer, the script first checks to see if one already exists for the window you're animating. This is another step towards avoiding polluting the GUI. If you wish to animate a window in more than one way, however, IDs have to be added onto the timer names to differentiate between them. It's that or create a new timer every time you animate it, which tend to limit the function's usefulness. It'd be much easier if it was possible to delete permanent timers; we could just toss old timers and create a new one for every animation.

For now you have to manually delete the timer if you wish to run a different animation on the same window, I didn't get around to adding in a way to generate IDs.
Code: [show] | [select all] lua
function animateWindow( name, fps, duration, xInitial, yInitial, xFinal, yFinal)
	local t = {}
	t.fps, t.anim_time = fps, duration

	t.frame_count = fps * t.anim_time
	t.time_per_frame = 1/fps
	t.x_gain_per_frame = (xFinal - xInitial) / t.frame_count
	t.y_gain_per_frame = (yFinal - yInitial) / t.frame_count

	display(t)

	_G["timer_frame_" ..name] = 1
	if exists("animation timer_" ..name, "timer") == 0 then
		permTimer("animation timer_" ..name, "Animation Timers", t.time_per_frame, [[moveWindow("]] ..name .. [[",]] ..xInitial.. [[ + timer_frame_]] ..name.. [[*]] .. t.x_gain_per_frame .. [[,]] ..yInitial.. [[ + timer_frame_]] ..name.. [[*]].. t.y_gain_per_frame..[[) timer_frame_]] ..name.. [[ = timer_frame_]] ..name.. [[+1 if timer_frame_]]..name.. [[ >= ]] .. t.frame_count .. [[ then disableTimer("animation timer_]] ..name .. [[") end]])
	end
	enableTimer("animation timer_" ..name)
end
Oh, and I'm still getting slowdown. Testing by activating an animateWindow() set to 4 seconds and a simple echo timer set to the same duration shows slowdown scaling with fps; it's noticeable even at 10-20fps.

Re: Moving graphical interface

Posted: Wed Oct 26, 2011 9:00 pm
by Vadi
There is a permGroup function on recent Mudlets that allows creating folders: http://wiki.mudlet.org/w/Manual:Lua_Functions#permGroup