Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Library: Swarm

Nahalen Nihilist
Registered User
Join date: 11 Jun 2006
Posts: 0
08-09-2006 20:10
Uh... I went to test this script, and all of the 'fish' fell through the ground... Help?
Dom DaSilva
Registered User
Join date: 18 Jun 2005
Posts: 8
08-12-2006 04:27
From: Aaron Levy
Help!

Ok... there's a rotate variable I can set, but the fish I made never turn around and swim the opposite direction or anything. They just keep steadily moving in one direction until they are long gone... I need them to stay within the tank I'm making! Unless I call them superfish, it won't be believable. Ha!

Second, how can I alter this script so that they NEVER de-spawn?

Finally, even though I set the variable about how far I want the fish to stray from where they spawned, the fish always slowly make it all the way to the floor where they go outside the sandbox and stop.

Any help would be greatly appreciated as I learn this languange.

Thanks!!


You can stop de-spawning; or llDie by setting the Die timer at the beginning of the script to zero.
Darkhorse Golem
Registered User
Join date: 25 Oct 2005
Posts: 23
Direction of multi-prim fish
09-10-2006 15:38
i can make some nice fish with a single prim, but to make them better i would like to use more than one prim.

2 prims - the fish points up in the water, i have tried to rotate the fish to the correct orientation and putting it in the rezzer but when it rezzes it comes out pointing up.

all the other functions work ok but i have a school of upright fish, lol.

2, i have tried to change the orientation before inserting the fish in the rezzer, i have tried changing the rez rotation in the rezzer script from this post, i have also looked to see if there is a line in the swarm script to change the line of impulse.

however if i manualy rez a fish the correct way up it stays that way up?

please can i have some help with this.

DarkHorse.
Imajica Hand
Registered User
Join date: 3 Feb 2006
Posts: 66
same here: Direction of multi-prim fish
09-11-2006 02:25
Yes, I've same trouble of DarkHorse! lol

And another trobule is I cant use "flexy" fish... :(
Jesse Barnett
500,000 scoville units
Join date: 21 May 2006
Posts: 4,160
09-11-2006 08:15
Darkhorse, I put an "Object Look At" script in mine also. I have about 30 of these rounds clown faces swarming around in the air always looking at me. Kind of creepy actually, heehee.

Warning: If you suffer from a clown phobia, DO NOT TRY THIS
Jesse Barnett
500,000 scoville units
Join date: 21 May 2006
Posts: 4,160
09-11-2006 08:20
WHOA!!!!!!

WHy is this thread being moderated??????????? I just posted a reply to Darkhorse's question and recieved this notice:

"Thank you for posting! You will now be taken to your post. If the administrator has selected to moderate all posts in this forum, you will be taken back to the forum and your post will be displayed presently. If you opted to post a poll, you will now be allowed to do so."

My answer has still not been posted 5 mins later. Never seen this happen before. Anybody know what is going on?
Newgate Ludd
Out of Chesse Error
Join date: 8 Apr 2005
Posts: 2,103
llRezObject Error
09-11-2006 10:25
From: Wheel Fizz
Hi,I got the Swarm script working fine,but can't seem to get the second small Swarm rez script to compile....I'm not really sure why :/ If any one can take a quick look at it,it is much appreciated :)



The call to llRezOject was incorrectly specified

CODE

default
{
state_entry()
{
llSetTimerEvent(20);
}
timer()
{
// Rez in a random location within a 10m cube. Don't use 5 in lieu of 5.0 or you
// could end up with slightly odd results due to the automatic conversion to integer instead of float.
vector mypos = llGetPos();
mypos.x += llFrand(10) - 5.0;
mypos.y += llFrand(10) - 5.0;
mypos.z += llFrand(10) - 5.0;
llRezObject("swarm object", mypos, <0,0,0>,<0,0,0,1>,0);
}
}
Tator Market
Registered User
Join date: 11 Sep 2006
Posts: 1
09-16-2006 18:23
From: Ariaruil Stygian


I wish I could remember the name of the follower or the Sesame Street creature it was modelled on, I'd name it if I could.

But it IS doable.



