Original Author:
Create Date: 10/29/2009
Category: Animation
Description: I found this on a website a long time ago and even though we have animesh, it was fun to use and I thought others might like it to play with. i left the copyright in place because Shine Renoir deserves the kudos for it.
Download Script Here:
// bending fish // 2007 Copyright by Shine Renoir (This email address is being protected from spambots. You need JavaScript enabled to view it. ) // //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). // 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); } } }
Have Questions? Need help? Leave a note for Kitsune Lassiter in Second Life
Additional Notes & Instructions(If any):