Luxianna Swords Posted May 21, 2021 Share Posted May 21, 2021 (edited) Hi, I am not looking to do anything complicated. I am wanting to figure out how to tweak an existing script to rotate two difffernt objects in different directions I am wanting to link two objects (a1 and a2) and i want them to have two different scripts one with default { state_entry() { llTargetOmega(<0,0,1>,2*PI/8,1.0); } } and one with default { state_entry() { llTargetOmega(<0,1,0>,2*PI/8,1.0); } } I have a basic understanding that i need some sort of coding to identify the objects which would be adjusting something to TargetOmega i imagine since when i link the two objects it defaults to the script of the parent object, but i really have no idea what to do or how to do it. If you have some resources you could point me towards to help me figure it out, that'd be lovely. Edited May 21, 2021 by Luxianna Swords Link to comment Share on other sites More sharing options...
Quistess Alpha Posted May 21, 2021 Share Posted May 21, 2021 (edited) You /can/ have different scripts in different objects(prims or meshes) in a linkset (EDIT: or even multiple scripts in the same object) and they will /all/ run at the same time. That being said it's best-practice to consolidate scripts into a single script if you can. for the sake of keeping things simple and for learning, try linking a few cubes together and put one or the other of your scripts into different cubes and see what happens. Omega is a bit weird, to get things to stop rotating, put this script into any of your cubes and set it to running: default { state_entry() { integer index = llGetNumberOfPrims()+1; while(--index>0) { llSetLinkPrimitiveParamsFast(index, [PRIM_OMEGA, <0,0,0>,0.0,0.0]); } } } Some things like 'Omega', Settext and particle effects are just special properties of the prim (like its size and shape, and textures) that for some reason you can't directly edit with the build window. if you remove the script that set the property, (in this case the spinning) it will continue to be there. You will also notice that if you have one of your omega scripts in the 'root prim' of your linkset, something slightly different will happen. Edited May 21, 2021 by Quistessa fixed infinite loop, woops. 1 Link to comment Share on other sites More sharing options...
Nova Convair Posted May 21, 2021 Share Posted May 21, 2021 In SL all linked prims are linked to the root. So if you rotate the root all linked prims will rotate around the root. If you want to have 2 independant rotating linked prims you need 3 prims! One is the root and you can make it small+invisible. You link your other 2 prims to it and then the scripts will rotate each of them independant. As Quistessa showed you, you need only one script and not one per prim. 1 Link to comment Share on other sites More sharing options...
Quistess Alpha Posted May 21, 2021 Share Posted May 21, 2021 3 hours ago, Nova Convair said: As Quistessa showed you, you need only one script and not one per prim. I didn't actually show how to (efficiently) use only one script. Gathering link numbers is a bit of a pain, and IMO not really a 1st time scripting task. For setting prim properties like omega, that are just going to stay static, it's a bit less of a chore to just place a script in the prim you want to have the property, (then take it out again, or set it inactive.) For the record though, two "correct" ways of going about the problem: Method 1: hard coded link numbers: First, after you've linked your thing together how you like it, use a touch-say script to gather the link numbers of the relevant pieces (the link numbers quoted in the build menu can be wrong, especially if you at any point linked together two linksets instead of linking everything in one step) default() { touch_start(integer i) { llOwnerSay("Link: "+llDetectedLinkNumber(0)+" Face: "+llDetectedTouchFace(0)); } } then knowing the link numbers, plug them into some global variables (so you can use them for any other manipulations) integer link1=2; // or whatever you got from step 1. integer link2=3; default { state_entry() { llSetLinkPrimitiveParamsFast(link1, [PRIM_OMEGA,<0,0,1>,TWO_PI/8,1.0]); llSetLinkPrimitiveParamsFast(link2, [PRIM_OMEGA,<0,1,0>,TWO_PI/8,1.0]); } } Method 2: Object Description: Use a specific identifier in the description of the prims you want to manipulate, for this example, set the description of the relevant prims/meshes to Thing1 and Thing2 integer link1; integer link2; // will fill these in state_entry() default { state_entry() { integer index=llGetNumberOfPrims+1; while(--index) { string desc = llList2String(llGetLinkPrimitiveParams(index, [ PRIM_DESC ]), 0); if(desc=="Thing1") { link1=index; }else if(desc=="Thing2") { link2=index; } } llSetLinkPrimitiveParamsFast(link1, [PRIM_OMEGA,<0,0,1>,TWO_PI/8,1.0]); llSetLinkPrimitiveParamsFast(link2, [PRIM_OMEGA,<0,1,0>,TWO_PI/8,1.0]); } } Hope that helps! 2 Link to comment Share on other sites More sharing options...
Nova Convair Posted May 21, 2021 Share Posted May 21, 2021 It depends what this construct is about to do. If it's just rotating then put a script in each prim and once it's rotating the scripts can be removed. (the scripts only start the rotation, removing the script will NOT stop the rotation) If it's planned to toggle the rotation on/off then a better script is needed. Toggle by click? Then you need to click both or send a message from script to script or use one script instead of two. The complexity of a universal solution exceeds the complexity of just making things rotate alot! For an experienced scripter a simple solution can be painful 😁 but for a beginner ... just make the stuff rotate! Anything else is only interesting if there is a general interest to learn how to script. Link to comment Share on other sites More sharing options...
Luxianna Swords Posted May 21, 2021 Author Share Posted May 21, 2021 Thanks, this is all really insightful and gives me some thoughts on what to tinker with. The end name is, i have three objects in total. i want one to rotate clockwise, one to to rotate counter clockwise, and one to rotate top to bottom - but i also need all three objects linked. I am trying to make myself this neat little hand orb thing. I can drop the scripts into the three objects and they work fine independently but when i link them they all default to the what i am assuming is referred to as the primary/root or parent objects script. I've also tried linking everything then editing linked objects and putting the scripts in each object but that didn't work either. I'll try the integer trick from Quintessa. Really appreciate everyone's advice and input. This community is so awesome. Link to comment Share on other sites More sharing options...
Profaitchikenz Haiku Posted May 21, 2021 Share Posted May 21, 2021 (edited) 5 hours ago, Luxianna Swords said: I can drop the scripts into the three objects and they work fine independently but when i link them they all default to the what i am assuming is referred to as the primary/root or parent objects script. If you just want to start them going and leave them spinning on the Prim_property, then delete all scripts, stop any rotations that might be going on, link them, then alter each of your working scripts to replace llTargetOmega(whatever); with Quistessa's suggestion , but use LINK_THIS instead of a had-coded link number llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_OMEGA,[whatever]); Drop each script into the correct child prim's content tab (don't forget to check edit linked part first Then delete each script once you've got it spinning. Edited May 21, 2021 by Profaitchikenz Haiku Link to comment Share on other sites More sharing options...
Quistess Alpha Posted May 21, 2021 Share Posted May 21, 2021 1 hour ago, Profaitchikenz Haiku said: replace llTargetOmega(...) with llSLPPF(LINK_THIS,[...]) I'm pretty sure they're both equivalent, no? Link to comment Share on other sites More sharing options...
Moles Quartz Mole Posted May 22, 2021 Moles Share Posted May 22, 2021 8 hours ago, Luxianna Swords said: Thanks, this is all really insightful and gives me some thoughts on what to tinker with. The end name is, i have three objects in total. i want one to rotate clockwise, one to to rotate counter clockwise, and one to rotate top to bottom - but i also need all three objects linked. I am trying to make myself this neat little hand orb thing. I can drop the scripts into the three objects and they work fine independently but when i link them they all default to the what i am assuming is referred to as the primary/root or parent objects script. I've also tried linking everything then editing linked objects and putting the scripts in each object but that didn't work either. I'll try the integer trick from Quintessa. Really appreciate everyone's advice and input. This community is so awesome. To keep track of which link is which, I always do something like this (there are others to do it, but this is what I do, because I'm used to it and it's automatic by now). integer iClockwisePrim; integer iCounterClockwisePrim; integer iTopToBottomPrim; string strClockwise = "Clockwise"; string strCounterClockwise = "CounterClockwise"; string strTopToBottom = "TopToBottom"; findPrims(){ integer iMax = llGetNumberOfPrims()+1; integer iCounter=1; do { string str = llList2String(llGetLinkPrimitiveParams(iCounter,[PRIM_DESC]),0); if(strClockwise == str){ iClockwisePrim = iCounter; } else if (strCounterClockwise == str){ iCounterClockwisePrim = iCounter; } else if (strTopToBottom == str){ iTopToBottomPrim = iCounter; } } while(++iCounter < iMax); } Call that in state_entry and when the linking changes, and you don't need to worry about link numbers, since iClockwisePrim will always be the one you gave that link description to. Then you can call llSetLinkPrimitiveParamsFast, and set all the different speeds and directions at once, in llSetLinkPrimitiveParamsFast, doing something like this llSetLinkPrimitiveParamsFast(LINK_SET,[ PRIM_LINK_TARGET,iClockwisePrim,PRIM_OMEGA,vAxis1, fSpinrate1, fGain1, PRIM_LINK_TARGET,iCounterClockwisePrim,PRIM_OMEGA,vAxis2, fSpinrate2, fGain2, PRIM_LINK_TARGET,iTopToBottomPrim,PRIM_OMEGA,vAxis3, fSpinrate3, fGain3 ]); with appropriate values for each link's rotation, speed and gain. Doing it that way makes it ever so easy to adjust. 2 Link to comment Share on other sites More sharing options...
Quistess Alpha Posted May 22, 2021 Share Posted May 22, 2021 14 minutes ago, Quartz Mole said: integer iMax = llGetNumberOfPrims()+1; integer iCounter=1; do { Minor nitpick, but ever since I learned backwards iteration from the wiki I never looked back. my automatic loop is something like: integer index = 10; // usually llGetListLength(list); while(--index>=0) { //do things } although the barebones most efficient version is probably something like integer index=10; do{ //do things }while(~--index); 1 Link to comment Share on other sites More sharing options...
Profaitchikenz Haiku Posted May 22, 2021 Share Posted May 22, 2021 (edited) 8 hours ago, Quistessa said: I'm pretty sure they're both equivalent, no? Yes, but I wasn't suggesting a new script. I was attempting to explain that the OP can continue to use their three existing scripts with a small alteration. The new statement would work both on an individual prim when LINK_THIS will return 0, and on a child in a link set. If all they want to do is set the three spinning and never alter them, they could therefore link three static prims, drop the scripts into each one by one, then remove the scripts. Sorry if I've confused you. Edited May 22, 2021 by Profaitchikenz Haiku Link to comment Share on other sites More sharing options...
Mollymews Posted May 22, 2021 Share Posted May 22, 2021 5 hours ago, Quistessa said: barebones most efficient version just adding to the conversation in production code then with lists use: integer n = llGetListLength(alist); while (~--n) { } the reason is that sometimes the list can be empty and when so then we want the While condition to fail when --n < 0. (~-1 = FALSE) with linksets then use integer n = llGetNumberOfPrims(); do { } while (--n); linksets (including linkset of one prim) are in the range 1.. to numberofprims. And we want the while condition to fail when --n = 0 when we know that n can never be 0 (is always >= 1) then use Do..While. Do..While uses 1 less bytecode branch instruction than does While 1 1 Link to comment Share on other sites More sharing options...
Moles Quartz Mole Posted May 22, 2021 Moles Share Posted May 22, 2021 1 hour ago, Mollymews said: just adding to the conversation in production code then with lists use: integer n = llGetListLength(alist); while (~--n) { } the reason is that sometimes the list can be empty and when so then we want the While condition to fail when --n < 0. (~-1 = FALSE) with linksets then use integer n = llGetNumberOfPrims(); do { } while (--n); linksets (including linkset of one prim) are in the range 1.. to numberofprims. And we want the while condition to fail when --n = 0 when we know that n can never be 0 (is always >= 1) then use Do..While. Do..While uses 1 less bytecode branch instruction than does While Is there a significant advantage to de-incrementing iNumberOfPrims (start at the end of the list, and work back) rather than incrementing -iNumberOfPrims (start at beginning of the list and work forwards), especially when the loop runs only rarely? Link to comment Share on other sites More sharing options...
Profaitchikenz Haiku Posted May 22, 2021 Share Posted May 22, 2021 I think so, both on fewer lines of code, fewer potential spots for bugs, and faster execution. To increment, you would, after having got the number of prims, 1) create a second variable (index) initialised to 1 2) in the while loop test, increment index and then test for it still being less than or equal to the maximum. So that's two extra statements and a more complicated test Whilst the optimizer might condense that into more compact bytecode it would still have to allocate two variables where Molly's solution only needs one. Forgetting the optimiser, (which would be just as efficient at oprimizing programmer errors as it would good code) every extra statement you add to a piece of code increases the chances of errors due to programmer misunderstanding, typing errors, forgetfullness, whatever. Link to comment Share on other sites More sharing options...
Moles Quartz Mole Posted May 22, 2021 Moles Share Posted May 22, 2021 (edited) 1 hour ago, Profaitchikenz Haiku said: I think so, both on fewer lines of code, fewer potential spots for bugs, and faster execution. To increment, you would, after having got the number of prims, 1) create a second variable (index) initialised to 1 2) in the while loop test, increment index and then test for it still being less than or equal to the maximum. So that's two extra statements and a more complicated test Whilst the optimizer might condense that into more compact bytecode it would still have to allocate two variables where Molly's solution only needs one. Forgetting the optimiser, (which would be just as efficient at oprimizing programmer errors as it would good code) every extra statement you add to a piece of code increases the chances of errors due to programmer misunderstanding, typing errors, forgetfullness, whatever. I've just done a quick test with lists of different lengths, first counting up from the first item to the last, and then backwards from the last item to the first, and comparing the time it took to process the list each time. list lTest; integer iMax; integer iHowMany; default { touch_end(integer num_detected) { //populate the list do{ lTest +=[(string)iMax]; } while(++iMax< iHowMany); integer n = llGetListLength(lTest); //loop through lTest from start to finish by incrementing -llGetListLength(lTest); iMax =-n + 1; llResetTime(); do{ llSay(-99,llList2String(lTest,iMax));//so I don't have to watch my screen fill up while it counts } while(++iMax); llOwnerSay("With a value of "+(string)iHowMany+" for iHowMany,incrementing -iMax took "+(string)llGetTime()+" seconds to complete"); //loop through lTest from last item to first by de-incrementing llGetListLength(lTest); iMax = n ; llResetTime(); do{ llSay(-99,llList2String(lTest,iMax)); } while(~(--iMax)); llOwnerSay("With a value of "+(string)iHowMany+" for iHowMany, de-Incrementing iMax took "+(string)llGetTime()+" seconds to complete"); } } Results just now on Magnum RC Sandbox 1 (where I happened to be) were: Quote With a value of 25 for iHowMany,incrementing -iMax took 0.022256 seconds to complete With a value of 25 for iHowMany, de-Incrementing iMax took 0.022694 seconds to complete With a value of 100 for iHowMany,incrementing -iMax took 0.043794 seconds to complete With a value of 100 for iHowMany, de-Incrementing iMax took 0.044556 seconds to complete With a value of 250 for iHowMany,incrementing -iMax took 0.132735 seconds to complete With a value of 250 for iHowMany, de-Incrementing iMax took 0.133607 seconds to complete With a value of 1000 for iHowMany,incrementing -iMax took 0.444629 seconds to complete With a value of 1000 for iHowMany, de-Incrementing iMax took 0.422689 seconds to complete YMMV, but I don't see there's much in it, at least not until the lists start to get quite long for SL (I'm normally counting stuff like items in a linkset or an object's inventory, or avatars on a region, so my lists don't normally contain more than a few hundred entries, at most, and normally far fewer). Edited May 22, 2021 by Quartz Mole 2 Link to comment Share on other sites More sharing options...
Wulfie Reanimator Posted May 22, 2021 Share Posted May 22, 2021 1 hour ago, Quartz Mole said: Is there a significant advantage to de-incrementing iNumberOfPrims (start at the end of the list, and work back) rather than incrementing -iNumberOfPrims (start at beginning of the list and work forwards), especially when the loop runs only rarely? Especially when a procedure happens rarely, any minor optimizations are pretty much pointless and up to preference. That said, I would still (and do) use Mollymews' first example because it's the most concise and more appealing than the alternatives. 3 Link to comment Share on other sites More sharing options...
Qie Niangao Posted May 22, 2021 Share Posted May 22, 2021 I too pretty much always decrement through loops; one exception that comes to mind is if there's reason to expect a loop termination condition to be more likely near the front of the list than the rear. One advantage of decrementing is to be able to insert or delete at the current index of the list (or, I suppose llCreate- or -BreakLink on a linkset) and just continue the loop, not needing to adjust the index nor a length-of-list termination condition. 3 Link to comment Share on other sites More sharing options...
Mollymews Posted May 22, 2021 Share Posted May 22, 2021 4 hours ago, Quartz Mole said: test a little thing with this iMax = -n + 1; do { ... llList2String(lTest, iMax)); } while (++iMax); it doesn't produce the 0th element, it should be: iMax = -n; and to a do complete comparison (meaning that it produces the list in reverse order) then iMax = -n; do { ... llList2String(lTest, -iMax-1); } while (++iMax); this said you are right that where possible it is best to use ++ or -- rather than ~++ or ~-- 1 Link to comment Share on other sites More sharing options...
Moles Quartz Mole Posted May 22, 2021 Moles Share Posted May 22, 2021 2 hours ago, Mollymews said: a little thing with this iMax = -n + 1; do { ... llList2String(lTest, iMax)); } while (++iMax); it doesn't produce the 0th element, it should be: iMax = -n; and to a do complete comparison (meaning that it produces the list in reverse order) then iMax = -n; do { ... llList2String(lTest, -iMax-1); } while (++iMax); this said you are right that where possible it is best to use ++ or -- rather than ~++ or ~-- Just to clarify, for other readers, if you change the llSay into llOwnerSay in my example and set iHowMany to 100, you'll see you get the 100 elements, but they're 0--99, not 1--100. So when you're dealing with link numbers, you have to be really careful , because link numbering begins at 1, of course, and it's so easy to get confused. That's why I name my links when I'm storing them in lists, because then it's always llList2Integer(lLinks, iIndex) and I can keep track of what I'm doing. 1 Link to comment Share on other sites More sharing options...
Mollymews Posted May 23, 2021 Share Posted May 23, 2021 (edited) 5 hours ago, Quartz Mole said: Just to clarify, for other readers, if you change the llSay into llOwnerSay in my example and set iHowMany to 100, you'll see you get the 100 elements, but they're 0--99, not 1--100. So when you're dealing with link numbers, you have to be really careful , because link numbering begins at 1, of course, and it's so easy to get confused. That's why I name my links when I'm storing them in lists, because then it's always llList2Integer(lLinks, iIndex) and I can keep track of what I'm doing. in this use case where we are not accessing list element 0 then the comparative test is integer iMax = n; do { } while (--iMax); as (~--iMax) will access the 0th list element which we don't want in this use case edit add: i also point out that Quartz is making a general point which is true. integer addition is more efficient than subtraction i just add on here as part of the conversation. The general rule that I go by is that a computer algorithm is more efficient when it uses the least number of clock cycles to complete its task. And in a shared environment, like LSL, then the general rule within a clock cycle is the least number of instructions LSL Mono is a little bit awkward to work with as we don't know much about the hardware that it runs on, and while we can surmise that the LSL CIL produced pretty much conforms with the Microsoft CIL standards, we don't know this for sure. As pretty much every compiler has its own tweaks to optimise performance for its specific task, and we (residents) don't have an indication from Linden of what they might be if there are any. And we don't have the code debugging/profiling tools that other coding language environments provide to peek into this ourselves hopefully maybe one day. And if that was only a variable watch window then I would be quite happy with that. More happier tho with breakpoints as well Edited May 23, 2021 by Mollymews 1 Link to comment Share on other sites More sharing options...
Bugs Larnia Posted May 27, 2021 Share Posted May 27, 2021 Do keep in mind that the rotation axis will differ when you link or attach prims to other prims. As it says on the Wiki: Link Sets If the script is attached to the root prim, the entire object rotates around the region axis. If the object is attached then it rotates around the attachment axis. If the script is attached to a child prim, the prim rotates around the local axis. A child prim can rotate around its own axis while the entire object rotates around another axis. Link to comment Share on other sites More sharing options...
Recommended Posts
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