The name of the creature... It's a YIP.
Foo Spark
alias Bathsheba Dorn
Join date: 8 Nov 2006
Posts: 110
Swarm doesn't work any more?
12-31-2006 21:38
I'm not able to make this work, my objects interpenetrate. From reading other posts, it's now my understanding that llVolumeDetect can no longer be used this way because two objects using it will not detect each other: each sees the other as phantom.

llVolumeDetect can still be used in one object to dected a different (physical, non-phantom) object, it just can't be used in two objects to mutually detect each other.

I realize this is a late post, but I wanted to put something in this thread to say that this implementation of swarming doesn't work at this time, so unless you're ready to go under the hood and write a workaround for llVolumeDetect not working, don't bother with it. I just wasted a lot of time not realizing that.

Or if it does work, I'd love to see exactly how...thanks.
Lightwave Valkyrie
Registered User
Join date: 30 Jan 2004
Posts: 666
01-01-2007 09:33
i made a bee hive with this script over a year and a half a go,
and its still working fine. what problem you having?
Hmmm my bees are set to physican and phantom
ill leave the hive out on my land in Kaili(180,200,26)
-LW
Foo Spark
alias Bathsheba Dorn
Join date: 8 Nov 2006
Posts: 110
01-01-2007 12:31
From: Lightwave Valkyrie
i made a bee hive with this script over a year and a half a go,
and its still working fine. what problem you having?
Hmmm my bees are set to physican and phantom
ill leave the hive out on my land in Kaili(180,200,26)


I think this just looks like it works -- the bees are very small compared to the area of the whole swarm, so you don't notice that on the rare occasions that two get into the same area, they fly through each other instead of avoiding each other. I bet that if each bee were, say, 2m, diameter you'd see it. :-)

I'll keep an eye out for swarms of large objects that would test this, but unless I see some my own tests are really convincing me that llVolumeDetect is not currently working between two objects.
Foo Spark
alias Bathsheba Dorn
Join date: 8 Nov 2006
Posts: 110
01-05-2007 23:23
Well, I whomped on the original swarm script, and here's what I came up with as a workaround for the nerfed llVolumeDetect feature. The comments are pretty raw and there's some stuff that doesn't have much to do with swarming behavior, but if I wait till I feel like prettying it up I'll never post it, so here it is hot off the griddle.

I had my swarm follow a leader to make it look like a school, since I couldn't seem to get convincing schooling behavior out of the original. The swarm objects are set up to look for a leader, and if they don't find one to rez a new one.

I made the objects swim upright (Z axis up) so they look more fishy. The parameters here are adjusted for a school of rays, as I write this they're swimming around at Klaw 243, 88, 5.

This script goes in the swarming objects:
CODE

// Swarm script
// by Bathsheba Dorn
// Modified from the script by Apotheus Silverman

//AS's comments:
// This script is my implementation of the well-known swarm algorithm
// which can be found in numerous open-source programs.
// Due to the specifics of the SL environment, I have strayed from some
// of the traditional rules slightly. Regardless, the end effect is
// indistiguishable from the original algorithm.


//BD: I started rewriting this because the llVolumeDetect function has been nerfed and
//does not work for this purpose. I ended up changing many things about it for my own purpose.
//It still uses the swarm code, but the school follows a leader rather than trying to move on its own.

//When a swarm object is rezzed or in any way finds itself without a leader, it will try to detect
//a leader (it expects a leader with the same name as itself but a funny orientation) and if it can't find one
//it will rez one.

//I also changed it so the objects will die if they leave the land of whosever land they were rezzed on,
//and so that they swim upright (z axis up).


// Configurable parameters

// Determines whether or not to enable STATUS_SANDBOX.
integer sandbox = FALSE;

// Timer length
float timer_length = 0.5;

// Die after this many seconds
integer kill_time = 0;

//Lower altitude limit to keep object from intersecting an above-ground floor
//if 0, use ground.
float lower_limit = 0;

//Objects are presumed to have collided when they're this close.
float collide_distance = 4;

//Object swims in X direction. How fast?
float swim_speed = 1.2;

// How much force to apply with each impulse
float force_modifier = 0.7;

// How much force to apply when repulsed by another like me
float repulse_force_modifier = 0.5;//.86

