Wednesday, September 1, 2010

Second Life Game Tile Testing


I've been messing around with game tile systems again using second life. Looking at the rudiments of a table top game like checkers, chess or even something as complex as monopoly. Trying to figure out how to develop something that doesn't use physics, but uses a tile based movement system.

I started by building a blank table top and adding a piece to it. Right now, the piece simply moves from corner to corner when someone clicks on the table. Under the hood there is a lot more going on than you might first think.



This is the code in the init script in the table.

default
{
state_entry()
{

//list bb = llGetBoundingBox(llGetKey()); // get my bounding box
vector sz = llList2Vector(llGetPrimitiveParams([PRIM_SIZE]),0);
llMessageLinked(LINK_ALL_OTHERS,1,(string)sz,NULL_KEY);
}

touch_start(integer total_number)
{
//llSay(0, "Touched.");
llSay(1024,"move");
}
}

You might as why did I comment out llGetBoundingBox. The reason is it works great when the table is by itself, but once the piece is on the table, the piece's location is included in the bounding box. This makes the box larger than expected.

So, the script get's the actual prim size from the table top and passes it to all the other linked objects (in this case the "disc" using a linked message. The identifier of the message is the number "1" which in this case means "table size", and the size (vector) is passed as a string.


You can also see that when the table is touched, it says "move" on channel 1024 which you can guess that the "disc" is listening for. Why not use llMessageLinked for both communications? We'll I should, but the "move" message was added early on and I started using linked messages later and have to get back to change to use llMessageLinked.


This is the code for the disc

vector mysize;
vector mysizediv2;
vector tablesize;
vector min;
vector max;
integer posMinOrMax;

default
{
state_entry()
{
//list bb = llGetBoundingBox(llGetLinkKey(1)); // get the bounding box of the table
//max = llList2Vector(bb, 1); // max corner
//min = llList2Vector(bb, 0); // min corner
//min = >min.x,min.y,max.z<;

//llWhisper(0,(string)min+" "+(string)max);

posMinOrMax = 0;

llListen(1024,"",llGetLinkKey(1),"move");
}


listen( integer channel, string name, key id, string message )
{
if (channel==1024)
{
if (posMinOrMax==0)
{
llSetPos(max);
//llWhisper( 0, "max" );
}
else
{
llSetPos(min);
//llWhisper( 0, "min" );
}
posMinOrMax = 1 - posMinOrMax;

}
}

link_message(integer sender_num, integer num, string str, key id)
{
if (num==1)
{
mysize = llList2Vector(llGetPrimitiveParams([PRIM_SIZE]),0);
mysizediv2 = mysize / 2;
mysizediv2.z = 0.0;

tablesize = (vector) str;
llWhisper(0,"got size = "+(string)tablesize);
vector sz = tablesize / 2;
min = >-sz.x,-sz.y,sz.z*2< + mysizediv2;
max = >sz.x,sz.y,sz.z*2< - mysizediv2;

}
}
}

You can see that early on I calculated the min and max positions based on the bounding box which I have already said is wrong. On the listen channel when I hear "move" I toggle the position between the min and max. That should be pretty straight forward.


The interesting stuff is in the link_message function. I first get the size of the "disc" using the llGetPrimitiveParams call. All positioning is done from the center of the object, so if I use the absolute min and max sizes of the table then the disc will hang off the edge. I divide the size by two because that is how far I have to inset the position from the table's min and max.

I then convert the table size vector from the string that was passed on the link message back to a vector and calculate the min and max positions using the inset of half the disc size. The min adds half the disc size and the max subtracts. The other thing is that the table's origin is at the center, and positioning the disc has to take that into account. So the min is the table position (center) subtracting half the size of the table. The max is the table position (center) and adding half the table size.