WoWInterface

WoWInterface (http://www.wowinterface.com/forums/index.php)
-   Graphics Help (http://www.wowinterface.com/forums/forumdisplay.php?f=14)
-   -   "Pulsating" effect...what's the proper method? (http://www.wowinterface.com/forums/showthread.php?t=30271)

Amenity 01-26-10 01:51 PM

"Pulsating" effect...what's the proper method?
 
I have frame "frame". I want it to fade from alpha "1" to alpha "0", then back to alpha "1" and repeat until I say otherwise to make a "pulsing" effect.

I tried doing this in a manner like so, and...well...yeah, infinite loops are bad.

lua Code:
  1. while myvariable = 1 do
  2.     alpha = frame:GetAlpha()
  3.     if alpha = 1 then
  4.         UIFrameFadeOut(frame, 1, 1, 0)
  5.     elseif alpha = 0 then
  6.         UIFrameFadeIn(frame, 1, 0, 1)

Hello, Mr. Client Crash. :o

d87 01-26-10 01:58 PM

Code:

local SHINE_FADE_IN = 0.15;
local SHINE_FADE_OUT = 0.15;
local TICK_PERIOD = 0.35;

local ShineFadeOut = function(frame)
    local fadeInfo = {};
        fadeInfo.mode = "OUT";
        fadeInfo.timeToFade = SHINE_FADE_OUT;
        fadeInfo.finishedFunc = function(self) self.animating = false end;
        fadeInfo.finishedArg1 = frame;
    UIFrameFade(frame, fadeInfo);
end
local ShineFadeIn = function(frame)
    if not frame.animating then
        local fadeInfo = {};
        fadeInfo.mode = "IN";
        fadeInfo.timeToFade = SHINE_FADE_IN;
        fadeInfo.finishedFunc = function(arg1) ShineFadeOut(arg1); end;
        fadeInfo.finishedArg1 = frame;
        frame.animating = true
        UIFrameFade(frame, fadeInfo);
    end
end

f.Shine = function(self)
        ShineFadeIn(self.shinetex)
    end

f.OnUpdate = function (self, time)
        self.OnUpdateCounter = (self.OnUpdateCounter or 0) + time
        if self.OnUpdateCounter < TICK_PERIOD then return end
        self.OnUpdateCounter = 0
       
        self:Shine()
    end


Xrystal 01-26-10 02:00 PM

Well did a quick search and there isn't much around on that subject so perhaps they hit a wall.

So far all I have seen is people utilising it on Enter and Leave scripts to do the different Fading functions. So how about this.

If you have an Update function that you call every so often perhaps you can put it in there to fadein if it has faded out or to fade out if it has faded in. Then keep a variable to store the last value updated. It's not perfect but might be the only way you can deal with it and even throwing the cycle in every event you watch may be a good idea too. The combination of the two functions may be enough to make it look passable at least.


Edit: Or what d87 said :D

nightcracker 01-26-10 02:16 PM

Pretty elegant IMO:
lua Code:
  1. frame.mult = 1
  2. frame.alpha = 1
  3. frame:SetScript("OnUpdate", function(self, elapsed)
  4.     self:SetAlpha(self.alpha)
  5.     self.alpha = self.alpha - elapsed*self.mult
  6.     if self.alpha < 0 and self.mult > 0 then
  7.         self.mult = self.mult*-1
  8.         self.alpha = 0
  9.     elseif self.alpha > 1 and frame.mult < 1 then
  10.         self.mult = self.mult*-1
  11.     end
  12. end)

Xrystal 01-26-10 02:32 PM

*book marks post so I can come back and ste... erm I mean utilise the code* :D

Quote:

Originally Posted by nightcracker (Post 176200)
Pretty elegant IMO:
lua Code:
  1. frame.mult = 1
  2. frame.alpha = 1
  3. frame:SetScript("OnUpdate", function(self, elapsed)
  4.     self:SetAlpha(self.alpha)
  5.     self.alpha = self.alpha - elapsed*self.mult
  6.     if self.alpha < 0 and self.mult > 0 then
  7.         self.mult = self.mult*-1
  8.         self.alpha = 0
  9.     elseif self.alpha > 1 and frame.mult < 1 then
  10.         self.mult = self.mult*-1
  11.     end
  12. end)


Torhal 01-26-10 02:39 PM

You'll want to hide the frame doing the OnUpdate when it's done, else you'll be needlessly using CPU.

nightcracker 01-26-10 02:42 PM

Quote:

Originally Posted by Xrystal (Post 176203)
*book marks post so I can come back and ste... erm I mean utilise the code* :D

Feel free to use it(I'm pretty amazed I came up with the mult*-1 trick lol).

Amenity 01-26-10 02:46 PM

Quote:

Originally Posted by nightcracker (Post 176205)
Feel free to use it(I'm pretty amazed I came up with the mult*-1 trick lol).

Wow guys...thank you for the quick responses! Working perfectly now. :)

(Also bookmarking as a reference page)

nightcracker 01-26-10 02:55 PM

Quote:

Originally Posted by Amenity (Post 176206)
Wow guys...thank you for the quick responses! Working perfectly now. :)

(Also bookmarking as a reference page)

If this is going to be a reference, then I'll add something new, a variable to determine speed of the pulse in seconds(don't set it to 0, dividing by 0 FTW):

lua Code:
  1. local speed = 1
  2. frame.mult = 1
  3. frame.alpha = 1
  4. frame:SetScript("OnUpdate", function(self, elapsed)
  5.     elapsed = elapsed*(1/speed)
  6.     self:SetAlpha(self.alpha)
  7.     self.alpha = self.alpha - elapsed*self.mult
  8.     if self.alpha < 0 and self.mult > 0 then
  9.         self.mult = self.mult*-1
  10.         self.alpha = 0
  11.     elseif self.alpha > 1 and frame.mult < 1 then
  12.         self.mult = self.mult*-1
  13.     end
  14. end)

Amenity 01-26-10 03:08 PM

Quote:

Originally Posted by Torhal (Post 176204)
You'll want to hide the frame doing the OnUpdate when it's done, else you'll be needlessly using CPU.

Just as a quick test, I set it to pulse my Minimap (lulz) and it's using so little CPU time that it could simply just be an error. By comparison, the tool I used to measure this used 24 times as much CPU time as the pulse addon. :eek:

Quote:

Originally Posted by nightcracker (Post 176208)
If this is going to be a reference, then I'll add something new, a variable to determine speed of the pulse in seconds(don't set it to 0, dividing by 0 FTW):