// How much friction to use on a scale from 0 to 1.
// Note that friction takes effect each timer cycle, so the lower the timer length,
// the more the friction you specify here will take effect, thereby increasing actual
// friction applied.
float friction = 0.45;//0.45;

// How much to modify the rotation strength. Higher numbers produce greater strength
// Note that if the modifier is too small, the object may not rotate at all.
float rotation_strength_modifier = .1; //2.8;

// How much to modify rotation damping. Higher numbers produce slower rotation.
float rotation_damping_modifier = 1.0; //5000000.0;

// Does this object "swim" in air or water?
// 2 = air
// 1 = water
// 0 = both
integer flight_mode = 0;

// Maximum distance from spawn point
float max_distance = 12.0;

// How far away to scan for others like me. 2 * max_distance + a bit is a good value.
float sensor_distance = 26.0;


// *** Don't change anything below unless you *really* know what you're doing ***

// Debug switch: if true object will report collisions
integer talk = FALSE;

//Remember whose land I started on, and die if I leave it.
key my_landowner;

// Key of swarm leader object
string leader_key = NULL_KEY;

//Flag: I just rezzed a leader but haven't detected it yet.
integer leader_rezzed_but_not_found = FALSE;

//how long I've been without a leader
integer no_leader = 0;


float mass;
vector spawn_location;


//Rez a new leader.
RezLeader()
{
llOwnerSay("Rezzing a new leader.");
llRezObject(llGetObjectName(), llGetPos(),ZERO_VECTOR, ZERO_ROTATION, 0);
no_leader = 0;
leader_rezzed_but_not_found = TRUE;
}


//Stay upright while turning.
//I got this from the scripty-tips forum, it points x axis at target while keeping z axis up
rotation upright_point_at(vector target)
{
vector fwd = llVecNorm(target - llGetPos());
vector left = llVecNorm(<0,0,1> % fwd);
vector up = fwd % left;
return llAxes2Rot(fwd, left, up);
}

do_rotation(vector mypos, vector myvel) {
llRotLookAt(upright_point_at(mypos + myvel),
mass * rotation_strength_modifier, mass * rotation_damping_modifier);
}


// Collision function
collide(vector loc) {
vector mypos = llGetPos();
// Apply repulse force
vector impulse = llVecNorm(mypos - loc);
llApplyImpulse(impulse * repulse_force_modifier * mass, FALSE);

if (talk) llOwnerSay("collide() - impulse " + (string)impulse + " applied.");
}


//Do collisions: this function is called whether or not the sensor finds anything
sensor_any() {
// Die after reaching kill_time
if (kill_time != 0 && llGetTime() >= kill_time) {
llDie();
}

// Get my velocity
vector myvel = llGetVel();

// Apply friction
llApplyImpulse(-(myvel * friction * mass), FALSE);

// Get my position
vector mypos = llGetPos();

//Die if off my land (this can happen if somebody shot or pushed me)
if (llGetLandOwnerAt(mypos) != my_landowner) {
llOwnerSay("Went off my parcel, I'll now die.");
llDie();
}

// Check for air/water breach
if (flight_mode == 1) {
// water
if (mypos.z >= llWater(mypos) - llVecMag(llGetScale())) {
if (talk) llOwnerSay( "collide() called due to air/water breach.");
collide(<mypos.x, mypos.y, mypos.z + 0.3>);
}
} else if (flight_mode == 2) {
// air
if (mypos.z <= llWater(mypos) + llVecMag(llGetScale())) {
if (talk) llOwnerSay( "collide() called due to air/water breach.");
collide(<mypos.x, mypos.y, mypos.z - 0.3>);
}
}

// Stay near spawn location
if (llVecDist(mypos, spawn_location) > max_distance) {
// Compensate for being near sim border
if (spawn_location.x - mypos.x > 100) {
mypos.x += 255;
}
if (talk) llOwnerSay("collide() called due to too much distance from my spawn point.");
// mypos=" + (string)mypos + ", spawn_location = " + (string)spawn_location);

collide(mypos - llVecNorm(spawn_location - mypos));
}

// Stay above ground level
if (lower_limit == 0) {
if (mypos.z <= llGround(ZERO_VECTOR)) {
if (talk) llOwnerSay("Collide called due to ground intersection.");
collide(<mypos.x,mypos.y,mypos.z - .3>);
}
} else
if (mypos.z <= lower_limit) {
if (talk) llOwnerSay("Collide called due to lower limit intersection.");
collide(<mypos.x,mypos.y,mypos.z - .3>);
}

}


