Showing posts with label llGetRot. Show all posts
Showing posts with label llGetRot. Show all posts

Tuesday, July 22, 2008

Second Life Physics Scripting - Pinball #17 - Flipper Rotations Working

Rotations, what a nightmare. A nightmare of my own making, but I finally got the problem solved and it looks like I mostly had confused myself, but after lots of reading and a thousand tests I finally got the flipper to rotate on the test table.



Here is the final code for the timer routine that rotates the flipper in x number of steps.


timer()
{
if (((rotation_tick>0) && (cur_rotation<max_rotation)) ||
((rotation_tick<0) && (cur_rotation>max_rotation)))

{
cur_rotation = cur_rotation + rotation_tick;

// what is currently pointing up in the z direction
// was originally in the -y direction.
if (!orig_axis_flag)
{
orig_axis_flag = TRUE;
orig_axis = llVecNorm(<0,-1,0> * llGetLocalRot());
}

// a rotation around the parents z normal
//rotation z_45 = make_quaternion(parent_norm,rotation_tick*DEG_TO_RAD);
rotation z_45 = llAxisAngle2Rot(orig_axis,rotation_tick*DEG_TO_RAD);

// we need to find the axis which is the heal of the wedge
// the original orientation of the flipper wedge is <0,0,1>
// i use -1 to point at the heal of the wedge
vector norm = <0,0,-1>;
// rotate that norm so it points towards the point of the wedge
norm = llVecNorm(norm * llGetLocalRot());
// find the size of the wedge
vector sz = llList2Vector(llGetPrimitiveParams([PRIM_SIZE]),0);
// get the center location of the wedge
vector flipper_pos = llGetLocalPos();
// find the offset distance from the center
vector offset = norm * (sz.z / 2);
// add that offset to the flipper_pos to get the axis
vector rot_axis = flipper_pos + offset;

// calculate the new rotation by adding the z axis rotation
// z_45 is the old name it is really z_plusang
rotation new_rot = llGetLocalRot()*z_45;
// http://wiki.secondlife.com/wiki/Rotation
// set the new local rotation
llSetLocalRot(new_rot);

// lsl wiki solution for non center rotation
vector new_pos = rot_axis + ((flipper_pos - rot_axis) * z_45);
llSetPos(new_pos);
}
else
{
// stop the timer and wait for the off event
llSetTimerEvent(0);
}
} // timer

It turns out that the basic problem I was having was that I didn't think there was a llSetLocalRot because I already knew there wasn't a llSetLocalPos. So that final call to llSetLocalRot was llSetRot for the longest time and this added a little extra y rotation which caused the flipper to lean in the wrong direction. This was a ton of time to actually find this problem, but rotation can be like that and this is really just another bug in a long development process.

The crazy part is that I continued to work on this even though I knew the mechanic was not going to work. The flipper just takes too long to rotate each step and I don't want a flipper that only has two angles of bounce. Very annoying that there is a lot of work there and the api/engine doesn't support the mechanic I want to use, but then this is the way in software development. You have to make your designs fit the platforms you use and hope people make good platforms. SL is good, but there are a number of changes I would like to see made, but I don't think that is any different than any other api/platform.

I'd rather not see them do the kitchen sink stuff that was done with Java and basically ruined a very nice small system. Then again, they ignored the client side and just gave it up to flash which was a huge mistake that can't really be addressed at this point because now they made the foot print way too big to be a client side platform. I still love Java, I just think Schwartz badly mismanaged it just like he has mismanaged Sun. Sorry for the short rant.

So I think I'm going to use textures to do flippers flat near the back of the machine. We'll see how that turns out next.

Thursday, July 17, 2008

Second Life Physics Scripting - Pinball #14 - Flipper Rotation Off Axis Issue

I've spent way too much time trying to get the flipper to rotate properly. I'm not even sure if it will work properly when I do get it to rotate, but now I'm on a mission to get this working.

Basically there are two rotation pages.
http://www.lslwiki.net/lslwiki/wakka.php?wakka=rotation
http://wiki.secondlife.com/wiki/Rotation

