LSL Swarm Script For Second Life – Make Birds & Bees

Alien Invasion In A Box 085The blog seems to have been getting hits from the search engines for an LSL swarm script – so, in an attempt to keep the customer happy, I thought I’d provide this. It’s a swarming script by Apotheus Silverman from the Second Life LSL Wiki.

It’s a lot of fun to play with, especially when you start playing around with the variables. What’s it used for? You can use it to create flocks of birds, butterflies, pterodactyls or anything else you can think of.

 I used it as the engine that runs my Alien Invasion In a Box.

As far as I know it’s public domain.
 ————————————————————————————————————————————————————————————————————————

// Swarm script
// by Apotheus Silverman
// 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.

// 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 = 300;

// Enables or disables schooling behavior
integer school = TRUE;

// Schooling comm channel
integer school_comm_channel = 9284;

// Schooling behavior update interval (should be a multiple of timer_length)
float school_update_interval = 2.0;

// 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.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.8;

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

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

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

// How far away to scan for others like me
float sensor_distance = 30.0;

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

float mass;
vector spawn_location;
float school_timer = 0.0;
vector school_modifier = <0,0,0>;

// Update rotation function
do_rotation(vector mypos, vector myvel) {
    llLookAt(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);
//llSay(0, “collide() – impulse ” + (string)impulse + ” applied.”);
    // Update rotation
    do_rotation(mypos, llGetVel());
}

// This function is called whether the sensor senses anything or not
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);

    // Schooling behavior
    if (school && llGetTime() – school_timer > school_update_interval) {
        llSay(school_comm_channel, (string)myvel);
        school_timer = llGetTime();
    }

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

    // Check for air/water breach
    if (flight_mode == 1) {
        // water
        if (mypos.z >= llWater(mypos) – llVecMag(llGetScale())) {
//llSay(0, “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())) {
//llSay(0, “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;
        }
//llSay(0, “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 (mypos.z <= llGround(ZERO_VECTOR)) {
        collide(mypos – llGroundNormal(ZERO_VECTOR));
    }
}
default {
    state_entry() {
        llResetTime();
        llSay(0, “Fishy spawned.”);

        // School
        if (school) {
            llListen(school_comm_channel, “”, NULL_KEY, “”);
        }

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

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

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

    }
    collision_start(integer total_number) {
//llSay(0, “collide() called due to physical object collision.”);
        collide(llDetectedPos(0));
    }

    no_sensor() {
        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;

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

            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);
                    }
                }
            }
        }
        // Process movement

        // Apply force
        if (llGetListLength(neighbors) == 2) {
            vector neighbor1 = llList2Vector(neighbors, 0);
            vector neighbor2 = llList2Vector(neighbors, 1);
            vector target = neighbor2 + ((neighbor1 – neighbor2) * 0.5);
            vector impulse = <0,0,0>;
            if (school) {
                impulse = llVecNorm(target + school_modifier – mypos);
            } else {
                impulse = llVecNorm(target – mypos);
            }
//llSay(0, “setforce ” + (string)(impulse * force_modifier * mass));
            llSetForce(impulse * force_modifier * mass, FALSE);
        }

        // Update rotation
        do_rotation(llGetPos(), llGetVel());
    }

    listen(integer channel, string name, key id, string message) {
        list myList = llCSV2List(llGetSubString(message, 1, llStringLength(message) – 2));
        if (llGetListLength(myList) == 3) {
            school_modifier = <llList2Float(myList, 0), llList2Float(myList, 1), llList2Float(myList, 2)>;
            school_timer = llGetTime();
        }
    }

    on_rez(integer start_param) {
        llResetScript();
//        spawn_location = llGetPos();
//        llResetTime();
    }
}

About these ads

~ by slconceptual on May 17, 2007.

