Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Rotating object B the difference of object A

Dzar Overlord
Registered User
Join date: 16 Mar 2007
Posts: 8
04-11-2007 07:30
Hey there. I'm having troubles getting a script to work correctly for me. I have two objects, Object A and Object B. Both objects will each have their own rotation. I, however, need it to be so that when Object A is rotated it determines the difference between it's old and new rotations and messages that to Object B (which is not linked) to rotate that same difference. Object B however can be rotated without Object A being affected.

I know I have to user a timer event in the first place to detect the rotation change and use a negative channel to communicate on between the two scripts in each object but that's about as far as I can get it.

I'm trying to build a multi jointed robotic arm with the basic effect being similar to how the elbow works. As you bend your elbow your hand moves with the elbow staying aligned with your arm. In the case of the robotic arm, as one joint moves all the other joints and arm pieces will move as well with it but have a sort of "stiffness" like your wrist does in the before mentioned example.

Thanks for the help in advance.
Deanna Trollop
BZ Enterprises
Join date: 30 Jan 2006
Posts: 671
04-11-2007 09:40
What you want to do is actually a two-step process. When Object A (the hierarchical parent) rotates about it's pivot, you want Object B (the hierarchal child) to rotate by the same amount, and also translate to match up with it's relative position to A before it was rotated. In effect, you want B to rotate about A's pivot. So what you need to do is have A supply B with two pieces of information: it's pivot point, and the differential rotation.

In the Parent:
Declare a global variable, call it something like LastRot. Store llGetRot there in default state_entry. Inside timer, if llGetRot and LastRot aren't equal, divide llGetRot by LastRot. This will give you the differential rotation. Communicate that to the child object(s), as well as the parent's llGetPos(), separated by a comma.

In the Child:
In listen, parse the vector and quat apart. Subtract the Parent's position from the child's, this will give you the child's offset relative to the parent. Multiply this offset by the differential rotation, this will give you the child's new position. Multiply llGetRot by the differential rotation, this will give you the child's new rotation. Use llSetPos and llSetRot, or llSetPrimitiveParams to apply the new position and rotation to the child.
Dzar Overlord
Registered User
Join date: 16 Mar 2007
Posts: 8
Can't get the scripting to work
04-12-2007 06:19
I'm having trouble getting the script to do as you said. Below are the scripts that I made for the different objects.

Using the llSetPos() in the child prim ends up moving it 10m downward. Had to search to find it. The llSetRot() doesn't do anything. Using the llOwnerSay() I have commented out below the llSetPos() returns the same values when I rotate it one way and the Ctrl+Z to undo back to it's original position. In this case it was: <-0.36036, 0.60762, -0.23534, 0.66750>.

Again all help is much appreciated. Thanks.


In the parent:
CODE

rotation old_rotate;

default
{
state_entry()
{
llSetTimerEvent(1.0);
}

timer()
{
rotation diff_rotate;
rotation new_rotate = llGetRot();
if (old_rotate != new_rotate)
{
diff_rotate = new_rotate / old_rotate;
llWhisper(-1000, "ruar*" + (string)diff_rotate + "*" + (string)llGetPos());
old_rotate = new_rotate;
}
}
}



In the child:
CODE

default
{
state_entry()
{
llListen(-1000, "", NULL_KEY, "");
}

listen(integer chan, string name, key id, string msg)
{
if (llGetOwnerKey(id) == llGetOwner())
{
list joints = llParseString2List(msg, ["*"], []);
string speaker = llList2String(joints,0);
if (speaker == "ruar")
{
vector offset = llGetPos() - (vector)llList2String(joints,2);
vector new_pos = offset * llList2Rot(joints,1);
rotation new_rot = llGetRot() * llList2Rot(joints,1);
llSetRot(new_rot);
// llSetPos(new_pos);
// llOwnerSay((string)new_rot);
}
}
}
}
// llWhisper(-1000, "ruar*" + (string)diff_rotate + "*" + (string)llGetPos());
Newgate Ludd
Out of Chesse Error
Join date: 8 Apr 2005
Posts: 2,103
04-12-2007 07:22
You may need to get your data out as a string and cast to a rotation rather than use llList2Rot as the data stored in the list will be a string representation of a rotation not an actual rotation.

