Flugelhorn McHenry
Valved bugle
Join date: 10 Jul 2004
Posts: 34
|
08-11-2005 11:14
I have an object (let's call it Mother), around which I want to create a host of Baby objects, each at the same radius from Mother. What I want to do is to be able to rez a load of contestants' seats arranged around a host's podium. So I think I want to create a function which would take the following parameters: - Radius
- Arc through which to distribute Babies
- Number of Babies required
I've done a fair bit of scripting in SL but have always shied away from anything involving complicated geometry or trigonometry, as I had bubonic plague when they taught geometry and trig at school. Could someone please point me towards the LSL functions I will need to look at to work out the vector of each baby object in order to rez it? If you could nudge me even further in the right direction I would appreciate it v v muchly. Flugelhorn
|
Cid Jacobs
Theoretical Meteorologist
Join date: 18 Jul 2004
Posts: 4,304
|
08-11-2005 11:30
From: Flugelhorn McHenry I have an object (let's call it Mother), around which I want to create a host of Baby objects, each at the same radius from Mother. What I want to do is to be able to rez a load of contestants' seats arranged around a host's podium. So I think I want to create a function which would take the following parameters: - Radius
- Arc through which to distribute Babies
- Number of Babies required
I've done a fair bit of scripting in SL but have always shied away from anything involving complicated geometry or trigonometry, as I had bubonic plague when they taught geometry and trig at school. Could someone please point me towards the LSL functions I will need to look at to work out the vector of each baby object in order to rez it? If you could nudge me even further in the right direction I would appreciate it v v muchly. Flugelhorn You could just use llGetPos and llGetScale to get the distance out you need to rez them right? add half of the local x or y axis to the x or y value of the returned pos. *edit* you could always you llRot2Fwd or llRot2Left or llRot2Up to get the vector infront of where you want to rez the object, then all you would need to do is add the vector offset of the radius to it.
|
Eloise Pasteur
Curious Individual
Join date: 14 Jul 2004
Posts: 1,952
|
08-11-2005 11:56
Um, doing it the trig way is actually easier I suspect, at least if you want them in a plane.
For radius R, number of seats n, arc ?, if you start at positive X from the mother (you've not defined that yet):
Seat 1 is at <R, 0, 0>+llGetPos() The seats are actually 2n?/? radians apart, which I'll call µ. Seat 2 is at <Rcosµ, Rsinµ, 0>+llGetPos() Seat 3 is at <Rcos2µ, Rsin2µ, 0>+llGetPos()
etc.
This can better be done in a for loop as seat 0 at <Rcosiµ, Rsiniµ, 0> as the offset you add to llGetPos(), using i as the count of the number of seats in the for loop.
to define your arc with a starting offset of ß this becomes <Rcos(iµ+ß), Rsin(iµ+ß), 0>
pass the angle (times 1000 say) as the number when rezzing, and you can apply that as the z-rotation to the rezzed babies.
Remember there's a range limit on rezzing!
|
Seifert Surface
Mathematician
Join date: 14 Jun 2005
Posts: 912
|
08-11-2005 12:28
From: Eloise Pasteur pass the angle (times 1000 say) as the number when rezzing, and you can apply that as the z-rotation to the rezzed babies.
Remember there's a range limit on rezzing! You can set the angle in the llRezObject function so you shouldn't need to get the babies to rotate themselves (though passing stuff in when you rez is a neat trick). The rezzing range could be more of a problem - having the whole setup end up inside a 10m radius circle might not be big enough for you. BTW, to work out what rotation to use, I'd look at llAxisAngle2Rot, with your axis vertical (<0,0,1>  and your angles as Eloise outlined.
_____________________
-Seifert Surface 2G!tGLf 2nLt9cG
|
Blain Candour
Registered User
Join date: 17 Jun 2005
Posts: 83
|
08-12-2005 03:10
o.O Taco Bell?... Really though I took AP calc, trig, and physics and I am lucky if I remember how to use a calulator to find the area of a room let alone figure out points on a curve. the following site helps me from time to time when I am trying to figure something out. When you haven't been in school for years there is no shame in a little lookup. http://mathforum.org/mathtools/There are tons of other sites as well obviously. Try the following:
integer num_objects = 12; float rezRadius = 4; string primname = "babyprim";
rezem() { vector SpawnerPos = llGetPos(); float angle = 0; integer a; for (a = 1; a <= num_objects; a++) { float Xchild = rezRadius * llSin(angle); float Ychild = rezRadius * llCos(angle);
vector childPos = SpawnerPos + <Xchild, Ychild, 0>; //Adjust the following to correct for base rotation of your child. rotation rightAngle = llEuler2Rot( <-PI_BY_TWO, 0, 0> );
rotation rot = llEuler2Rot(<0, 0, (-1 * angle)>); rotation childRot = rightAngle * rot;
llRezObject(primname,childPos,ZERO_VECTOR,childRot,0); angle = angle + (TWO_PI/num_objects); } }
default { state_entry() { llSay(0, "It's ALIVE!!!"); }
touch_start(integer total_number) { rezem(); }
}
|
Flugelhorn McHenry
Valved bugle
Join date: 10 Jul 2004
Posts: 34
|
My results
08-14-2005 02:47
Thank you very much to all who answered, especially Eloise for the first bit of hard maths and Blain for the works-out-of-the-box code. I took Blain's function and added a few lines to allow the user to define an arc rather than a full circle, and also to orient the baby objects based on the orientation of the spawner so that the spawner points at the centre of the arc of babies (useful for my seating example). I then added some bells and whistles to allow the user to define the parameters at runtime, as well as some Massacre of the Innocents code because I was in that sort of mood. Here's the current state of my code. There are two scripts: a big one for the spawner and a little one for the baby. Make an object called "Ephemeral Seat" and drop the baby script into it. Then make an object for the spawner and drop the Ephemeral Seat and the spawner script into that. Some of the maths might be a little messy where I've modified Blain's rezem() function because I'm not really at home with that sort of maths and was just hacking about. There's probably a more elegant way to do it, but the code works well for my purposes, and I haven't been able to break it yet. Flugelhorn Spawner script: float maximumRezDistance = 10; integer spawnerChannel = 7; float sleepTime = 0.25; list MENU_MAIN = ["Number", "Radius", "Arc", "Vert. Offset", "KILL", "SPAWN"];
integer numObjects = 6; float rezRadius = 3; float zOffset = 0;
// The following defines the arc through which the babies will be distributed, as 360/circleDivider. // A value of 1 spreads the babies through 360 degrees; 2 spreads them through 180 degrees; etc. float circleDivider = 3;
string babyPrimName = "Ephemeral Seat"; integer suicideChannel = 0;
float randBetween(float min, float max) { return llFrand(max - min) + min; }
rezem() { vector spawnerPos = llGetPos(); vector myRotationAsEuler = llRot2Euler(llGetRot()); // The following determines the position and angle of the first baby to be created. This is positioned so that // the front face of the spawning object points towards the centre of the arc of babies. // Once the first value of angle is determined, it continues to be incremented. float angle = -myRotationAsEuler.z - ((TWO_PI/circleDivider)/2) + (((TWO_PI/circleDivider)/numObjects)/2); // Adjust the following to correct for base rotation of your child. vector childBaseRotationEuler = <0,0,-PI_BY_TWO>; // In this case, a negative right-angle rotation childBaseRotation = llEuler2Rot(childBaseRotationEuler); integer angleCounter; for (angleCounter = 1; angleCounter <= numObjects; angleCounter++) { float xChild = rezRadius * llSin(angle); float yChild = rezRadius * llCos(angle);
vector childPos = spawnerPos + <xChild, yChild, zOffset>; rotation rot = llEuler2Rot(<0, 0, (-1 * angle)>); // was: rotation rot = llEuler2Rot(<0, 0, (-1 * angle)>); rotation childRot = childBaseRotation * rot;
llRezObject(babyPrimName,childPos,ZERO_VECTOR,childRot,suicideChannel); angle = angle + ((TWO_PI/circleDivider)/numObjects); //llOwnerSay("angle is: " + (string)angle); } }//rezem()
default { state_entry() { if(suicideChannel == 0)// i.e. if the script has just been initialised { suicideChannel = (integer)randBetween(10, 2147483640); //llOwnerSay("Suicide channel is " + (string)suicideChannel); llOwnerSay("Script initialised."); } llSetObjectDesc("State: Default"); llListen(spawnerChannel, "", llGetOwner(), ""); }
touch_start(integer total_number) { if(llDetectedKey(0) == llGetOwner()) { string menuPrompt = "MAIN MENU\n"; menuPrompt = menuPrompt + "\nNumber of seats:\t" + (string)numObjects; menuPrompt = menuPrompt + "\nRadius:\t" + (string)rezRadius + " metres"; menuPrompt = menuPrompt + "\nSeating arc:\t" + (string)(360/circleDivider) + " degrees"; menuPrompt = menuPrompt + "\nVertical offset:\t" + (string)zOffset; menuPrompt = menuPrompt + "\nSuicide channel:\t" + (string)suicideChannel; llDialog(llGetOwner(), menuPrompt, MENU_MAIN, spawnerChannel); // present dialog on click } }
listen(integer channel, string name, key id, string message) { if (llListFindList(MENU_MAIN, [message]) != -1) // verify dialog choice { // llSay(0, name + " picked the option '" + message + "'."); // output the answer if (message == "SPAWN") { llOwnerSay("Putting out the seats..."); rezem(); } else if (message == "KILL") { llOwnerSay("Packing up the seats..."); llShout(suicideChannel, "DIE"); } else if (message == "Radius") { state settingRadius; } else if (message == "Number") { state settingNumberOfSeats; } else if (message == "Arc") { state settingArc; } else if (message == "Vert. Offset") { state settingVerticalOffset; } } else llOwnerSay("You picked invalid option '" + llToLower(message) + "'."); // not a valid dialog choice }// listen
}//default
state settingArc { state_entry() { llSetObjectDesc("State: Setting arc"); llOwnerSay("Please define the arc through which you wish to distribute the seats."); llSleep(sleepTime); llOwnerSay("Say out loud the number by which you wish the circumference to be divided."); llSleep(sleepTime); llOwnerSay("For example, say '2' to distribute the seats through an arc of 180 degrees."); llSleep(sleepTime); llOwnerSay("Current value is " + (string)circleDivider + ", giving an arc of " + (string)(360/circleDivider) + " degrees."); llListen(0, "", llGetOwner(), ""); }// state_entry listen(integer channel, string name, key id, string message) { if( (float)message < 1 ) { llOwnerSay("Sorry, that isn't a valid divisor. Please give a number greater than or equal to 1."); } else { circleDivider = (float)message; llOwnerSay("Setting divisor to " + (string)circleDivider + ", giving an arc of " + (string)(360/circleDivider) + " degrees."); state default; } }// listen }// state settingArc
state settingNumberOfSeats { state_entry() { llSetObjectDesc("State: Setting number of seats"); llOwnerSay("Please say the number of seats you want."); llSleep(sleepTime); llOwnerSay("Current value is " + (string)numObjects); llListen(0, "", llGetOwner(), ""); }// state_entry listen(integer channel, string name, key id, string message) { integer messageAsInteger = (integer)message; if( messageAsInteger < 1 || (string)messageAsInteger != message ) { llOwnerSay("Sorry, that isn't a valid number. Please give a positive integer."); } else { numObjects = messageAsInteger; llOwnerSay("Setting number of seats to " + (string)numObjects); state default; } }// listen }// state settingNumberOfSeats
state settingRadius { state_entry() { llSetObjectDesc("State: Setting radius"); llOwnerSay("Please define (in metres) the radius, i.e. the distance between the spawner and each seat."); llSleep(sleepTime); llOwnerSay("This must be " + (string)maximumRezDistance + " metres or less."); llSleep(sleepTime); llOwnerSay("Current value is " + (string)rezRadius); llListen(0, "", llGetOwner(), ""); }// state_entry listen(integer channel, string name, key id, string message) { if( (float)message <= 0 || (float)message > maximumRezDistance ) { llOwnerSay("Sorry, that isn't a valid radius. Please say a number greater than 0."); } else { rezRadius = (float)message; llOwnerSay("Setting radius to " + (string)rezRadius + " metres."); state default; } }// listen }// state settingRadius
state settingVerticalOffset { state_entry() { llSetObjectDesc("State: Setting vertical offset"); llOwnerSay("Please define (in metres) the vertical offset of the seat from the spawner."); llSleep(sleepTime); llOwnerSay("This must be " + (string)maximumRezDistance + " metres or less."); llSleep(sleepTime); llOwnerSay("Current value is " + (string)zOffset); llListen(0, "", llGetOwner(), ""); }// state_entry listen(integer channel, string name, key id, string message) { if( (float)message<-maximumRezDistance || (float)message>maximumRezDistance) { llOwnerSay("Sorry, that isn't a valid offset."); llSleep(sleepTime); llOwnerSay("Please give an offset which is a positive or negative float between 0 and " + (string)maximumRezDistance); } else { zOffset = (float)message; llOwnerSay("Setting vertical offset to " + (string)zOffset + " metres."); state default; } }// listen }// state settingVerticalOffset
Baby script: integer suicideChannel;
default { state_entry() { llListen(suicideChannel, "", NULL_KEY, "DIE"); llSitTarget(<0.3,0,0.3>, ZERO_ROTATION); } listen(integer channel, string name, key id, string message) { if(message == "DIE") { llDie(); } } on_rez(integer start_param) { suicideChannel = start_param; llListen(suicideChannel, "", NULL_KEY, "DIE"); llSitTarget(<0.3,0,0.3>, ZERO_ROTATION); }
}
|
Blain Candour
Registered User
Join date: 17 Jun 2005
Posts: 83
|
08-14-2005 03:27
Glad it worked for you.
|