Couples Animations... Synchronizing
|
Vivienne Daguerre
Registered User
Join date: 12 Apr 2004
Posts: 28
|
08-22-2005 06:23
I have made a great couple cuddle animation, where they cuddle and kiss, but don't have a clue about how to make the timing right so both do the right thing at the right time. Can someone point me in the right direction please? Is it a delay and stop animation and starting again? Would that work if they got on the pose balls at different times?
Thank you
@};- Vivienne Daguerre
|
Jesrad Seraph
Nonsense
Join date: 11 Dec 2004
Posts: 1,463
|
08-22-2005 06:53
Just make a pair of poses out of the first frame of both animations, call them pre_(your anim name here).
So when one of the AV gets on the poseball, use the pre_anim on it and open a listener on a private channel. When the second AV gets on the other poseball it'll send a message for the first poseball to hear and respond to. When both have received the message, they start their animation.
Laid out simply:
Poseball 1: when someone sits: open listener on, say, /211, say "ready" on /212 and play pre_anim when "ready" is sent on /211: send "go" on /212, close listener and play anim when "go" is sent on /211: close listener and play anim
Poseball 2: when someone sits: open listener on /212, say "ready" on /211 and play pre_anim when "ready" is sent on /212: send "go" on /211, close listener and play anim when "go" is sent on /212: close listener and play anim
_____________________
Either Man can enjoy universal freedom, or Man cannot. If it is possible then everyone can act freely if they don't stop anyone else from doing same. If it is not possible, then conflict will arise anyway so punch those that try to stop you. In conclusion the only strategy that wins in all cases is that of doing what you want against all adversity, as long as you respect that right in others.
|
Vivienne Daguerre
Registered User
Join date: 12 Apr 2004
Posts: 28
|
Thank you!
08-22-2005 08:04
Now this is scary... that makes sense to this noobie scripter, who is still at the stage of modifying existing scripts she comes across! Now, to see if I can write the code! *Watch out, I may blow up the world... if SL disappears, blame it on me... and do NOT buy me a chemistry set...*
@};- Vivienne Daguerre
|
Vivienne Daguerre
Registered User
Join date: 12 Apr 2004
Posts: 28
|
It is beyond me... can anyone do this for me? Will pay...
08-22-2005 16:56
This is way beyond my skills. I will pay someone if they can do this for me please?
@};- Vivienne Daguerre
|
Jesrad Seraph
Nonsense
Join date: 11 Dec 2004
Posts: 1,463
|
08-23-2005 02:35
From: Jesrad Seraph Poseball 1: when someone sits: open listener on, say, /211, say "ready" on /212 and play pre_anim when "ready" is sent on /211: send "go" on /212, close listener and play anim when "go" is sent on /211: close listener and play anim
Poseball 2: when someone sits: open listener on /212, say "ready" on /211 and play pre_anim when "ready" is sent on /212: send "go" on /211, close listener and play anim when "go" is sent on /212: close listener and play anim Translated in LSL: integer my_chan = 211; // channel this poseball will listen on integer paired_chan = 212; // channel that other poseball is listening on integer handle; // listen handle, for starting/stopping listening float delay = 0.06;
string starting_pose = "your starting pose name here"; string synchronised_animation = "your full couple animation name here";
key avatar;
default { state_entry() { llSitTarget(<0,0,0.1>, ZERO_ROTATION); }
changed(integer c) { if (c & CHANGED_LINK) { avatar = llAvatarOnSitTarget(); if (avatar != NULL_KEY) { llRequestPermissions(avatar, PERMISSION_TRIGGER_ANIMATION); } else { llListenRemove(handle); llStopAnimation(starting_pose); llStopAnimation(synchronised_animation); } } }
run_time_permissions(integer p) { if (p & PERMISSION_TRIGGER_ANIMATION) { handle = llListen(my_chan, "", "", ""); llStartAnimation(starting_pose); llSay(paired_chan, "ready"); } }
listen(integer channel, string name, key id, string message) { if (message == "ready") { llStopAnimation(starting_pose); llSay(paired_chan, "go"); llListenRemove(handle); llSleep(delay); llStartAnimation(synchronised_animation); } else if (message == "go") { llStopAnimation(starting_pose); llListenRemove(handle); llStartAnimation(synchronised_animation); } } }
You will want to change the variables at the beginning of the script. Copy it over and make another for second poseball, and exchange the my_chan and paired_chan values (and update the animation names, too) 
_____________________
Either Man can enjoy universal freedom, or Man cannot. If it is possible then everyone can act freely if they don't stop anyone else from doing same. If it is not possible, then conflict will arise anyway so punch those that try to stop you. In conclusion the only strategy that wins in all cases is that of doing what you want against all adversity, as long as you respect that right in others.
|
Ricky Shaftoe
Owner, "Rickymations"
Join date: 27 May 2005
Posts: 366
|
08-30-2005 13:48
From: someone Poseball 1: when someone sits: open listener on, say, /211, say "ready" on /212 and play pre_anim when "ready" is sent on /211: send "go" on /212, close listener and play anim when "go" is sent on /211: close listener and play anim Hmm, maybe I'm missing something, but doesn't this have Poseball 1 start the main animation twice? Once when "ready" is sent on /211, and once again when "go" is sent on /211? Likewise with Poseball 2? Similarly, the following code seems to imply that we'll be starting synchronised_animation twice, no?: listen(integer channel, string name, key id, string message) { if (message == "ready") { llStopAnimation(starting_pose); llSay(paired_chan, "go"); llListenRemove(handle); llSleep(delay); llStartAnimation(synchronised_animation); } else if (message == "go") { llStopAnimation(starting_pose); llListenRemove(handle); llStartAnimation(synchronised_animation); } }
|
Padraig Stygian
The thin mick
Join date: 15 Aug 2004
Posts: 111
|
08-30-2005 23:24
What you're seeing as starting twice is actually the sync process. If ball 1 starts first, it waits for a trigger from ball 2. If ball 2 starts first, ball 1 sends the trigger, and automatically starts its own anim.
I hope that makes sense...
|
Ricky Shaftoe
Owner, "Rickymations"
Join date: 27 May 2005
Posts: 366
|
09-24-2005 16:52
Well, this worked well, to a point! A couple of problems and questions:
1. It works great until I link the two balls together -- then the animations don't sync as well, if at all. Is there any reason linking might interfere with the listens?
2. Also, this script doesn't stop ball 1 if the avi on ball 2 hops off. I tried adding code to do that: sent a message from ball 2 to ball 1 (on the channels established for ready/go) when the avi got off ball 2, but it didn't work. In fact, my anims suddenly seemed kinda distorted; not sure what was up with that. What's the best way to stop both animations, and reset, when one avi gets off one ball?
|
Jesrad Seraph
Nonsense
Join date: 11 Dec 2004
Posts: 1,463
|
09-24-2005 23:42
The above code was made to start nonlooped, synced anims so it has no code for stopping :/
_____________________
Either Man can enjoy universal freedom, or Man cannot. If it is possible then everyone can act freely if they don't stop anyone else from doing same. If it is not possible, then conflict will arise anyway so punch those that try to stop you. In conclusion the only strategy that wins in all cases is that of doing what you want against all adversity, as long as you respect that right in others.
|
Ricky Shaftoe
Owner, "Rickymations"
Join date: 27 May 2005
Posts: 366
|
09-25-2005 08:46
Ah, ok. I'll keep fussing with it, then. My current theory is that I messed up by trying to stop the sync'd anim and restart the starting animation. The result seemed to be that those two anims kept playing alternately, which produced very odd visual effects. Now I'm going to try simply having ball 2 stop *everything* (all anims) when ball 1 says "stop," and then use llResetScript.
But I'm open to suggestions!
|
Ricky Shaftoe
Owner, "Rickymations"
Join date: 27 May 2005
Posts: 366
|
09-26-2005 11:21
I've been experimenting with this further, and I still haven't found a way to handle what happens once when player one hops off one of the two balls and then hops back on. In that case, player two just keeps animating.
I'm thinking I'll set a flag called "already dancing alone" once player one hops off, and have player two's ball check if that flag is on when player two hops back on and sends new "ready/go" messages. (Otherwise player two's ball just keeps playing the anim without re'syncing.) If the flag is on, player one's ball needs to llStopAnimation(synchronised_animation), pause(delay), and then llStartAnimation(synchronised_animation). Will that restart the sync'd anim from the start?
In the meantime, I'm wondering again whether llLinkedMessage might be a better way to go. By all accounts it's quicker than llListen. And indeed, I see some lag with llListen; sometimes the two balls sync up, sometimes not.
|
Memory Harker
Girl Anachronism
Join date: 17 Jun 2005
Posts: 393
|
Oh Ricky!
09-26-2005 13:03
When you've got this a little closer to completion? You'll probably, being so professional and all, want to test it out with a variety of avatars. I mean, that's what all the Really Cool scripters do, of course. Why, everybody knows THAT!
So I was just ... well, I just wanted you to know ... I mean ... I think a friend and I ... well, listen, we could prolly help you out with the testing process. If you really needed the help, that is. I mean, at least twice. Or twice a day. For a few weeks?
*blush*
IM me inworld when it's available, yes?
|
Ziggy Puff
Registered User
Join date: 15 Jul 2005
Posts: 1,143
|
09-26-2005 13:41
AFAIK, the Wiki says an object won't listen to itself, so yes, you'll need linked messages. Why don't you have each ball send the other a link message that conveys its own state to its partner ball. In other words, A tells B "I have someone sitting" or "I don't have anyone sitting" whenever you get a change link event. B does the same to A. Both balls maintain their partner's state in a variable, like isSomeoneSittingOnPartner. Then the code for each ball becomes symmetrical, each has to handle 4 events: * Someone just sat on me (received via a change event) * Someone just got off me (also received via a change event) * Someone sat on my partner (received via a link message) * Someone got off my partner (link message again) And your code would look something like this. Every time someone sits on you or gets off, you tell your partner. If you receive a message from your partner, remember his state. And you need to play your animation if both balls have someone sitting on them, else stop it. So, the following logic should be in both balls, since they're symmetrical: * Someone just sat on me (received via a change event) Tell partner Is someone sitting on my partner? If yes, start animation * Someone just got off me (also received via a change event) Tell partner * Someone sat on my partner (received via a link message) Store partner's new state in my local variable Is someone sitting on me? If yes, start animation * Someone got off my partner (link message again) Store partner's new state in my local variable Is someone sitting on me? If yes, stop animation, because I'm alone Hope that makes sense 
|
Ricky Shaftoe
Owner, "Rickymations"
Join date: 27 May 2005
Posts: 366
|
09-26-2005 16:07
Memory: I always need testers! I test all my animations extensively before I put them out for sale. The more avi's, the better. It's one of the most enjoyable parts of my job, in fact.  Ziggy: That does make sense. First, thanks for confirming my suspicion that llListen wasn't working for linked objects. I'm selling linked pose balls; customers expect couples dances and the like to be linked. And if I succeed in making synchronized animations, then they really need to stay linked to preserve the integrity of the performance, such as it is. Second, thanks for clarifying my thinking on when to used linked messages and when to use change. I think change is giving me trouble right now. I've been sending 'change' messages to both balls, incrementing a counter every time there's a new sitter, and decrementing when someone hops off. That method isn't working; my counter gets up to 3 or 4. A couple questions. You say: " Tell partner Is someone sitting on my partner? If yes, start animation." I assume I would tell partner this via a linked message? And: what part of the code should test the overall "state" of things? Can I put this in run_time_permissions? E.g., run_time_permissions(integer perm) { if (perm) if (state == "people on both balls") llStartAnimation("Award-winning sync'd anim"); if (state == "someone on this ball only") llStopAnimation("Award-winning sync'd anim"); // but what if this anim wasn't already playing? llStaartAnimation("sit"); if (state == "someone on other ball only") llStopAnimation("Award-winning sync'd anim"); // again, what if not playing already? if (state == "no one on balls") llStopAnimation("Award-winning sync'd anim"); llStartAnimation("sit"); llResetScript();
|
Ziggy Puff
Registered User
Join date: 15 Jul 2005
Posts: 1,143
|
09-26-2005 16:53
From: someone A couple questions. You say: " Tell partner Is someone sitting on my partner? If yes, start animation." I assume I would tell partner this via a linked message?
Correct. From: someone And: what part of the code should test the overall "state" of things? Can I put this in run_time_permissions? Take this with a grain of salt, because I'm not very experienced with pose balls. But I normally put this kind of code in two places. In the changed event, I check to see if I have the permissions I need. If I do, I go ahead and do what I need to do. If I don't, I ask for the required permissions. Then in run time permissions I again check to make sure I have the permissions I need, and if I do, repeat. But that only takes care of the person who's sitting on this ball (let's say ball A). When someone sits on ball B, ball A won't get any notification at all. So you need ball B to send a link message to ball A. This comes into ball A in the link_message handler, so you'll need to put in code there as well. Basically, something like this. I'm writing this in psuedocode cause I'm lazy, I hope you can convert this to real LSL. This code should be symmetrical, so it should exist in both balls. And I'm not in the game right now, so I can't test it, so there might be some logic errors here. Now that the disclaimers are out of the way  // Global variables to keep track of my partner's state integer sittingOnPartner = 0; // Default state, we begin with no one sitting
// Same thing for my own state integer sittingOnMe = 0; // Default state, we begin with no one sitting // // Function to tell partner my state tellPartner(integer myState) { llMessageLinked(LINK_ALL_OTHERS, myState, "", NULL_KEY); }
default {
// state_entry, on_rez, etc... whatever setup stuff you need to do
// Then this is what you do in a change event handler, i.e. when someone // sits/gets up on this ball changed(integer change) { if (change == CHANGED_LINK) { key avatar = llAvatarOnSitTarget();
if (avatar != NULL_KEY) { integer perms = llGetPermissions();
if (!(perms & PERMISSION_TRIGGER_ANIMATION)) { // No perms, need to request them llRequestPermissions(avatar, PERMISSION_TRIGGER_ANIMATION); } else { // We have perms, so do what we need to do
// Someone just sat down on me. First, set my own variable sittingOnMe = 1; // Tell my partner that someone's sitting on me, so he // can check if someone's sitting on him and start his // animation tellPartner(1); // See if partner has already told me that someone's sitting // on him. If he has, then this person is the 2nd person to // sit, and I need to start my animation. If not, then this // person is the 1st person to sit, and I need to wait until // someone sits on my partner and he lets me know via a link // message and then start my animation if (sittingOnPartner == 1) { llStartAnimation("whatever"); } } } else { // My person got off. No need to stop animation, because his // animation would have stopped automatically. But I do need // to let my partner know, so if there's still someone on his // ball, he can stop his animation.
// First set my own state sittingOnMe = 0;
// Now tell partner tellPartner(0); } } }
// Run time permissions - basically a repeat of what we did when we detected an // avatar had sat down and we have the perms run_time_permissions(integer perms) { if (!(perms & PERMISSION_TRIGGER_ANIMATION)) { // We asked for the perms but didn't get them. Some people // ask again, which makes the script endlessly ask for perms until // they're granted. Some people print a warning message and unsit the // sitter... do whatever you want } else { // A copy of the code from the block inside the change handler above
// Someone's just sat down on me. First, set my own variable sittingOnMe = 1;
// Tell my partner that someone's sitting on me, so he // can check if someone's sitting on him and start his // animation tellPartner(1);
// See if partner has alreadyy told me that someone's sitting // on him. If he has, then this person is the 2nd person to // sit, and I need to start the animation. If not, then this // person is the 1st person to sit, and I need to wait until // someone sits on my partner and he lets me know via a link // message if (sittingOnPartner == 1) { llStartAnimation("whatever"); } } }
// Now for the link message handler, i.e. when stuff happens in the other ball link_message(integer sender, integer num, string str, key id) { if (num == 1) { // Partner is telling us someone sat on him. Remember that sittingOnPartner = 1;
// Do we have someone already sitting on us? If yes, then this is the // 2nd person to sit down, and we need to start the animation if (sittingOnMe == 1) { llStartAnimation("whatever"); }
// Else... nothing to do. Whoever sat on the other ball is the first sitter. // When someone sits on me, I'll get the change event, I'll detect that the // partner already has someone sitting, and I'll start the animation there } else { // Someone got off partner sittingOnPartner = 0;
// Is someone still sitting on me? If so, I need to stop his animation if (sittingOnMe == 1) { llStopAnimation("whatever"); } } } }
See if that makes sense. I structured it to (hopefully) be easy to follow, not to run very efficiently. You can move some code around to clean up the logic once you understand what it's doing. Edited for syntax errors.
|
Ricky Shaftoe
Owner, "Rickymations"
Join date: 27 May 2005
Posts: 366
|
09-26-2005 18:51
Wow, thanks for that wonderfully detailed reply. Really beyond the call of duty. I love this game sometimes.  I'll try something like that code tonight. Two quick initial reactions: 1. Thanks to you, I think I finally understand the difference between llGetPermissions(s) and llRequestPermissions(). Heh, not that it's rocket science. But I'd been requesting permissions every time. Now I understand: once you get those permissions, they stay good for a while, huh? (Er, how long?) So you can llGetPermissions, test it bitwise to ensure it includes my particular (animation) permission, and then go right ahead and animate if you already have permissions. Doh. Learn something every day. That also explains to me why you have animation code in both changed and run_time_permissions: the former if you already have perms; the latter if you don't. 2. You say: "// My person got off. No need to stop animation, because his animation would have stopped automatically...." The tutorial's poseball code seems to say you should call llStopAnimation("my anim"  when the person gets off. (So of course I was going nuts requesting permissions to stop the animation, and generating lots of "no agent to request perms from" error messages.) And indeed I think I've had problems with avi's continuing to animate even after jumping off a ball, so I put the llStopAnimation code back in. But I'll try it your way and see if it works. Thanks again. About to go give it a whirl...
|
Ziggy Puff
Registered User
Join date: 15 Jul 2005
Posts: 1,143
|
09-26-2005 19:22
I could definitely be wrong about not needing to stop the animation. Like I said, I haven't done any poseballs  From: someone Now I understand: once you get those permissions, they stay good for a while, huh? (Er, how long?)
No idea.  I've seen objects re-request permissions on a script reset, so that would be my guess. From: someone That also explains to me why you have animation code in both changed and run_time_permissions: the former if you already have perms; the latter if you don't.
So there's your first optimization/improvement - put that code into a separate function and call it from both places. That way if you make a change, you won't need to remember to change it in two places. Also, you could do something like: if (we got perms) { sittingOnMe = 1;
if (sittingOnPartner == 1) { llStartAnimation("whatever"); } } else { sittingOnMe = 0; }
// Now tell partner tellPartner(sittingOnMe);
Since you set sittingOnMe to 1 and tellPartner(1), and ditto for 0, you can pull the tellPartner() call out of the if/else block and call it with sittingOnMe, which will have the correct value you want to send to the partner. That'll clean up the code a little. I didn't do it originally because it's a teeny bit more difficult to follow, IMO  Edited for typos and syntax errors  P.S. There's an error in my earlier script. Every place I typed: if (sittingOnPartner = 1) { llStartAnimation("whatever"); }
Should be: if (sittingOnPartner == 1) { llStartAnimation("whatever"); }
Double equals for comparison, single for assignment. I'll fix that post too.
|
Ricky Shaftoe
Owner, "Rickymations"
Join date: 27 May 2005
Posts: 366
|
09-26-2005 22:03
Success! Well, mostly, anyway.
1. At first, only one avatar animated. I am still not sure how I fixed this! hehe. I did add a little llSleep(0.04) after each call to TellPartner, but I doubt that did anything.
2. Now both animate, pretty much in sync. Sometimes with a .25 sec lag, sometimes not; that may just be server lag? Doesn't seem to depend on which ball is the main prim etc.
3. I was right that you sometimes need to halt the animation even if someone jumps off the ball. I added a call to llStopAnimation() to fix this.
4. One thing you might not know: you need a call to llSitTarget (in state_entry) to make llAvatarOnSitTarget work properly, I think.
5. The only real issue I have is that change senses events other than sits, so occasionally I'll get an error message (no avi to request permissions) after I finish editing or otherwise touching the poseball. I also am seeing a permissions error early in the execution of the script. I *think* the solution is to test for an avatar's key a second time; my default poseball script does this to distinguish avi-sit events from other change events. I think.
Anyway, thanks so much; I'm well on my way now. Item 5 is really my only issue now. Thanks!
|
Ziggy Puff
Registered User
Join date: 15 Jul 2005
Posts: 1,143
|
09-26-2005 22:17
Like I said, no poseball experience  From: someone 4. One thing you might not know: you need a call to llSitTarget (in state_entry) to make llAvatarOnSitTarget work properly, I think. Good catch, though I can hide behind "Well, that was included in the general setup that I assumed you did"  From: someone 5. The only real issue I have is that change senses events other than sits Even inside an "if (change == CHANGED_LINK)" check? Interesting. Ah... found the error, I think, unless you fixed this already. I wrote "if (avatar != NULL)". That should be "if (avatar != NULL_KEY)". Sorry about that. From: someone I *think* the solution is to test for an avatar's key a second time Sounds like a good idea. I'm sure other people have figured out sequences of events that need to be handled differently, that I haven't thought of and will therefore trip the logic in my script. From: someone Sometimes with a .25 sec lag, sometimes not Hmm...if you did the code cleanup I suggested in my last post, that has the side effect (as I now realize) of switching the sequence of sending the link message to the partner and starting its own animation. Maybe it lags if you do one first and works well if you do the other first? Try it out and see if you can find a pattern. And it's probably safer to change: if (!(perms & PERMISSION_TRIGGER_ANIMATION)) To: if ((perms & PERMISSION_TRIGGER_ANIMATION) != PERMISSION_TRIGGER_ANIMATION) Both should work in C, as any non-zero value evaluates to true in a boolean expression. Not sure if LSL follows that all the time, so it's probably better to be explicit. *shrug*
|
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
|
09-26-2005 23:00
if (!(perms & PERMISSION_TRIGGER_ANIMATION))
is safe in this case because the value has a single bit turned on. But in the grand sceme of things you are right. They could change it (however that is unlikely).
_____________________
Truth is a river that is always splitting up into arms that reunite. Islanded between the arms, the inhabitants argue for a lifetime as to which is the main river. - Cyril Connolly
Without the political will to find common ground, the continual friction of tactic and counter tactic, only creates suspicion and hatred and vengeance, and perpetuates the cycle of violence. - James Nachtwey
|
Ricky Shaftoe
Owner, "Rickymations"
Join date: 27 May 2005
Posts: 366
|
09-26-2005 23:46
Thanks for your further reply. Actually, I already fixed NULL_KEY; it wasn't that. I'm pretty sure I need to check again to see if there's a sitter at the very end of your changed routine. If a sitter, then stop anim; but if no sitter, don't do anything. I haven't had a chance to play with it more tonight; too busy celebrating now that I can make sync'd animations.  And nope, I haven't really had a chance to play around with moving code around either. I did tinker with a few things, and even experimented with adding delays to one or the other ball. I didn't see the "main" ball reacting any faster or slower than the child prim; I thought I"d read somewhere that the main prim might have some sort of priority. When I'm more awake tomorrow, I'll take another stab at it. Basically, if I can get rid of the occasional "can't find avi for permissions check" error message, I'll be a happy camper. A .25 discrepancy isn't noticeable unless you're doing something like joint calisthenics -- the precise anim I chose to test this with. With that anim, I notice the lag only when doing jumping jacks.  Even then, it's pretty close. For a salsa or (ahem) other couples set, it should be a non-issue. Woot!
|
Ricky Shaftoe
Owner, "Rickymations"
Join date: 27 May 2005
Posts: 366
|
09-26-2005 23:52
One more thought: I added some llSay(0,"debug message"  calls in both balls, when I first compiled the script, because only one avi was animating. (I had it report the value of each state to me at various times.) Come to think of it, I probably added more such calls to one script than the other. Well, that function is bound to take time to execute, and so it may also be producing my slight out-of-sync results -- results that vary from perfect to close-to-perfect. I'll comment the llSays out and see if sync is better. When I've had sleep and some more time to work. 
|