Quistess Alpha Posted July 27, 2021 Share Posted July 27, 2021 (edited) Sometimes when we get into one way of thinking about a problem, it can be hard to realize that there might be other, better solutions. Case and point; I had convinced myself that it was necessary to use 2 separate prims for a movable dial/slider object, because I had really focused myself on using llDetectedTouchST, and if the object moves, that changes where you're touching and leads to some recursive nonsense, which it's possible but not very nice to get around: // Not ideal single-prim dial script. // drop into a linked prim and click-drag on face 0: float gAngTouchStart; default { state_entry() { llMinEventDelay(0.2); // a slower event speed is in-fact neccessary to prevent a feedback loop. // expiramentally anything below 0.2 causes some kickback; below 0.1 or so it spins wildly out of control. } touch_start(integer total_number) { if(llDetectedTouchFace(0)!=0) return; vector pos = llDetectedTouchUV(0); gAngTouchStart = llAtan2(pos.y-0.5,pos.x-0.5); } touch(integer n) { if(llDetectedTouchFace(0)!=0) return; vector pos = llDetectedTouchUV(0); float angTouch = llAtan2(pos.y-0.5,pos.x-0.5); float angDiff=angTouch-gAngTouchStart; llSetLinkPrimitiveParamsFast(LINK_THIS, [ PRIM_ROT_LOCAL, llEuler2Rot(<0,0,angDiff>)* llList2Rot(llGetLinkPrimitiveParams(LINK_THIS,[PRIM_ROT_LOCAL]),0) ]); } } After taking a breather though, I realized it is in-fact possible to get around this using llDetectedTouchPos, and absolute positions: //same idea but much smoother: vector gPosRest; rotation gRotRest; float gAngGrabPrev; // previous grab angle. float gAngSet; // angle the dial is set to. float angNorm(float a) { return a-llFloor(a/TWO_PI)*TWO_PI; } default { state_entry() { gPosRest=llList2Vector(llGetLinkPrimitiveParams(LINK_THIS,[PRIM_POSITION]),0); gRotRest=llList2Rot(llGetLinkPrimitiveParams(LINK_THIS,[PRIM_ROT_LOCAL]),0); llSetText((string)gAngSet,<0,1,0>,1.0); } touch_start(integer n) { if(llDetectedTouchFace(0)!=0) return; // dials only really make sense as disks. //gRotTStart=llList2Rot(llGetLinkPrimitiveParams(LINK_THIS,[PRIM_ROT_LOCAL]),0); vector posGrabStart = (llDetectedTouchPos(0)-gPosRest)/gRotRest; gAngGrabPrev = llAtan2(posGrabStart.y,posGrabStart.x); } touch(integer n) { if(llDetectedTouchFace(0)!=0) return; vector posGrab = (llDetectedTouchPos(0)-gPosRest)/gRotRest; float angGrab = llAtan2(posGrab.y,posGrab.x); float angChange =angGrab-gAngGrabPrev; if(angChange<-PI) { angChange+=TWO_PI; }else if(angChange>PI) { angChange-=TWO_PI; } gAngGrabPrev=angGrab; gAngSet+=angChange; llSetText((string)gAngSet,<0,1,0>,1.0); rotation rotLocal = llList2Rot(llGetLinkPrimitiveParams(LINK_THIS, [ PRIM_ROT_LOCAL]),0); llSetLinkPrimitiveParamsFast(LINK_THIS, [ PRIM_ROT_LOCAL, llEuler2Rot(<0,0,gAngSet>)*gRotRest ]); } touch_end(integer n) { // inform main script about our new setting. llMessageLinked(LINK_ROOT,0,"Dial Setting",(key)((string)gAngSet)); } } and the same idea can be applied to sliders: vector gPosRest; vector gPosTStart; vector gPosGrabStart; integer gTouchFace; default { state_entry() { gPosRest=llList2Vector(llGetLinkPrimitiveParams(LINK_THIS,[PRIM_POS_LOCAL]),0); } touch_start(integer n) { gPosTStart=llList2Vector(llGetLinkPrimitiveParams(LINK_THIS,[PRIM_POS_LOCAL]),0); gPosGrabStart = llDetectedTouchPos(0); gTouchFace=llDetectedTouchFace(0); } touch(integer n) { if(llDetectedTouchFace(0)!=gTouchFace) return; vector posChange = llDetectedTouchPos(0)-gPosGrabStart; // choose 1 or none of the following 3 to constrain to a single axis: posChange = <posChange.x,0,0>; //posChange = <0,posChange.y,0>; //posChange = <0,0,posChange.z>; //limit the total movement (remove this paragraph for unlimited drag potential) // replace x with desired axis: vector posSet = gPosTStart+posChange-gPosRest; if(posSet.x<-0.5) posSet.x=-0.5; else if(posSet.x>0.5) posSet.x=0.5; llSetLinkPrimitiveParamsFast(LINK_THIS, [ PRIM_POS_LOCAL, posSet+gPosRest ]); } touch_end(integer n) { vector posSet = llList2Vector(llGetLinkPrimitiveParams(LINK_THIS,[PRIM_POS_LOCAL]),0)-gPosRest; llSetText((string)posSet,<0,1,0>,1.0); //llMessageLinked ... // inform main script about our new setting. } } Of course it's better practice to integrate this sort of thing into a single script, rather than having a script per interactable (huh, not in my web-browser's dictionary. . .fixed.) element, but I'll leave that as an 'exercise for the reader' Edited July 27, 2021 by Quistess Alpha 3 4 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