Jump to content

Footstep effect scripting?


MajorCooke
 Share

You are about to reply to a thread that has been inactive for 1811 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

I've seen people with a footstep effect before, but I've always been at a loss on how to recreate this ability, except for a script someone gave me. However, unfortunately it tends to go out of sync, so I'm wondering if there's a better way to perform this?

float timerevent = 0.40;
float sleeper = 0.25;
float vol = 1.0;
integer running = FALSE;

default
{
    on_rez(integer start_param)
    {
        llResetScript();
    }
    
    state_entry()
    {
        integer agentinfo = llGetAgentInfo(llGetOwner());
        llSetTimerEvent(timerevent);
    }
    
    timer()
    {
        integer agentinfo = llGetAgentInfo(llGetOwner());
        
        if(agentinfo & AGENT_ALWAYS_RUN)
        {
            running = TRUE;
        }
        if(agentinfo & AGENT_WALKING)
        {
            if(running == TRUE)
            {
                //llStopSound();
                llTriggerSound("6559cdbf-a664-d93c-184e-42d95a965104", vol);
                llSleep(sleeper);
            }
            else
            {
                //llTriggerSound("4c19068e-38ae-f3a9-21a3-630a59d62a31", 0.4);
                llTriggerSound("6559cdbf-a664-d93c-184e-42d95a965104", vol);
                llSleep(sleeper);
            }
        }
        else
        {
            running = FALSE;
            llStopSound();
        }
    }
}

I have an object attached to the feet already, but depending on how intensive the place I'm at will definitely slow it down, since animation speeds and the like are not synced together.

I was considering using http://wiki.secondlife.com/wiki/LlGetPos by getting the distance from the avatar, but unfortunately, the caveat of object position with avatar animation being invisible to the simulation means I cannot get it based on that. Does anyone have a better idea on how to do this? 

Link to comment
Share on other sites

You're off topic once again. I can understand someone using llSleep() to avoid using a timer, but llSleep() inside a timer is just silly, especially here where the sleep time is shorter than the timer scheduling anyway.

But I also don't expect someone like You @steph Arnott to understand good practices given how you deliver bad advice with the precision of a swiss clock.

  • Haha 3
Link to comment
Share on other sites

Just now, Kyrah Abattoir said:

You're off topic once again. I can understand someone using llSleep() to avoid using a timer, but llSleep() inside a timer is just silly, especially here where the sleep time is shorter than the timer scheduling anyway.

But I also don't expect someone like You @steph Arnott to understand good practices given how you deliver bad advice with the precision of a swiss clock.

No, that script is alowing the server to catch up. Clearly it is you that does not understand.

  • Haha 2
Link to comment
Share on other sites

@MajorCookeUnfortunately, animations are purely clientside, so there isn't even a guarantee that they started at the same time for everyone unless llStartAnimation was fired for everyone while the object was in view. Even two animations started at the same time will eventually drift apart.

The only way to "resync" is essentially to stop the animation and start playing it again.

Edited by Kyrah Abattoir
Link to comment
Share on other sites

2 minutes ago, Kyrah Abattoir said:

@MajorCookeUnfortunately, animations are purely clientside, so there isn't even a guarantee that they started at the same time for everyone unless llStartAnimation was fired for everyone while the object was in view. Even two animations started at the same time will eventually drift apart.

The only way to "resync" is essentially to stop the animation and start playing it again.

The script is not an animation. Secondly the sync is subjective to how fast the others BB is and how far away from the server in RL.

Link to comment
Share on other sites

Like I said, it was sent to me by someone else. I know very little about scripting.

As for the stopping and restarting, I could try and measure when the animation stops and starts, but I have no idea how to script that in properly. Can someone help me out there?

Anything to get it as close as possible would be appreciated.

Edited by MajorCooke
Link to comment
Share on other sites

It's impossible.

LSL can never know the state of an animation playing on the client. There is an indeterminate about of time between the the script saying "play this anim" or "play this sound" and either events actually happening in the client. Load times, latency, etc etc.