59 Responses to “LSL Swarm Script For Second Life – Make Birds & Bees”

  1. I attempted to use this but when you save it it says

    syntax error

    default {
    state_entry() {
    llResetTime();
    llSay(0, “Fishy spawned.”);

    there

    plus what ht ehell do you do with this – no instructions maybe some guidance would help :)

  2. If you paste this directly into an SL script, you’ll get errors because of the extra html characters that the blog software sticks in.

    Tip:
    Paste it into notepad first, then paste from that into an SL script to remove the extra characters, and that should work.

    Then put the script into an object, create several copies of the same object, and they should all interact together.

  3. copy paste into notepad then in script/object still gives errors!
    plse help

  4. I’ll drop you a copy in-world – one that I know works.

  5. hay the script doesn’t work

  6. i need help
    plzzzzzz

  7. If you want to tell me your AV name dreamcast, I’ll drop you a working copy in-world.

  8. ok my name is nyil carnell

    ^.^

    thnxs

  9. It’s done. Have fun with it.

  10. hey could you send me the script as well. I’m also getting errors. my name is avah greenwood

  11. It’s done Fiona.

  12. Hey, send me a copy.
    CammyD Beningbrough

  13. it is possible to give me a copy too ???
    merry chrismas !!!

    chechel Choche

  14. I got the script to compile by replacing the parenthesis ”

    But it still doesn’t want to work for me. :(

    Then again i don’t have fish or birds to play with.

    I just tried to use teddy bears and carried the other one.

    probably works with stuff that moves on their own.. heh.

    Any idea how to make teddy bears fly?

    SL Name = Anti Destiny

  15. great and fun !! i use it and work. But i put my fish not a linden water, how to let the fish in a limit area ? fish go under ground .. like a worm :))
    (sorry for my basic english) .
    sl name = lastping Asp
    Im me if you have Answer.

  16. Lastping…..
    This is the relevant line…..

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

    Set this to a suitable value, make sure the emitter is right in the middle of the area you want to use, and make sure your pond is deep enough and you should be ok.

  17. pls i need a copy too can you send one to me?

  18. Please drop me a working copy too, if you are so kind. I got the script to compile, but no fishies appeared. My inworld name is Cecilie Haggwood. Thank you so much.

  19. hi, i read all the comments and answers and i would like to have COPY OF THE SCRIPT. CAN I MAKE IT AS a swarm to follow my avatar by wearing it ?
    thanks for reply

  20. The swarm won’t follow you as the script is without a rewrite – but the swarm is created as temponrez objects, so any individual object will only last for a minute or so, with new ones being created all the time from your current location if you are wearing the emitter.

  21. thank you for the script, i put it in an object and then it says “SWARM emitter: Fishy spawned.”thats all and the objectsinks down a little and the after the set killtime it disappears. do i misunderstand something ??
    normally i am not so stupid :-))

  22. You need at least 3 objects for the swarming to take effect. Usually you have an emitter with your spawning object inside its it, the emitter spawns an object every 10 secs or so, and the objects are temponrez so will last for a minute or so.

    Also you need to play with the numbers in the script so the speed/behaviour suits your objects (fish/birds/butterflies etc)

  23. sorry, but i cannot get it to work. i put some objects in a box, then add the script as it is, then close the editor and the box moves a bit and dies after 300 sec, thats all. noting coming out of it. when i make several objects with the script in it, they move a bit and then disappear. i guess i lack some brain cells :-)

  24. i thank you for your support, its really special, some could learn from your service

  25. Here’s the swarm help notes from SL
    Note the bit about creating an emitter towards the end of the script.
    ———————————————
    Swarm Help from Hank Ramos
    ———————————————

    The swarm algorithm in its purest sense creates any number of things that are attracted to each other. Any objects you tie this script to (after modifying the configurable parameters according to your object size, desired speed, etc) behave like social animals. That is, they swarm/flock/school… whatever you want to call it. None of generated movement is random, though it may appear to be.

    Swarm rules for each swarm object to follow:
    1. Accelerate toward the halfway point between your two nearest neighbors.
    2. Upon collision, momentarily be repulsed by whatever object or ground was collided with.
    3. If no neighbors are detected, just keep moving in a straight line at a constant speed. If I go off-world, then so be it.

    The traditional swarm algorithm actually has a few more rules than this, but those rules are rather specific to a single application handling the entire swarm rather than multiple state engines working together.

    The best way of using this script that I have found is to create your swarm object… let’s say you want to make a school of fish. Create your fish model. Add the script into your fish.

    Now comes the tricky part: getting the parameters just right. The swarming behavior does not occur until there are at least 3 of your swarm object within 96 meters of each other. When you have the parameters adjusted and are ready to test your swarm, you must rez at least 3 of the current object. An easy way to do this is to be in edit mode and hit ctrl+d twice. Make sure you take a copy of your object BEFORE you start testing, as incorrectly configured objects tend to fly away very fast! You can also set sandbox to TRUE so they don’t get too far away.

    Once you have your swarm behaving the way you want it to, make sure you have a timeout set (I generally use 5 minutes) on the swarm object, then create another object that will be the main center point of your swarm. This object will rez new swarm objects every N seconds. This ensures you always have a swarm that is relatively nearby the rezzing object, and in conjunction with the swarm object timeout, ensures you always have a relatively constant number of swarm objects rezzed. The script code for your rezzing object should be something like this (ignore errors… i’m at work right now and don’t have access to SL to test this):

    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, , );
    }
    }
    ——————————————————————————–

    Once you apply this script to your rezzing object, add your swarm object to its contents and let it go. Congratulations, you now have a completely self-maintaining swarm.

    Oh and please please please please please do not create huge swarms with a ton of swarm objects and just let it stay that way. You’ll dump the sim’s script and physics performance right in the toilet and end up making all your neighbors angry. Just as an FYI I had a swarm of 25 going in Cordova and did not see any slowdown or performance loss at all, but your mileage may vary.

    Since it is quite obvious that creating a swarm is not something to be tackled by a non-scripter or even someone who doesn’t have much patience, I will be selling my swarm creations soon at my new home in Abbots for a small fee. Since the code is open-source, I will also allow full copy/mod/transfer perms to purchasers.

  26. Can you give me a copy to or pls make it possible to correct?
    SL Name: Hackerx72 Kattun

  27. I SOLVED THE PROBLEM: Everything that has =>” this sign must be deleted and retyped because the signs on this page are like italic. Great script man =)

  28. Can I also get a copy?
    SL Name: Juggle Barzane

  29. Juggle – it’s done

  30. Hey there,
    This looks fantastic, saw the video of it in action with a school of fish here: http://www.wegame.com/watch/Fish_School_Rezzer/

    Could I get a copy in-world please? I’ve used my avatar name for this post.

    I’m hoping it will work when brought into OpenSim, doing a private art installation and would love some flocking surreal wildlife.

    Thanks in advance! No need to inform me here, I probably won’t see it.

  31. I try the script but get error’s can you send me the script inworld. Corne Garfield.
    Thanks

  32. Hi
    I looked at script and found that it compiled ok when you replace the pasted double quotes

  33. Hey, can you drop me an example, I cant seem to get it working, no matter what I try…
    My name is Kiana Woodrunner on SL
    Thanks very much, and I hope to be making some flying death stars soon…

    Hehehe

  34. Sent you one earlier today.

  35. Id like 1 2 please!! :)))))
    Melichka Trizomu

  36. Please may I get a working copy too .. many thanks and Best Regards

  37. // Swarm script
    // by Apotheus Silverman
    // with mods from Riptide Ramos
    // 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.

    // Configurable parameters

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

    // Timer length
    float timer_length = 0.7;

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

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

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

    // 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.6;

    // How much to modify rotation damping. Higher numbers produce slower rotation.
    float rotation_modifier = 80;

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

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

    // Collision function
    collide(vector loc) {
    vector mypos = llGetPos();
    float mass = llGetMass();
    // Apply repulse force
    vector impulse = llVecNorm(mypos – loc);
    llApplyImpulse(impulse * repulse_force_modifier * mass, FALSE);
    // Update rotation
    llLookAt(mypos + llGetVel(), mass * 0.5, mass * rotation_modifier);
    }

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

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

    // Check for air/water breach
    if (flight_mode == 1) {
    // water
    if (mypos.z >= llWater(mypos)) {
    collide( );
    }
    } else if (flight_mode == 2) {
    // air
    if (mypos.z <= llWater(mypos)) {
    collide( );
    }
    }
    }

    default {
    state_entry() {
    llSay(0, “Fishy spawned.”);

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

    // Initialize physics behavior
    llSetBuoyancy(1.0);
    llSetStatus(STATUS_PHYSICS, TRUE);
    llSetStatus(STATUS_PHANTOM, FALSE);

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

    collision_start(integer total_number) {
    collide(llDetectedPos(0));
    }
    land_collision_start(vector position) {
    vector mypos = llGetPos();
    collide(mypos – llGroundNormal(mypos));
    }

    no_sensor() {
    sensor_any();
    }

    sensor(integer total_number) {
    sensor_any();

    // Populate neighbors with the positions of the two nearest neighbors.
    vector mypos = llGetPos();
    float mass = llGetMass();
    list neighbors = [];
    integer i;

    vector v1;
    vector v2;
    float d1 = 100;
    float d2 = 100;

    for (i = 0; i < total_number; i++) {
    vector current_pos = llDetectedPos(i);
    float cur_dist = llVecDist(mypos, current_pos);
    if ( cur_dist < d1 ) {
    // Shift list down, take over top slot.
    d2 = d1;
    v2 = v1;
    d1 = cur_dist;
    v1 = current_pos;
    } else if ( cur_dist < d2 ) {
    // Replace second slot only
    d2 = cur_dist;
    v2 = current_pos;
    }
    }

    // Process movement

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

    // Apply force
    if (llGetListLength(neighbors) == 2) {
    vector neighbor1 = llList2Vector(neighbors, 0);
    vector neighbor2 = llList2Vector(neighbors, 1);
    vector target = neighbor2 + ((neighbor1 – neighbor2) * 0.5);
    vector impulse = llVecNorm(target – mypos);
    llSetForce(impulse * force_modifier * mass, FALSE);
    }

    // Update rotation
    llLookAt(llGetPos() + llGetVel(), mass * 0.5, mass * rotation_modifier);
    }

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

  38. Could someone also send me a working copy of this script in world. My name is xB45 Maggs, thank you very much

  39. Wonderful page. hope to visit again:D

  40. Could I also receive a copy of the script in world, And really great work I am excited to work with this. My name is Omen Crow

  41. Hi,
    It does not work for me. Pls send me pls.

    sl Zizawar Yardley

  42. It works now after retype – and “. Thank you so much.

  43. Can I also have one copy please, my in world name is et0021 Jupiter… thanks….

  44. The error i got is under

    // Collision function
    collide(vector loc) {
    vector mypos = llGetPos();
    // Apply repulse force
    vector impulse = llVecNorm(mypos-loc);
    llApplyImpulse(impulse * repulse_force_modifier * mass, FALSE);
    //llSay(0, “collide() – impulse ” + (string)impulse + ” applied.”);
    // Update rotation
    do_rotation(mypos, llGetVel());
    }

    The SL say line vector impulse = llVecNorm(mypos-loc); got syntax error. May I know why?

  45. will this script work with simple shapes or points, i am trying to generate a flocking/swarming like moveement of a series of basic shapes through my building. i am an architecture student but have little experiance with scripting. is this one suitable? or is there an easier generative script out there?

  46. please send me a copy too my ID is Guruh Back

  47. LMSO – hilarious, I bet you’re sorry you posted this!

  48. I kept getting syntax errors – Even after copying to notepad then into SL, I was getting syntax errors in two places:

    1. The minus signs had all changed to em-dashes
    2. Some of the quotation marks had been changed to the wrong kind.

    Once I got those straightened out, The script worked beautifully, however the prims tended to prefer to stay below the terrain surface. I’ll need to work that one out next…

    Thanks for sharing this script, much fun!

  49. I got the script to compile successfully by making the following edits with ctrl F in the SL script editor. I just found the lines that had been converted to a bad format and manually retyped them out. You can copy paste the ll part to get the tab to make things easier. It may look the same but something about how the text copy / pastes out of this page into the script editor screws up two lines. Create a box, drop it on the ground, drop this script in it then save it to your inventory. Don’t expect the one on the ground to do anything cause it never rezzed so it wont activate the script. After saving it to your inventory, delete the one on the ground then drag 3 out of your inventory to the ground. They script should pop some green text saying “Fishy Spawned.” and they will begin to swarm each other. Btw, I also tweaked mine for air as I’m rezzing on the ground.

    This is where I saw the ” that should be a ” yes, I did see someone else pointed this out. I hope this helps the rest catch on.

    change
    llSay(0, “Fishy spawned.”);
    to
    llSay(0, “Fishy spawned.”);

    &

    change
    llListen(school_comm_channel, “”, NULL_KEY, “”);
    to
    llListen(school_comm_channel, “”,NULL_KEY, “”);

  50. To my last comment, please not that even me posting a ” turns into a “. Just manually type that char out into the SL script editor and you will see the difference. One is angled ( the wrong one ) and one is straight ( correct char )

  51. Could you send send me a working copy of this script in world. My name is Cybertgirl Gynoid, t I would appreciate it a lot. Thank you very much in advance

  52. The fix is very simple.
    Just replace all the (bad) minus signs and quotes by real minus signs and quotes. And it works.

    But I only get a dropping bee/bird until it dies. Was hoping it would fly around…

  53. you need at least three objects (a swarm) before they start flying around.

  54. They do fly around, but do not rotate so far.

  55. Funny. Made new prims and they rotate. One I had made, doesn’t.

    Nice work anyway.

  56. Brilliant algorithm! I have had fun with this script and made a swarm of bats inside a hollow sphere – that seems to be the best shape.

    HOWEVER – the rezzing script works right up to the moment that I log out of SL – then it stops rezzing.
    Has anyone else experienced this?
    Any suggestions?

    Jarapanda Snook

  57. I tried this today and nothing I did all the work arounds and tried some that I know but nothing can you help?

  58. Hmm. Apparently this doesn’t work well under OpenSimulator 0.7.5 (dev). All that happens is that newly spawned fish (I’m using fishes for now) flip on their sides and sink to slightly below ground, where they remain until they die. It’s a bit morbid, to be honest :)

    Since this script is so insanely old, maybe it triggers some yet-to-be-discovered bugs in OpenSim.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.

%d bloggers like this: