Showing posts with label llSetTimerEvent. Show all posts
Showing posts with label llSetTimerEvent. Show all posts

Wednesday, July 30, 2008

Second Life Physics Scripting - Pinball #23 - llRez and llDie

The next feature is to remove the ball when it hits the back wall and then to have it respawn when the user presses the page up key.

The first problem is that the ball has to remove itself. There doesn't seem to be a way to have a script remove another object.

I first set out to have the ball remove itself when it had a collision with the back wall. The problem with this is that the back wall is linked and the collision name had "pinball 1.4" which may change over time and that this collision only occured once when the ball was first placed on the table since it is all one linked set.

The next solution is to send a message to the ball when the back wall is hit and I did this with the chat system llSay.


if (llDetectedName(0) == "ball")
{
...
//llPushObject(llDetectedKey(0), pos3, <0,0,0>, FALSE);

llSay(1296,"byebye");

}

This was as simple as removing the push and adding the llSay. The next step is to have the ball listen for the message.

integer listen_handle;

default
{
state_entry()
{
listen_handle = llListen( 1296, "backwall", NULL_KEY, "" );
}
listen(integer channel, string name, key id, string message)
{

//llOwnerSay("ball listen, heard = "+name);
if ((channel==1296) && (llToLower(message) == "balldied"))
{
//llOwnerSay("Ball died!");
llDie();
}
}

}

The ball is listening for the object backwall to say "byebye" on channel 1296. At first I thought this would be too slow, but it seems very quick and the ball goes away before bouncing back onto the table.

Make sure you keep a copy of the ball in your inventory because when it dies you don't want to have to recreate the scripts over and over.

The next step is the spawning of the ball (llRez) when the user presses the page up key. I did this in the PayAndKeyboard script in root table object. This is the same script that handles the key presses to move the puck flipper.


RezBall()
{
if (!in_play)
{
in_play = TRUE;

// find the size of the this table
vector sz = llList2Vector(llGetPrimitiveParams([PRIM_SIZE]),0);

vector pos = llGetPos();
//llOwnerSay("pos = "+(string)pos);
vector up = llVecNorm(pos * llGetLocalRot());
up = up * ((sz.z/2) + 0.21); // add the size of the ball
//llOwnerSay("up = "+(string)up);

pos = pos + up;
//llOwnerSay("rez pos = "+(string) pos);

llRezObject("ball",pos,<0,0,0>,ZERO_ROTATION,0);
}
}

I wrote a separate function for the rez ball. This still has problems as I think it rezes the ball too low on the table, but it has a neat effect in that the ball sort of oozes out of the table. It needs looking into at some point.

Next is the event to rez the ball.

control(key id, integer held, integer change)
{
... puck flipper code

// page up key
if ((held&CONTROL_UP) && (change&CONTROL_UP))
{
if (!in_play)
{
llSay(0," here we go!!!");
}
RezBall();
}
}


Then we have to have a way to reset the in_play flag so the user can press the "page up" key again and have the ball rez. This is as simple as adding the listen method the same as we used for the ball. Both the ball and this PayAndKeyboard script will both hear the same message from the backwall.

state_entry()
{

listen_handle = llListen( 1296, "backwall", NULL_KEY, "" );
llSetTimerEvent(30);

... other initialization code
}

listen(integer channel, string name, key id, string message)
{
if ((channel==1296) && (llToLower(message) == "balldied"))
{
llSay(0,"Oops, drain. Press 'Page Up' to start another ball.");
in_play = FALSE;
llSetTimerEvent(30);
}
}

As you can see I also added some timer events. This is so the table is actually doing something when people first walk up to it. A teaser to get people interested. 30 seconds after every drain, then timer goes off. If the ball isn't already in play (because someone pushed page up), then a new ball is spawned.

timer()
{
if (!in_play)
{
llSay(0,"Autoplay starting");
RezBall();
}
llSetTimerEvent(0);
}

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.