CODE

default
{
state_entry()
{
llListen(-1000, "", NULL_KEY, "");
}

listen(integer chan, string name, key id, string msg)
{
if (llGetOwnerKey(id) == llGetOwner())
{
list joints = llParseString2List(msg, ["*"], []);
string speaker = llList2String(joints,0);
if (speaker == "ruar")
{
rotation rot = (rotation)llList2String(joints,1);
vector pos = (vector)llList2String(joints,2);
vector offset = llGetPos() - pos;
vector new_pos = offset * rot;
rotation new_rot = llGetRot() * rot;
llSetRot(new_rot);
// llSetPos(new_pos);
// llOwnerSay((string)new_rot);
}
}
}
}
Deanna Trollop
BZ Enterprises
Join date: 30 Jan 2006
Posts: 671
04-12-2007 10:32
OOPS. I forgot one crucial step. The child's new position should it's offset multiplied by the diff rotation, plus the parent's position.

CODE

vector new_pos = offset * rot + pos;
As it is now, it's trying to literally move to it's new offset in global coordinates, which will be down near <0,0,0>, but llSetPos will only move 10m at a time, so that's where it stays. Sorry 'bout that, my fault for not testing.

What Newgate said about casting the rotation from a string manually as you already did with the vector, is also correct.

[Edit: Grrrr.... apparently my method for determining differential rotation doesn't work when z-axis rotations are involved. Quats really are evil :mad: ]

[Edit #2: Oh, also, your original script doesn't save the initial rotation in default state_entry, so if the child is listening when the script starts/resets, and the parent is at anything other than ZERO_ROTATION, the child will move as though the parent had just changed from ZERO_ROTATION, above caveat notwithstanding. ]
Deanna Trollop
BZ Enterprises
Join date: 30 Jan 2006
Posts: 671
04-12-2007 12:05
Ok, enough post-scripts to my last message. :cool:

The following works, though it might not be optimal. Changes to original code noted.

Parent:
CODE

rotation old_rotate;

default
{
state_entry()
{
old_rotate = llGetRot(); // added, initial rotation must be stored
llSetTimerEvent(1.0);
}

timer()
{
rotation new_rotate = llGetRot();

if (old_rotate != new_rotate)
{
// Send both old and new rotations to the child,
// instead of a differential
llWhisper(-1000, "ruar*" + (string)new_rotate + "*" + (string)old_rotate + "*" + (string)llGetPos());
old_rotate = new_rotate;
}
}
}


Child:
CODE
default
{
state_entry()
{
llListen(-1000, "", NULL_KEY, "");
}

listen(integer chan, string name, key id, string msg)
{
if (llGetOwnerKey(id) == llGetOwner())
{
list joints = llParseString2List(msg, ["*"], []);
string speaker = llList2String(joints,0);

if (speaker == "ruar")
{
// read and store individual list components first,
// as in Newgate's example, rather than inline
vector pos = (vector)llList2String(joints,3);
rotation old_rot = (rotation)llList2String(joints,2);
rotation new_rot = (rotation)llList2String(joints,1);

// calculate offset in "parent-space"
vector offset = ( llGetPos() - pos ) / old_rot;

// calculate new position in "parent-space"
vector new_pos = offset * new_rot + pos;

// calculate rotation in "parent-space"
new_rot = ( llGetRot() / old_rot ) * new_rot;

// perform translation and rotation operations at once
llSetPrimitiveParams( [ PRIM_POSITION, new_pos, PRIM_ROTATION, new_rot ] );
}
}
}
}