The best you can do is time your sound effects to match the speed of the animation as played, aim for ideal conditions (both sounds and anim are loaded and ready to be played AND the latency for both instructions is the same) and hope for the best.

  • Like 1
Link to comment
Share on other sites

You can't "measure" it per say, but when a non-looping animation ends it will be removed from llGetAnimationList(). However the keys returned by this function do not correspond to animation asset UUIDs so you'll have to deal with that too.

I understand what you're trying to do but you're fundamentally trying to synchronise server side with something that is purely client side and not synchronised across clients.

  • Like 2
Link to comment
Share on other sites

9 hours ago, MajorCooke said:

Then that's what I'd like to do. How would I go about doing this? Particularly I'd like to start with the walking animation.

I should note I learn best by examples with explanations.

this is not an easy problem and there is no total solution to it. The main obstacle is that we can't make our script run in constant time on the server. Best we can do is try to ameliorate matters by knowing the server dilation time (how slower than the standard 1.0 is the server running). http://wiki.secondlife.com/wiki/LlGetRegionTimeDilation. 1.0 dilation equates to 45 server frames a second

our walking animation is running client side in constant time (30 frames a second typically). Lag caused by network data traffic excepted. Nothing can be done from LSL about network lag  

Proceeding then some arithmetic: 1.0 / 30 * 45  = 1.5.  Or more simply 2 client side animation frames for every 3 server side frames

If we don't have access in RL to the animation file then we use our eyes and a stopwatch to get the time for each walking stride.  From this we work out the number of animation frames for the stride.  Lets say we calculate  3 client-side animation frames per stride

with this information we get the following:  1.5 * 3.0 = 4.5.  4.5 server frames for each stride when the server is running at 1.0 dilation. 

knowing this we then can set llSetTimerEvent() to some proportion of this.  1.0 / 45 * 4.5 = 0.1 seconds

basically when the server is lagging then we try to muscle the server event queue so our script timer event gets called proportionately sooner

state_entry()
{
    llSetTimerEvent(0.1);
}

timer()
{
   // ... play our effect ...


   llSetTimerEvent(llGetRegionTimeDilation() / 45 * 4.5);
}

 

ps. add

as wrote this is just the basic beginning of how this can be ameliorated.  We can do further amelioration (adjusting for spikes and dips - smoothing) by using a queue. Queue in this case meaning  putting the last x number of dilations into a list.  Removing the  oldest dilation and adding the latest dilation. Then setting the next timer event to an average of the queue

Edited by Mollymews
ps add
  • Like 1
Link to comment
Share on other sites

 

4 hours ago, Mollymews said:

basically when the server is lagging then we try to muscle the server event queue so our script timer event gets called proportionately sooner

For a vanity effect most wont even hear because they turn sl sounds off.

Link to comment
Share on other sites

Okay, @Mollymews I get the last part but I don't know how to write it for SL. I've been trying to learn it but this is syntax I've never worked with before, and I thought LUA was rough. Would you mind helping me adapt the current code I have for it?

As for the what you wrote above, I take it I can just put that in my code and replace the current SetTimerEvent I have already?

I clocked the animation stride to be roughly 0.55 seconds between the steps.

@CoffeeDujour Understandable, but the folks I hang out with, they rather enjoy it. Quite a lot of them.

Edited by MajorCooke
Link to comment
Share on other sites

9 minutes ago, MajorCooke said:

this is syntax I've never worked with before

It's pretty much the same as C/java languages. What you may need to study is the events, since most of the interesting things happen in response to an event being triggered (notified to your script by the server). It isn't predictable, you can't assume that a touch event will occur in your script at a set number of milliseconds after the user touches the scripted item. The other issue, clientside versus serverside has already been mentioned.

Link to comment
Share on other sites

Yeah. I get that much, which is why I was considering having some form of change to the script where instead of the body itself doing the animation when walking/running, a script detects if moving and letting that both change the animation and do the playing sound... if that's at all possible. Then at least it can try to be a little more concise. Is that possible?