The rotation from the center of the flipper works great, the off axis rotation is even harder. I think I spent a lot of time on one flipper that was rotated differently than I thought so I started over with a new flipper and the same code.

Basically, I need to calculate the base/heal of the flipper. I do this by looking at the initial orientation of the tip of the flipper and it was straight up in the z direction. I take the negative z vector and multiply it by the starting rotation which points me in the direction of the heal and convert it to a unit vector. I then multiply that unit vector by half of the z size which should give the the starting location of the heal offset from the center of the flipper. Tricky. That will be the point of rotation and that is what I've struggled with so far.

Both wiki's say it should be fairly straight forward, but I keep getting a rotational axis that is missing the mark.

Here is the current (not working code with a ton of test code). The test code is not offset so I can find it more easily.

link_message(integer from, integer msg_id, string str, key id)
{
if (msg_id == MSG_RIGHT_ON_NUM)
{
//llOwnerSay("right flipper on");
//llSetLocalRot(end_rot);
// a rotation of 45 degrees around the x-axis
rotation x_45 = llEuler2Rot( <0, 0, -45 * DEG_TO_RAD> );


// the original orientation of the flipper wedges is <0,0,1>
// i use -1 to point at the heal of the wedge
vector norm = <0,0,-1>;
// rotate that norm so it points towards the point of the wedge
norm = llVecNorm(norm * llGetLocalRot());

// find the size of the wedge
vector sz = llList2Vector(llGetPrimitiveParams([PRIM_SIZE]),0);
llOwnerSay("size = "+(string)sz);
vector offset = norm * (sz.z / 2);
vector rot_axis = start_pos + offset;
llMessageLinked(dbg_marker, 1,(string)rot_axis, NULL_KEY);
llOwnerSay("distance from center to heal = "+(string)offset);
llOwnerSay("get rot = "+(string)llGetRot());
rotation new_rot = llGetLocalRot() * x_45; // compute global rotation
//new_rot = new_rot * norm;
// http://wiki.secondlife.com/wiki/Rotation
// find the rotated norm
vector rotated_offset = offset * new_rot;
llOwnerSay("new rot = "+(string)new_rot);
llSetLocalRot(new_rot);

llOwnerSay(" cur pos = "+(string)llGetLocalPos());
vector offsettimesrot = (-offset*new_rot);
llOwnerSay("offset times rot ="+(string)offsettimesrot);
vector new_pos = rot_axis + (offset * new_rot);
//vector new_pos = llGetLocalPos() - (offset * llGetLocalRot());
//vector newPos = llGetPos() + (offset - rotatedOffset) * llGetRot()
llOwnerSay(" new pos = "+(string) new_pos);
llSetPos(new_pos);

}
else if (msg_id == MSG_RIGHT_OFF_NUM)
{
//llOwnerSay("right flipper off");
llSetLocalRot(start_rot);

// already in local coords since child prim
llSetPos(start_pos);
}
}

At this point I'm having trouble visualizing the actual origin that is being rotated, so I've created a thin black cylinder called "dbg_marker" and I'm going to position that what I calculate to be the origin of the heal.


As usual I can find the marker by traversing the link list.


test_find_marker()
{
integer current_link_nr = llGetNumberOfPrims();
// Check if it's more than one
if (1 < current_link_nr)
{
// avatars sitting on us get added at the end, so subtract...
while (llGetAgentSize(llGetLinkKey(current_link_nr)))
--current_link_nr;

while(current_link_nr>0)
{
if (llGetLinkName(current_link_nr)=="dbg_marker")
{
llOwnerSay("found dbg_marker: "+(string)current_link_nr);
dbg_marker = current_link_nr;
}
current_link_nr--;
}
}
}

The code to actually move the marker is yet another link message and some code in the marker. There really isn't a lot of api code to move another object to a specific location, you have to send a message to the object and have it move itself. Sort of a pain, but it forces you to separate out your logic which is a good thing.

Here is the code placed in the dbg_marker to move it to the location.

