I wanted to make my actor's eyes blink infrequently, and preferably irregularly.
"SpriteAnimMode = 2" does randomize frames, but I didn't want to make (and have CC load) many frames of the same open eyes with one closed eyes frame. I'm a total novice at programming, but I managed to hack together some Lua. If my approach is bad, I'd rather get feedback before sharing it in the Minor Mod Dump (if there's a Script Dump, I have no idea where it is).
At first I hacked together a while-loop. But since I had to add in a timer to keep it from blinking inhumanly fast (and a coroutine.yield to keep it from locking my computer), I rewrote it as two timers. One is for the interval between blinks and the other for the duration of the blink. Both use math.random to make it more naturally variable.
Here's my code:
Code:
function Create(self) self.blinkIntervalTimer = Timer(); -- Time between blinks. self.blinkDurationTimer = Timer(); -- Time each blink takes. end
function Update(self)
-- Random time span between blinks, multiplied to skew higher but allow rare flutterings. if self.blinkIntervalTimer:IsPastRealMS(math.random(150,2250)*1.2) then -- Once the interval timer is up, switch to "eyes closed" frame... self.Frame = 1; -- ...for a randomized duration of time. if self.blinkDurationTimer:IsPastRealMS(math.random(10,500)*0.92) then -- Once the blink is over... self.Frame = 0; -- ...return to the "eyes open" frame... self.blinkIntervalTimer:Reset(); -- ...and reset both timers to start all over. self.blinkDurationTimer:Reset(); end
end
end
I don't know if timers have to be checked every millisecond or if they're actually lighter on clock cycles than I suspect. Would "coroutine.yield" and "coroutine.resume" be useful in this kind of "do something, then wait, then do something else" constructions? I'm not very clear on what they even are; they just sound cool. The CC wiki says nothing, but I breezed over the Lua coroutine documentation.
Anyone have feedback or suggestions?
Wed Apr 10, 2013 11:48 am
Coops
Joined: Wed Feb 17, 2010 12:07 am Posts: 1545 Location: That small peaceful place called Hell.
Re: Blinking
Well first off your problem is the timer for the blink duration is already passed by the time the interval has passed. So really, you're not even getting a single frame for the blink to even happen.
This can easily be fixed by adding two lines fortunately, instead of all that coroutine nonsense.
Second, 0.18 - 2.7 seconds is a rather inhuman blink interval. Remember that MS stands for milliseconds, not seconds.
Code:
function Create(self) self.blinkIntervalTimer = Timer(); -- Time between blinks. self.blinkDurationTimer = Timer(); -- Time each blink takes. end
function Update(self)
if self.blinkIntervalTimer:IsPastSimMS(math.random(1000,4150)*1.2) then --Adjusted time self.Frame = 1; if self.blinkDurationTimer:IsPastSimMS(math.random(300,800)*0.92) then --Adjusted time self.Frame = 0; self.blinkIntervalTimer:Reset(); self.blinkDurationTimer:Reset(); end -- Reset blink duration until the interval is over else self.blinkDurationTimer:reset(); end
end
Also you might be better off with IsPastSimMS instead of IsPastRealMS
SimMS counts for delta/simulation time whereas RealMS counts for real life time.
Wed Apr 10, 2013 1:59 pm
Brendan
Joined: Tue Jun 19, 2012 8:01 pm Posts: 19
Re: Blinking
Ah, thanks Coop. I had totally overlooked how the duration timer is still running during the interval between blinks. The script worked, but it only looked good after changing the millisecond values from what I started with from researching it. The timer problem explains why realistic values looked unreal.
Wed Apr 10, 2013 9:19 pm
Brendan
Joined: Tue Jun 19, 2012 8:01 pm Posts: 19
Re: Blinking
I got a lot of flickering with your version, Coop. I think math.random gets called every update and, by sheer repetition, it tends to eventually come up with a small value for each timer and run through the whole process.
So I set up counters to hold interval and duration values that get set once and only once in the blink process. Thanks for drawing my attention to what's happening with each timer as it updates each frame.
It's looking pretty good on my actor. May be useful for others wanting a meatpuppet (or robot) with a little more life on its face.
Code:
function Create(self) self.blinkIntervalCounter = 2800; -- Holds randomized values for time between blinks. self.blinkIntervalTimer = Timer(); -- Counts milliseconds until time between blinks reached. self.blinkDurationCounter = 300; -- Holds randomized values for time blink takes. self.blinkDurationTimer = Timer(); -- Counts milliseconds until blink length reached. end
function Update(self)
-- While the interval timer is over the interval limit... if self.blinkIntervalTimer:IsPastSimMS(self.blinkIntervalCounter) then self.Frame = 1; -- ...switch to "eyes closed" frame... -- ...and let the duration timer run until it hits the duration limit. if self.blinkDurationTimer:IsPastSimMS(self.blinkDurationCounter) then -- Once the blink is over... self.Frame = 0; -- ...return to the "eyes open" frame... self.blinkIntervalTimer:Reset(); -- ...and reset the interval timer. -- Set new random time until next blink, skews toward 2800ms but allows 500-10000ms intervals. self.blinkIntervalCounter = math.random(1785,35700)*0.28; -- Set new random length of next blink, skews toward 300-400ms but allows 100-400ms durations. self.blinkDurationCounter = math.random(66,285)*1.5; end -- Keep the duration timer suppressed during the interval between blinks. else self.blinkDurationTimer:Reset(); self.Frame = 0; -- Open the eyes, just in case something went wrong. end
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot post attachments in this forum