default {
state_entry() {
llResetTime();
llOwnerSay("Started.");

// Sandbox
llSetStatus(STATUS_SANDBOX, sandbox);
llSetStatus(STATUS_BLOCK_GRAB, FALSE);

// spawn_location = <240,77,10>;
spawn_location = llGetPos();

//Find out what land I'm on
my_landowner = llGetLandOwnerAt(llGetPos());

// Initialize physics behavior
mass = llGetMass();
llSetStatus(STATUS_PHYSICS, TRUE);
llSetStatus(STATUS_PHANTOM, TRUE); //Note that if the script is turned off, the object will fall off-world.
llSetBuoyancy(1.0);

//BD turned off because doesn't work llVolumeDetect(TRUE);

// Initialize sensor
llSensorRepeat(llGetObjectName(), NULL_KEY, ACTIVE|SCRIPTED, sensor_distance, PI, timer_length);

}

touch_start(integer detected) {
if (llDetectedKey(0) == llGetOwner())
state stopped;
// llResetScript();
}

//If I've rezzed a new leader, capture its key.
object_rez(key id) {
leader_key = id;
llOwnerSay("Found new leader!");
leader_rezzed_but_not_found = FALSE;
}


//This is only called if leader isn't found and I'm the only swarmer.
//Therefore, if no new leader has been rezzed already, I need to rez one.
no_sensor() {
llOwnerSay("Lost leader, nothing sensed.");
if (!leader_rezzed_but_not_found) RezLeader();

sensor_any();
}


sensor(integer total_number) {
sensor_any();

// Populate neighbors with the positions of the two nearest neighbors.
vector mypos = llGetPos();
list neighbors = [];
integer i;
vector leaderpos;
integer leaderfound = FALSE;

for (i = 0; i < total_number; i++) {
vector current_pos = llDetectedPos(i);

if (llDetectedKey(i) == leader_key) {
if (talk) llOwnerSay("Found leader");
leaderpos = llDetectedPos(i);
leaderfound = TRUE;
i++;
jump Next;
}

if(llDetectedName(i) != llGetObjectName()) {
i++;
jump Next;
}

if (llGetListLength(neighbors) < 2) {
// Add to list
neighbors = llListInsertList(neighbors, [current_pos], llGetListLength(neighbors));
} else {
// Check to see if the current vector is closer than the list
// vector which is furthest away.
if (llVecDist(mypos, llList2Vector(neighbors, 0)) >
llVecDist(mypos, llList2Vector(neighbors, 1))) {
// check against first list item
if (llVecDist(mypos, llList2Vector(neighbors, 0)) >
llVecDist(mypos, current_pos)) {
llListInsertList(neighbors, [current_pos], 0);
}
} else {
// check against second list item
if (llVecDist(mypos, llList2Vector(neighbors, 1)) >
llVecDist(mypos, current_pos)) {
llListInsertList(neighbors, [current_pos], 1);
}
}
}
@Next;
}

// Process movement

//If there is a closest neighbor and it is too close, push away
//This is a proxy for the lamentable fact that llVolumeDetect no longer
//works in this context: two objects cannot mutually detect each other using it, because
//each sees the other as phantom.
if (llGetListLength(neighbors) > 1) {
vector neighbor1 = llList2Vector(neighbors,0);
if (llVecDist(mypos,neighbor1) < collide_distance) {
if (talk) llOwnerSay( "collide() called due to collision.");

collide(neighbor1);
//return;
}
}

// Apply force
vector impulse = <0,0,0>;
if (llGetListLength(neighbors) == 2) {
vector neighbor1 = llList2Vector(neighbors, 0);
vector neighbor2 = llList2Vector(neighbors, 1);
vector target = neighbor2 + ((neighbor1 - neighbor2) * 0.5);
impulse = llVecNorm(target - mypos);
}

// Follow leader
if (leaderfound) {
vector leaderTarget = llVecNorm(leaderpos - mypos);
impulse += swim_speed * leaderTarget;
}

//This keeps 3 swarmers from getting into a horizontal formation and staying there forever.
if (llFrand(1.0) > .8) {
// llOwnerSay("Vertical push");
impulse += <0,0,llFrand(4.0) - 2.0>;
}
//llOwnerSay("setforce " + (string)(impulse * force_modifier * mass));
llSetForce(impulse * force_modifier * mass, FALSE);

// Update rotation
do_rotation(llGetPos(), leaderpos - llGetPos());

//If leader wasn't found and none is pending,
//look for a swarm member with rotation 90 degrees off from normal...
if (!leaderfound && !leader_rezzed_but_not_found) {
llOwnerSay("Lost leader.");
for (i = 0; i < total_number; i++) {
vector left = llRot2Left(llDetectedRot(i));

if (left.z * RAD_TO_DEG < -10) {
leader_key = llDetectedKey(i);
no_leader = 0;
llOwnerSay("Found leader by rotation.");
}
}
no_leader++;

//if no leader could be found after looking 20 times, rez a new one.
//Do this randomly so that if a whole swarm loses its leader at once, they won't all rez newleaders
//at the same moment
if (no_leader > 20 && llFrand(1.0) > .9) RezLeader();
}
}

on_rez(integer start_param) {
llResetScript();
}
}