default
{
state_entry()
{

}

link_message(integer from, integer msg_id, string str, key id)
{
if (msg_id == 1)
{
vector vpos = (vector)str;
llOwnerSay("dbg_marker position"+(string)vpos);

llSetPos(vpos);
}
}
}


Then this final screen shot which shows that the location I calculated with all that crazy math was actually precisely on target.


It is obviously very very close to working, I just have a transformation out of order or something... Hmmm.... Welcome to my world.

Wednesday, July 16, 2008

Second Life Physics Scripting - Pinball #13 - Flipper Rotation Issues

I've got the first flipper movement. It doesn't actually orient correctly or rotate around the correct axis, but it is movement and the rest is just some extra math.

I took the start rotation and end rotation ligning up the flipper where I wanted it, then running the script to see the rotation. This doesn't seem to work as the rotation is not the same as how I lined it up, but it's close and late at night and deserves to be a stopping point.


Here is the script in the flipper.

integer MSG_RIGHT_ON_NUM = 5115;
integer MSG_RIGHT_OFF_NUM = 5116;
integer MSG_LEFT_ON_NUM = 5117;
integer MSG_LEFT_OFF_NUM = 5118;

rotation start_rot = <0.35240, 0.55950, 0.62163, 0.41994>;
rotation end_rot = <0.66946, 0.22398, 0.36898, 0.60458>;

default
{
state_entry()
{
//start_rot = llGetRot();
llOwnerSay("right rot = "+(string)llGetRot());
llSetRot(start_rot);
}

link_message(integer from, integer msg_id, string str, key id)
{
if (msg_id == MSG_RIGHT_ON_NUM)
{
llOwnerSay("right flipper on");
llSetRot(end_rot);
}
else if (msg_id == MSG_RIGHT_OFF_NUM)
{
llOwnerSay("right flipper off");
llSetRot(start_rot);
}
}
}


Here is the code in the main object that takes over the controls.

integer MSG_RIGHT_ON_NUM = 5115;
integer right_flipper = -1;

integer MSG_RIGHT_OFF_NUM = 5116;
integer MSG_LEFT_ON_NUM = 5117;
integer MSG_LEFT_OFF_NUM = 5118;

state_entry()
{
integer current_link_nr = llGetNumberOfPrims();
// Check if it's more than one
if (1 < current_link_nr)
{
// avatars sitting on us get added at the end, so subtract...
while (llGetAgentSize(llGetLinkKey(current_link_nr)))
--current_link_nr;

while(current_link_nr>0)
{
if (llGetLinkName(current_link_nr)=="right_flipper")
{
llOwnerSay("found right_flipper: "+(string)current_link_nr);
right_flipper = current_link_nr;
llMessageLinked(right_flipper, MSG_SET_PARENT_ROT, (string)llGetRot(), NULL_KEY);

}
current_link_nr--;
}
}
}

control(key id, integer held, integer change)
{
//llSay(0, "control id="+(string)id);
//llSay(0, " held="+(string)held+" change="+(string)change);
//llSay(0, " ROT_RIGHT"+(string)CONTROL_ROT_RIGHT);
if ((held&&CONTROL_ROT_RIGHT) && (change&&CONTROL_ROT_RIGHT))
{
//llSay(0," right flipper on");
llMessageLinked(right_flipper, MSG_RIGHT_ON_NUM, "", NULL_KEY);

}
else if (((held&&CONTROL_ROT_RIGHT)==0) && (change&&CONTROL_ROT_RIGHT))
{
//llSay(0," right flipper off");
llMessageLinked(right_flipper, MSG_RIGHT_OFF_NUM, "", NULL_KEY);
}
}

As you can see I'm using linked messages to tell the flipper to rotate. This is normal. Also, the control code is a separate script in the root object. Now my root object has 8 scripts. Blank Collision, Bumper, LinkNanny, LinkNanny-bumper, LinkNanny-sidewall, PayAndKeyboard, RootNanny, side-wall-bounce. LSL almost requires that you break up your code into different and more manageable scripts.