lua Code:
  1. local speed = 1
  2. frame.mult = 1
  3. frame.alpha = 1
  4. frame:SetScript("OnUpdate", function(self, elapsed)
  5.     elapsed = elapsed*(1/speed)
  6.     self:SetAlpha(self.alpha)
  7.     self.alpha = self.alpha - elapsed*self.mult
  8.     if self.alpha < 0 and self.mult > 0 then
  9.         self.mult = self.mult*-1
  10.         self.alpha = 0
  11.     elseif self.alpha > 1 and frame.mult < 1 then
  12.         self.mult = self.mult*-1
  13.     end
  14. end)

Hm, I'll have to give that a go. In the previous incarnation, I was just adjusting the value of frame.mult to adjust the speed.

nightcracker 01-26-10 03:28 PM

Quote:

Originally Posted by Amenity (Post 176212)
Just as a quick test, I set it to pulse my Minimap (lulz) and it's using so little CPU time that it could simply just be an error. By comparison, the tool I used to measure this used 24 times as much CPU time as the pulse addon. :eek:



Hm, I'll have to give that a go. In the previous incarnation, I was just adjusting the value of frame.mult to adjust the speed.

Woops, I actually made a mistake in the script, and you are right, it should be enough to change frame.mult.

FINAL VERSION(I hope):

lua Code:
  1. frame.mult = 1
  2. frame.alpha = 1
  3. frame:SetScript("OnUpdate", function(self, elapsed)
  4.     self:SetAlpha(self.alpha)
  5.     self.alpha = self.alpha - elapsed*self.mult
  6.     if self.alpha < 0 and self.mult > 0 then
  7.         self.mult = self.mult*-1
  8.         self.alpha = 0
  9.     elseif self.alpha > 1 and self.mult < 0 then
  10.         self.mult = self.mult*-1
  11.     end
  12. end)

Torhal 01-26-10 05:44 PM

Quote:

Originally Posted by Amenity (Post 176212)
Just as a quick test, I set it to pulse my Minimap (lulz) and it's using so little CPU time that it could simply just be an error. By comparison, the tool I used to measure this used 24 times as much CPU time as the pulse addon. :eek:
<snip>

Profilers will use a huge amount of CPU because of everything they have to do for measuring every AddOn you're running.

Anyway: Saying "it's using so little CPU" and then ignoring that is rather dismissive - people running 200+ AddOns which do this are suddenly using a metric ****-ton of CPU for no reason whatsoever. If you aren't currently generating a pulse, the frame should be hidden so its OnUpdate will not be run.

