Olympia Rebus
Muse of Chaos
Join date: 22 Feb 2004
Posts: 1,831
|
07-13-2005 12:28
Hi all Below is a script based on one posted by Zak Escher (with help from Surina Skallagrimson) , plus annotations and a few parts I incorperated from Apotheus Silverman's swarm script to keep the creature(s) underwater and to have them bounce when it hits something. This works reasonably well but isn't perfect (the not-pefect part being my melding of two seperate scripts together as opposed to anything wrong with the originals, which are wonderful). The "fish" (walled in and underwater) still manage to get loose and sometimes it lags the sim. Any tips on how I could improve it? A Linden told me that making the fish phantom would be easier on the sim, but wouldn't that mean they'd be swimming through walls? (Go easy on me- I'm still in the dummy stage) Thanks in advance. float ver_num = 0.7; //the "fish" will be called "aLife", but you can change that if you wish string obj_name = "aLife"; float fStrength = 1.0;
float repulse_force_modifier = .86; float rotation_damping_modifier = 50000;
//Rotation function do_rotation(vector mypos, vector myvel) { float fmass = llGetMass(); llLookAt(llGetPos() + llGetVel(), fmass * 2.8, fmass * rotation_damping_modifier); }
// Collision function
collide(vector loc) { vector mypos = llGetPos(); float fmass = llGetMass(); // Apply repulse force vector impulse = llVecNorm(mypos - loc); llApplyImpulse(impulse * repulse_force_modifier * fmass, FALSE);
// Update rotation do_rotation(mypos, llGetVel()); }
default { state_entry() { llSetColor(<1,1,1>, ALL_SIDES); llSetStatus(STATUS_SANDBOX, FALSE); llSetStatus(STATUS_PHYSICS, TRUE); llCollisionSound("", 0.0); //Set Object Name to obj_name, which has been assigned as "Alife" (see above) llSetObjectName(obj_name); llSetObjectDesc((string)ver_num); llSetBuoyancy (1.0); //Look for other fish. //In this case,get the name of nearby objects with active, running scripts llSensorRepeat(llGetObjectName(), NULL_KEY, ACTIVE|SCRIPTED, 30, PI, 1.0); }
on_rez(integer start_param) { llResetScript(); } sensor(integer num_detected)
{ //turn green if something is detected llSetColor(<0,1,0>, ALL_SIDES); vector vSwarm_Center; vector vSwarm_Vel; integer iSwarm_Pop; integer i; //for each number deteteded do this: for (i=0; i < num_detected; i++) { //add the detected position of current fish to vSwarm_Center vSwarm_Center += llDetectedPos(i); //add the detected velocity of the current fish to vSwarm Vel vSwarm_Vel += llDetectedVel(i); //add add one to iSwarmPop iSwarm_Pop++; } //get the average position of the Swarm vSwarm_Center = vSwarm_Center / iSwarm_Pop; //get the average velocity of the Swarm vSwarm_Vel = vSwarm_Vel / iSwarm_Pop; float fMass = llGetMass(); //vTarget will be the current swarm center plus the veloctiy //this tells us where the swarm is going vector vTarget = vSwarm_Center + vSwarm_Vel; //this tells us where the individual fish is going vector vMypos = llGetPos() + llGetVel(); //we figure out the difference between where HE is and where the swarm is vector vDesiredHeading = vTarget - vMypos; //this tells us the distance beteen the two float fDist = llVecDist(vTarget,vMypos); //this tells us which way he needs to point vector vImpulse = llVecNorm(vDesiredHeading); //to keep him from getting too close, we create a repulse factor //as fDist gets smaller, vRepulse gets bigger vector vRepulse = vImpulse / fDist; //this launches the fish llApplyImpulse((vImpulse - vRepulse) * fStrength * fMass, FALSE); //this points him in the right direction llLookAt(vMypos, fMass * 2.8, fMass * 50000); // keep underwater if (vMypos.z >= llWater(vMypos) - llVecMag(llGetScale())) { //llSay(0, "collide() called due to air/water breach."); collide(<vMypos.x, vMypos.y, vMypos.z + 0.3>); } } //if he hits a wall (or another fish) collision_start(integer total_number) { //llSay(0, "collide() called due to physical object collision."); collide(llDetectedPos(0)); } //if he sees nobody, he turns blue no_sensor() { llSetColor(<0,0,1>, ALL_SIDES); } }
//Notes & Reminders //Operators used: //++ means add one increment each time //thus i++ means add one to i
//+= adds variables together //more precisly, it adds the second variable to the first: // thus vSwarm_Vel += llDetectedVel(i) // means add llDetectedVel(i) to vSwarm_Vel
p.s. If you're new to this stuff, as I am, the two scripts I linked to above are great learning tools.
|
Eloise Pasteur
Curious Individual
Join date: 14 Jul 2004
Posts: 1,952
|
07-14-2005 02:19
Although I'm not totally convinced it will make things easier on the sim you could use llVolumeDetect(). This will make your object phantom, and since you already have a buoyancy of 1.0 not cause it to fall through the floor.
It also seems to me that something 'extra' to keep them within a fixed distance of the start point might be helpful, although I do appreciate that what you're doing should stop that. Grabbing llGetPos() in the state_entry() event as start and a max distance global (of say 20) and calling the collide function or even just recalculating the various desired heading calculations should be easy enough to do.
Other's here might argue, but I'd probably take float fMass out of there, declare fMass as a global, and grab it in the state_entry() event too, no need to call it every time you go into the sensor event, as it shouldn't change.
iSwarmPop better equal i too! You (hope) you set it to 0 by redeclaring it each time, then you increment it i times so if i=1 you do 0+1, if i=2 you do 0+1+1 etc. I can't see it slowing the script down appreciably, but as you write bigger scripts the ability to save a bit of memory like that will become increasingly important.
I've got to say that it looks good to me, I'm going to have a play in a minute and see if anything else comes along.
|
Eloise Pasteur
Curious Individual
Join date: 14 Jul 2004
Posts: 1,952
|
07-14-2005 04:42
It needs something tweaking in the water breach part, but I'm not thinking clearly atm.
I made a school of fish (should have been flying fish) and found they kept jumping out of the water - I'm assuming the impulse to 'flee' each other as they get closer was outweighing the impulse to stay underwater. They also perform some *amazing* aerobatics as they fly up, twirl and spin spectacularly and dive back into the water.
I'm thinking that the check for water height needs to be moved above the llApplyImpulse. It might also be an idea to change how it check, maybe so that you adjust vMypos (the target position) to have a z component less than the height of the water before you apply it?
Other than that, and thus the need for really high walls to keep them constrained it does reproduce a very nice school of fish pattern of behaviour.
BTW defining a global fMass will also let you avoid checking it in both the collide and do_rotation functions, I'm leaning more and more to the idea it's worth it.
|
Olympia Rebus
Muse of Chaos
Join date: 22 Feb 2004
Posts: 1,831
|
07-14-2005 08:08
Thanks for the ideas, Eloise. I can't wait to log in again and try them. 
|
Eloise Pasteur
Curious Individual
Join date: 14 Jul 2004
Posts: 1,952
|
07-14-2005 09:54
Good luck with them!
I had a script that worked nicely with a shoal of cubes, but it was a bit ugly.
I have yet to try it with a shoal of fish, but I will give it a go.
btw, for fish the colour changes are also a nuisance! I changed it so there's a 10s sleep in state_entry() so you've got time to rez some companions, and an llDie() in no_sensor().
It also helps my fish not run too far away, which was important sometimes when I got the sums wrong!
|
Sue Stonebender
Piano Craftsman
Join date: 7 Jan 2005
Posts: 219
|
Question About Flexi-Prims
06-30-2006 18:50
Olympia, thanks so much for sharing this, and Eloise, thanks for helping troubleshoot. Very generous of both of you.
I've been giving this a try, with some minor modifications. I've found that it works beautifully with two exceptions:
1) Even tho I've adjusted the water height call as Eloise suggested (moving the water height check above where the impulse is applied), they still breach every time. Is there some other way of keeping them below water? They seem to ignore the equation even if placed before the impulse. I see the suggestion to hardcode an implicit value for roaming distance. I have a long cove, and am hoping not to have to restrict their movement by implying an absolute limit on the distance they are allowed to roam from where they first rezzed.
2) If I make the fins (or any prim attached to the root) flexi, it kills the script. Is there a way to modify the script to allow the flexi's, or is this just not possible? I'm assuming it's because flexi prims by their very nature are automatically phantom, and even when linking to a non-phantom parent prim their taking on of this attribute is buggy. That being the case, might there be a way to use the llSetPrimitiveParams([PRIM_FLEXIBLE,1,2,.3,2,0,1,<0,0,0>]); function to toggle flexi off on rez, and then on again once the swim script is running?
Grasping at straws. Thanks a bunch for any ideas you might be able to share!
Sue.
|