Or as a last resort, I upload a custom looping variant of the steps that I loop and monitor for possible desyncing and, every X seconds, stop the loop and restart it in order to bring it back in line using the dilation @Mollymews suggested. I've already tweaked the audio to Hell and back to ensure it's as consistent as possible so that part's been taken care of, as I recorded the character strolling and used Premiere Pro to align the audio clips. 

But I certainly want that to be a last resort because that requires using lindens. While I have some, I cannot afford mistakes.

@Mollymews Also, should I be using http://wiki.secondlife.com/wiki/LlGetRegionFPS as part of it? Since that can certainly have an effect, I've been told by a friend, do you recommend I plug that in for the 45 of your code?

Edited by MajorCooke
Link to comment
Share on other sites

I was just about to ask you, actually, what would you use in place of llSleep? Just llSetTimerEvent?

Also, the animation I have is not controlled by speed. Where can I view some of those footstep gadgets? And, is it possible to change the AO I have to work based on velocity?

Edited by MajorCooke
Link to comment
Share on other sites

Okay. Stepping back and thinking about this for a moment, it's not so much the desyncing happening between animation and sounds that bothers me, so much as the sounds themselves. There's a lot that could be fixed here. I am not caring so much about syncing it with the animation directly, so much as playing them without them being delayed rather sporadically. I think, if I addressed this issue, then that could make enough of a difference.

  • Like 1
Link to comment
Share on other sites

Okay, so after doing a lot of experimentation, what I came up with is a lot more feasible. 

float timerevent = 0.5615;
float sleeper = 0.2;
float vol = 0.8;
float delaytime = 0.30;
integer delay = TRUE;

default
{
    on_rez(integer start_param)
    {
        llResetScript();
    }
    
    state_entry()
    {
        integer agentinfo = llGetAgentInfo(llGetOwner());
        llSetTimerEvent(sleeper);
        delay = TRUE;
    }
    
    timer()
    {
        integer agentinfo = llGetAgentInfo(llGetOwner());

        if (agentinfo & AGENT_WALKING)
        {
            // Add a small delay because it takes this long for the foot to make 
            // contact with the ground when transitioning from normal to this.
            if (delay)
            {
                llSetTimerEvent(delaytime);
                delay = FALSE;
            }
            else
            {
                if (agentinfo & AGENT_ALWAYS_RUN)
                {
                    llTriggerSound("6559cdbf-a664-d93c-184e-42d95a965104", 1.0);
                }
                else
                {
                    // Since the object is an attachment, play is fine.
                    llPlaySound("6559cdbf-a664-d93c-184e-42d95a965104", vol);
                    //llTriggerSound("4c19068e-38ae-f3a9-21a3-630a59d62a31", 0.4);
                }
                llSetTimerEvent(timerevent);
            }
        }
        else
        {
            delay = TRUE;
            llSetTimerEvent(sleeper);
        }
    }
}

Something amusing I found out... llTriggerSound is susceptible to a small delay - and this is primarily a guess, but after having worked with some game engines in the past, I think it's safe to say: because it spawns a temporary object. At least, that's what the engine I fiddled around with the most did. It spawned an object to play the sound, and then destroyed itself immediately afterwards which means it's subjected to more networking stuff than that of llPlaySound.

Considering this is an attachment at any rate doing the sound playing, I don't need to worry about occupying the objects sound channel - in fact it's wide open for use.

Furthermore, using llSetTimeredEvent definitely seemed to help a little as well, and while it's still not perfect, it at least won't go completely out of whack in more populated areas and won't screw up the rest of the timing, which apparently llSleep was doing for the script.

Not perfect, but still a LOT better than what it used to be. I'll continue expanding upon this as time goes on.

  • Like 1
Link to comment
Share on other sites

54 minutes ago, MajorCooke said:

Something amusing I found out... llTriggerSound is susceptible to a small delay - and this is primarily a guess, but after having worked with some game engines in the past, I think it's safe to say: because it spawns a temporary object.

Don't forget there is a delay between the script command to play a script, that being translated to a command for the viewer, and that in turn being sent down the wire to the client.

Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 1811 days.

Please take a moment to consider if this thread is worth bumping.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...