Amenity 01-26-10 06:13 PM

Quote:

Originally Posted by Torhal (Post 176232)
Profilers will use a huge amount of CPU because of everything they have to do for measuring every AddOn you're running.

Well, yeah. Just using it as a frame of reference.

Quote:

Anyway: Saying "it's using so little CPU" and then ignoring that is rather dismissive - people running 200+ AddOns which do this are suddenly using a metric ****-ton of CPU for no reason whatsoever. If you aren't currently generating a pulse, the frame should be hidden so its OnUpdate will not be run.
I agree that this is good coding practice, yes. My point is that for 99% of the people out there, having a frame that pulses indefinitely is not going to be an issue (as is the intent of my usage).

**EDIT:

Just discovered something while we're on the topic of performance that I thought should be part of this:

You can set this thing to absolutely ridiculous speeds (I've personally tried it up to 150, WELL beyond my refresh rate, just to see what would happen). The only upper limit here is your computers' crash threshold. BE CAREFUL WHEN DOING THIS. The reason it was/is using so little CPU is because apparently Blizz uses GPU time for this. On my machine at 1440x900, Ultra settings w/ some cVar tweaks, fullscreen windowed, and a frame pulsing at 150, I hit around 50%-ish GPU usage on average (peak no higher than 65%) with dual 5700-series ATis.

At any "normal" speed (say, 0.3 to 10.0 at the fastest) it's negligible, though. I'm also pulsing a pretty big frame (1024x256). Really, if you need something faster than 10...don't. You're gonna give kids seizures.

zork 02-05-10 08:27 AM

Check blackbox (http://wow.curseforge.com/addons/blackboxlua/)

You may want to look at the animation system.

Blizzard uses this kind of stuff for the Glyph window.

http://wowprogramming.com/utils/xmlb...rd_GlyphUI.lua

Look out for "PulseGlow".

The cool stuff is that you can "PLAY" and "STOP" those animations as you wish.

I cannot recommend onUpdate stuff anymore, the animations are much more valuable imo since they eat nearly no cpu usage instead of those nasty onupdates.

I'm using the animation system for rFrameRotater. Since you can "LOOP" animations it will start and never stop. (If you say so.)

Very simple rotate-function that I'm using to rotate stuff.
Code:

  function a:rotateme(texture,width,height,scale,anchorframe,framelevel,texr,texg,texb,alpha,duration,side,blendmode,point,pointx,pointy)

    local h = CreateFrame("Frame",nil,anchorframe)
    h:SetHeight(height)
    h:SetWidth(width)           
    h:SetPoint(point,pointx,pointy)
    h:SetScale(scale)
    h:SetFrameLevel(framelevel)
 
    local t = h:CreateTexture()
    t:SetAllPoints(h)
    t:SetTexture("Interface\\AddOns\\rFramerotater\\media\\"..texture)
    t:SetBlendMode(blendmode)
    t:SetVertexColor(texr,texg,texb,alpha)
    h.t = t
   
    local ag = h:CreateAnimationGroup()
    h.ag = ag
   
    local a1 = h.ag:CreateAnimation("Rotation")
    if side == 0 then
      a1:SetDegrees(360)
    else
      a1:SetDegrees(-360)
    end
    a1:SetDuration(duration)
    h.ag.a1 = a1
   
    h.ag:Play()
    h.ag:SetLooping("REPEAT") 

  end


So sth. like this could be it, don't know the exact syntax

http://wowprogramming.com/docs/widgets/Alpha/SetChange

Code:

    local h = CreateFrame("Frame",nil,UIParent)
    h:SetHeight(100)
    h:SetWidth(100)           
    h:SetPoint("CENTER",0,0)
    h:SetScale(1)
    h:SetFrameLevel(1)
 
    local t = h:CreateTexture()
    t:SetAllPoints(h)
    t:SetTexture(1,1,1,1)
    h.t = t

    local ag = h:CreateAnimationGroup()
    h.ag = ag
   
    local a1 = h.ag:CreateAnimation("Alpha")
    --go from 1 to 0
    a1:SetChange(-1)
    a1:SetDuration(5)

    local a2 = h.ag:CreateAnimation("Alpha")
    --go from 0 to 1
    a2:SetChange(1)
    a2:SetDuration(5)

    h.ag.a1 = a1
    h.ag.a2 = a2
   
    h.ag:Play()
    h.ag:SetLooping("REPEAT")

how can this lua code stuff be done?

With the animation system you can do this in just one animationgroup.

- move (translate)
- rotate
- scale
- change alpha

You can even add a path the frame will move on.

Xrystal 02-05-10 10:28 AM

Cool, I was wondering the use for animation barring prettifying movement around the screen. But if it's the better option than onUpdate it may be the way to go.

Nemnacill 02-05-10 11:01 AM

I'm not sure about how it would work in lua, but any pulsating effect can be achieved with a simple sinus function.

pseudo code:
var sequence = 0;
sequence ++;
AlphaProperty = sin(sequence);

this would result in the AlphaProperty going from 0 to 1, then from 1 to 0 and so on. google 'math sin lua' for more info :)

Good luck

Hati-EK 02-05-10 12:01 PM

http://www.wowwiki.com/API_UIFrameFlash

UIFrameFlash(frame, fadeInTime, fadeOutTime, flashDuration, showWhenDone, flashInHoldTime, flashOutHoldTime)

if you call it more than once(while it's active) - you'll need something that blocks this calls: (atleast for UIFrameFadeIn it makes it nearly go to infinite time - if called unnecessary times (even if you use :GetAlpha()) - you would need something like spareTime=totaltime-(GetAlpha()/totaltime))

(Note this is for UIFrameFadeIn, and not UIFrameFlash)
Code:

local fade_in = {}
local fade_out= {}

--improved UIFrameFadeIn(frame,time,startAlpha,endAlpha,~type)
function lib:UIFrameFadeIn(frame,t,startAlpha,endAlpha,typ)
        local now=GetTime()
        local fname = frame:GetName()
        if typ=='in' then
                local IsInTable,num = self:inTable(fname,fade_in)
                if not IsInTable then
                        UIFrameFadeIn(frame,t,startAlpha,endAlpha)
                        --tinsert(frame,{icon_name,endTime})
                        tinsert(fade_in,{fname,GetTime()+t})
                else
                        if now>fade_in[num][2] then
                                tremove(fade_in,num)
                        end
                end
        elseif typ=='out' then
                local IsInTable,num = self:inTable(fname,fade_out)
                if not IsInTable then
                        UIFrameFadeIn(frame,t,startAlpha,endAlpha)
                        tinsert(fade_out,{fname,GetTime()+t})
                else
                        if now>fade_in[num][2] then
                                tremove(fade_out,num)
                        end
                end
        end
end

source: LibCooldownIcons-1.0
(Note inTable returns boolean,index of value in table(numeric))

dunno if you can 'calculate' the Pulse-time or want to fix it to some number

nightcracker 02-05-10 11:25 PM

Quote:

Originally Posted by Nemnacill (Post 177453)
I'm not sure about how it would work in lua, but any pulsating effect can be achieved with a simple sinus function.

pseudo code:
var sequence = 0;
sequence ++;
AlphaProperty = sin(sequence);

this would result in the AlphaProperty going from 0 to 1, then from 1 to 0 and so on. google 'math sin lua' for more info :)

Good luck

True, but that would require an onupdate function. And an onupdate function gets called at every frame. So if you run at 120 FPS your calling a sin function 120 times per second. Not that efficient as running my way(look above).

Torhal 02-06-10 01:59 AM

Quote:

Originally Posted by nightcracker (Post 177522)
<snip>So if you run at 120 FPS your calling a sin function 120 times per second.<snip>

Not true.

Code:

do
        local last_update = 0
        local updater = CreateFrame("Frame", nil, UIParent)

        updater:Hide()
        updater:SetScript("OnUpdate",
                          function(self, elapsed)
                                  last_update = last_update + elapsed

                                  if last_update >= 0.25 then
                                          RunSinFunction()
                                          last_update = 0
                                  end
                          end)
end

That executes the sin function every quarter of a second.

Hati-EK 02-06-10 03:25 AM

Quote:

Originally Posted by Torhal (Post 177529)
Not true.

Code:

do
        local last_update = 0
        local updater = CreateFrame("Frame", nil, UIParent)

        updater:Hide()
        updater:SetScript("OnUpdate",
                          function(self, elapsed)
                                  last_update = last_update + elapsed

                                  if last_update >= 0.25 then
                                          RunSinFunction()
                                          last_update = 0
                                  end
                          end)
end

That executes the sin function every quarter of a second.

Code:

last_update = last_update -0.25
is more precise and does not skip seconds (even if this would just be some miliseconds) than reseting the whole value to 0 - (ie last_update could be 0.25182965 - so you would missing 0.00182965 - if you have this ~1000 times there's something missing


All times are GMT -6. The time now is 03:41 PM.

vBulletin © 2014, Jelsoft Enterprises Ltd
©2012 ZAM Network LLC