'Open Source Scripting' group (Second Life) wiki

Bending Fish

Modified: 25/02/2007 03:13 by Shine.

A short tutorial how to build linked objects, which are physical and flexible at the same time, with a fish movement script as an example



First create a box A. Edit it, click Object->More and select the Physical checkbox. Then create a box B and select the Features->Flexible Path checkbox. Set 1 for wind for testing. Now first select box B, then ctrl-click box A to select both and click Link in Tools menu. This makes box A the root prim in the link set. Now the whole link set is physical, but box B is still flexible.

Finally you can add the script below to the link set for a fish movement. Edit the objects by checking the "Edit linked parts" checkbox to make box A invisible, apply texture to box B and rotate it for the right bending effect, change the flexible parameters and move box A within the link set for more realistic movement (somewhere inside the fish).

 
// bending fish
// 2007 Copyright by Shine Renoir (fb@frank-buss.de)
//
// The center position is stored on rez.

// maximum swim radius from last center float radius = 3.0;

// maximum swim distance for swimming up or down from last center float height = 1.0;

// delay in seconds for next movement float delay = 4.0;

// internal channel for communication integer CHANNEL = -87;

// last center position vector center;

float randBetween(float min, float max) { return llFrand(max - min) + min; }

init() { llOwnerSay("start swimming"); llListen(CHANNEL, "", llGetOwner(), ""); llSetTimerEvent(0.0); llSetStatus(STATUS_ROTATE_X, FALSE); llSetStatus(STATUS_ROTATE_Y, FALSE); float t = llSqrt(2.0) / 2.0; llSetRot(<0, 0, 0, 0>); center = llGetPos(); llSetBuoyancy(1.0); llSetTimerEvent(delay); }

default { touch_start(integer num) { llDialog(llGetOwner(), "Click 'stop', then move the fish to a new center and then click 'start'. Change parameters with the other buttons", ["radius", "height", "delay", "stop", "start"], -33); }

state_entry() { init(); }

on_rez(integer start_num) { init(); }

timer() { // get current position vector pos = llGetPos(); // calculate random next position vector dest = pos; dest.x += randBetween(-radius, radius); dest.y += randBetween(-radius, radius); dest.z += randBetween(-radius, height); // move to center, if outside radius integer i; for (i = 0; i < 3; i++) { if (llVecMag(dest - center) > radius) { dest = (dest - pos) / 2.0 + pos; } } if (dest.z < center.z - height) { dest.z += 0.5; } if (dest.z > center.z + height) { dest.z -= 0.5; } // fallback: if other objects pushes the fish, move back to center if (llVecMag(dest - center) > radius) { dest = center; }

// calculate new rotation and move to target vector delta = pos - dest; float angle = llAtan2(delta.y, delta.x) + PI / 2.0; rotation rot = llEuler2Rot(<0, 0, angle>); llRotLookAt(rot, 1.0, 1.0); llMoveToTarget(dest, 2); }

listen(integer channel, string name, key id, string message) { if (message == "stop") { llOwnerSay("stop swimming"); llSetTimerEvent(0.0); llStopMoveToTarget(); } else if (message == "start") { init(); } else if (message == "radius") { llDialog(llGetOwner(), "Change radius in meters from center of the fish. Current radius: " + (string) radius, ["radius +1", "radius -1", "radius +5", "radius -5"], -33); } else if (message == "radius +1") { radius += 1.0; llOwnerSay("new radius: " + (string) radius); } else if (message == "radius -1") { radius -= 1.0; if (radius < 1.0) { radius = 1.0; } llOwnerSay("new radius: " + (string) radius); } else if (message == "radius +5") { radius += 5.0; llOwnerSay("new radius: " + (string) radius); } else if (message == "radius -5") { radius -= 5.0; if (radius < 1.0) { radius = 1.0; } llOwnerSay("new radius: " + (string) radius); } else if (message == "height") { llDialog(llGetOwner(), "Change moving height in meters. Current height: " + (string) height, ["height +1", "height -1", "height +5", "height -5"], -33); } else if (message == "height +1") { height += 1.0; llOwnerSay("new height: " + (string) height); } else if (message == "height -1") { height -= 1.0; if (height < 1.0) { height = 1.0; } llOwnerSay("new height: " + (string) height); } else if (message == "height +5") { height += 5.0; llOwnerSay("new height: " + (string) height); } else if (message == "radius -5") { height -= 5.0; if (height < 1.0) { height = 1.0; } llOwnerSay("new height: " + (string) height); } else if (message == "delay") { llDialog(llGetOwner(), "Change max delay in seconds. Current delay: " + (string) delay, ["delay +1", "delay -1"], -33); } else if (message == "delay +1") { delay += 1.0; llOwnerSay("new delay: " + (string) delay); } else if (message == "delay -1") { delay -= 1.0; if (delay < 1.0) { delay = 1.0; } llOwnerSay("new delay: " + (string) delay); } } }

ScrewTurn Wiki version 1.0.11. Some of the icons created by FamFamFam.