state stopped {
state_entry() {
llOwnerSay("Stopped.");
llSetForce(<0,0,0>,TRUE);
}
touch_start(integer detected) {
if (llDetectedKey(0) == llGetOwner())
state default;
}

}




The swarmers expect to find a leader object in their inventory, with the same name as themselves and containing a script to makes it move around so they can follow it. The leader has to exist, move, have the same name as the swarm objects, and swim on its side (this last is how the objects know which one is the leader.) I used a transparent sphere as the leader, since I don't especially want to see it.

This is the leader script of my rays:
CODE

// Swarm leader script
// by Bathsheba Dorn
// Modified from the script by Apotheus Silverman


//************
//This object is the swarm leader, all it does is swim around for other swarm objects to follow.



// Configurable parameters
// Determines whether or not to enable STATUS_SANDBOX.
integer sandbox = FALSE;

//remember whose land I started on, and die if I leave it.
key my_landowner;

// Timer length
float timer_length = 0.5;

// Die after this many seconds
integer kill_time = 0;

//Lower altitude limit to keep object from intersecting an above-ground floor
//0 = use ground
float lower_limit = 0;

//Object swims in X direction. How fast?
float swim_speed = 1.3;

// How much force to apply with each impulse
float force_modifier =1.0;

// How much force to apply when repulsed by a collision condition
float repulse_force_modifier = 4.0; //.86

// How much friction to use on a scale from 0 to 1.
// Note that friction takes effect each timer cycle, so the lower the timer length,
// the more the friction you specify here will take effect, thereby increasing actual
// friction applied.
float friction = 0.45;

// How much to modify the rotation strength. Higher numbers produce greater strength
// Note that if the modifier is too small, the object may not rotate at all.
float rotation_strength_modifier = .2; //2.8

// How much to modify rotation damping. Higher numbers produce slower rotation.
float rotation_damping_modifier = .10; //5000000.0;

// Does this object "swim" in air or water?
// 2 = air
// 1 = water
// 0 = both
integer flight_mode = 0;

// Maximum distance from spawn point
float max_distance = 12.0;


// *** Don't change anything below unless you *really* know what you're doing ***

//debug switch: if true object will report collisions
integer talk = FALSE;

float mass;
vector spawn_location;


// Update rotation function

//Swim in a particular orientation. I got this from the forum, it points x axis at target while keeping y axis down.
//Note that that's the reverse of the usual: this is so the other swarm members can recognize this object
//as their leader.
rotation upright_point_at(vector target)
{
vector fwd = llVecNorm(target - llGetPos());
vector left = llVecNorm(<0,0,1> % fwd);
vector up = fwd % left;
return llAxes2Rot(fwd, -up, left);
}

do_rotation(vector mypos, vector myvel) {
llRotLookAt(upright_point_at(mypos + myvel),
mass * rotation_strength_modifier, mass * rotation_damping_modifier);
}


// Collision function
collide(vector loc) {
vector mypos = llGetPos();
// Apply repulse force
vector impulse = llVecNorm(mypos - loc);
llApplyImpulse(impulse * repulse_force_modifier * mass, FALSE);

if (talk) llOwnerSay("collide() - impulse " + (string)impulse + " applied.");
}


default {
state_entry() {
llResetTime();
llOwnerSay("Leader started.");

// Sandbox
llSetStatus(STATUS_SANDBOX, sandbox);
llSetStatus(STATUS_BLOCK_GRAB, FALSE);
spawn_location = llGetPos();

//Find out what land I'm on
my_landowner = llGetLandOwnerAt(llGetPos());

// Initialize physics behavior
mass = llGetMass();
llSetStatus(STATUS_PHYSICS, TRUE);
llSetStatus(STATUS_PHANTOM, TRUE);
llSetBuoyancy(1.0);

// Swim forward
llSetForce(<swim_speed,0,0> * force_modifier * mass, TRUE);

// Set timer
llSetTimerEvent(timer_length);

}


touch_start(integer detected) {
if (llDetectedKey(0) == llGetOwner())
state stopped;
// llResetScript();
}


timer() {
// Die after reaching kill_time
if (kill_time != 0 && llGetTime() >= kill_time) {
llDie();
}

// Get my velocity
vector myvel = llGetVel();

// Apply friction
llApplyImpulse(-(myvel * friction * mass), FALSE);


// Get my position
vector mypos = llGetPos();

//Die if knocked off my land
if (llGetLandOwnerAt(mypos) != my_landowner) {
llOwnerSay("Swarm leader went off parcel, will now die.");
llDie();
}

// Check for air/water breach
if (flight_mode == 1) {
// water
if (mypos.z >= llWater(mypos) - llVecMag(llGetScale())) {
if (talk) llOwnerSay( "collide() called due to air/water breach.");
collide(<mypos.x, mypos.y, mypos.z + 0.3>);
}
} else if (flight_mode == 2) {
// air
if (mypos.z <= llWater(mypos) + llVecMag(llGetScale())) {
if (talk) llOwnerSay( "collide() called due to air/water breach.");
collide(<mypos.x, mypos.y, mypos.z - 0.3>);
}
}

// Stay near spawn location
if (llVecDist(mypos, spawn_location) > max_distance) {
// Compensate for being near sim border
if (spawn_location.x - mypos.x > 100)
mypos.x += 255;

if (talk) llOwnerSay("collide() called due to too much distance from my spawn point.");
// mypos=" + (string)mypos + ", spawn_location = " + (string)spawn_location);

collide(mypos - llVecNorm(spawn_location - mypos));
}

// Stay above ground level
if (lower_limit == 0) {
if (mypos.z <= llGround(ZERO_VECTOR)) {
if (talk) llOwnerSay("Collide called due to ground intersection.");
collide(<mypos.x,mypos.y,mypos.z - .3>);
}
} else
if (mypos.z <= lower_limit) {
if (talk) llOwnerSay("Collide called due to lower limit intersection.");
collide(<mypos.x,mypos.y,mypos.z - .3>);
}

//point in the direction you're swimming
do_rotation(llGetPos(), llGetVel());

}


on_rez(integer start_param) {

llResetScript();
spawn_location = llGetPos();
// llResetTime();
}
}


state stopped {
state_entry() {
llOwnerSay("Stopped.");
llSetForce(<0,0,0>,TRUE);
}
touch_start(integer detected) {
if (llDetectedKey(0) == llGetOwner())
state default;
}

}

Kothlak Balhaus
Registered User
Join date: 7 Jan 2007
Posts: 3
The swarm script and flexi
06-01-2007 15:17
I have been playing with the swarm script. With the leader script only, so far..and I found that any flexiable prim or linked prims with any flexiable prims will not utilize the Swarm script. Is there anything I am missing with this, or a way around this problem?
rup Eizenberg
Registered User
Join date: 23 May 2008
Posts: 31
03-10-2009 05:54
Simply brilliant script. Works like a charm and love it
1 2