Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Anchoring objects in a house to move with a single group

Sabrick Sicling
Registered User
Join date: 6 Dec 2007
Posts: 3
04-07-2008 15:45
I can I put a script on an object that makes it move if another object moves?

I have about 400 prims that I want to move when I move just one "anchor" object that I can use anytime I want
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
04-07-2008 18:23
Certainly. You'll need some kind of method of identifying the anchor object. Probably that'll be some kind of chat interface, like having the anchor announce itself when first rezzed/reset. Then you'll want the scripts in the other objects to keep track of their initial position and rotation relative to the anchor. Note that you will want the movement scripts in the ROOT prims of your other objects and NOT in any child prims they might have. Though you could use chat to trigger the scripts checking on the prim's whereabouts, or use sensors, it is easier these days to simply call llGetObjectDetails() on a timer.

Here is one way to do it (note: not yet compiled or tested; may need some minor fixes):

anchor:
CODE

integer ANCHOR_CHANNEL = -1781543109;
string ANCHOR_ANNOUNCE_CHAT = "anchor";

announce()
{
llRegionSay(ANCHOR_CHANNEL, ANCHOR_ANNOUNCE_CHAT);
}

default
{
state_entry()
{
announce();
}

on_rez(integer startParam)
{
announce();
}
}


movers:
CODE

integer ANCHOR_CHANNEL = -1781543109;
string ANCHOR_ANNOUNCE_CHAT = "anchor";

float MOVE_PERIOD = 2.0;

key anchor = NULL_KEY;
rotation relativeRot;
vector relativePos;

anchorTo(key speaker)
{
anchor = id;

// Space objects apart timewise to start to reduce sudden lag spikes
llSleep(llFrand(MOVE_PERIOD));

list details = llGetObjectDetails(anchor, [ OBJECT_ROT, OBJECT_POS ]);
if (llGetListLength(details) == 0)
{
anchor = NULL_KEY;
return;
}

rotation anchorRot = llList2Rot(details, 0);
vector anchorPos = llList2Vector(details, 1);

relativeRot = llGetRot()/anchorRot;
relativePos = (llGetPos()-anchorPos)/anchorRot;
}

updatePosition()
{
list details = llGetObjectDetails(anchor, [ OBJECT_ROT, OBJECT_POS ]);
if (llGetListLength(details) == 0)
{
anchor = NULL_KEY;
return;
}

rotation anchorRot = llList2Rot(details, 0);
vector anchorPos = llList2Vector(details, 1);

rotation rot = relativeRot*anchorRot;
vector pos = relativePos*anchorRot+anchorPos;

llSetPrimitiveParams([ PRIM_ROTATION, rot, PRIM_POSITION, pos ]);
}

default
{
state_entry()
{
llListen(ANCHOR_CHANNEL, "", NULL_KEY, ANCHOR_ANNOUNCE_CHAT);
}

listen(integer channel, string name, key id, string message)
{
if (llGetOwnerKey(id) != llGetOwner() || message != ANCHOR_ANNOUNCE_CHAT)
{
return;
}

anchorTo(id);
if (anchor != NULL_KEY)
{
state moving;
}
}
}

state moving
{
state_entry()
{
llListen(ANCHOR_CHANNEL, "", NULL_KEY, ANCHOR_ANNOUNCE_CHAT);

updatePosition();
llSetTimerEvent(MOVE_PERIOD);
}

state_exit()
{
llSetTimerEvent(0.0);
}

timer()
{
updatePosition();
}

listen(integer channel, string name, key id, string message)
{
if (llGetOwnerKey(id) != llGetOwner() || message != ANCHOR_ANNOUNCE_CHAT)
{
return;
}

llSetTimerEvent(0.0);
anchorTo(id);
if (anchor == NULL_KEY)
{
state default;
} else
{
llSetTimerEvent(MOVE_PERIOD);
}
}
}


Some notes about using this:

1.) Be careful not to move the objects such that some leave the current sim, or they will be stranded; as listed here this is not checked for. If sensors were used or the anchor announced its position and rotation on a timer instead, this system could also be enhanced to cross sim borders.

2.) Don't move the anchor object for the first few seconds after the script is saved/reset or the anchor object is rezzed. Best to leave about 5 seconds just in case. You could probably put a convenient timer and announcement in the anchor script to help with this if you want.
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
04-07-2008 18:53
Bah. Actually, here is a version that simply announces from the anchor object. Simpler, more robust, and probably less demanding on sim resources. The limitation now is that all the moving objects must be within 100m of the anchor.

anchor:
CODE

integer ANCHOR_CHANNEL = -1781543109;
// format is: anchor <anchorGlobalPos>,<anchorRot>
string SET_ANCHOR_CHAT_PREFIX = "setAnchor ";
// format is: updatePos <anchorGlobalPos>,<anchorRot>
string UPDATE_POS_CHAT_PREFIX = "updatePos ";

float UPDATE_PERIOD = 5.0;

announceAnchor()
{
llShout(ANCHOR_CHANNEL, SET_ANCHOR_CHAT_PREFIX+llList2CSV([ llGetPos(), llGetRot() ]));
}

announcePos()
{
llShout(
ANCHOR_CHANNEL,
UPDATE_POS_CHAT_PREFIX+llList2CSV([ llGetRegionCorner()+llGetPos(), llGetRot() ]));
}

default
{
state_entry()
{
announceAnchor();
llSetTimerEvent(UPDATE_PERIOD);
}

on_rez(integer startParam)
{
announceAnchor();
llSetTimerEvent(UPDATE_PERIOD);
}

timer()
{
announcePos();
}

moving_end()
{
announcePos();
}
}


movers:
CODE


integer ANCHOR_CHANNEL = -1781543109;
// format is: anchor <anchorGlobalPos>,<anchorRot>
string SET_ANCHOR_CHAT_PREFIX = "setAnchor ";
// format is: updatePos <anchorGlobalPos>,<anchorRot>
string UPDATE_POS_CHAT_PREFIX = "updatePos ";

key anchor = NULL_KEY;
vector relativePos;
rotation relativeRot;

default
{
state_entry()
{
init();

llListen(ANCHOR_CHANNEL, "", NULL_KEY, "");
}

listen(integer channel, string name, key id, string message)
{
if (llGetOwnerKey(id) != llGetOwner())
{
return;
}

if (llSubStringIndex(message, SET_ANCHOR_CHAT_PREFIX) == 0)
{
list params =
llCSV2List(llDeleteSubString(message, 0, llGetStringLength(SET_ANCHOR_CHAT_PREFIX)-1));
if (llGetListLength(params) < 2)
{
return;
}

anchor = id;
vector anchorGlobalPos = (vector)llList2String(params, 0);
rotation anchorRot = (rotation)llList2String(params, 1);

vector globalPos = llGetRegionCorner()+llGetPos();

relativePos = (globalPos-anchorGlobalPos)/anchorRot;
relativeRot = llGetRot()/anchorRot;
} else if (llSubStringIndex(message, UPDATE_POS_CHAT_PREFIX) == 0)
{
if (id != anchor)
{
return;
}

list params =
llCSV2List(llDeleteSubString(message, 0, llGetStringLength(UPDATE_POS_CHAT_PREFIX)-1));
if (llGetListLength(params) < 2)
{
return;
}

vector anchorGlobalPos = (vector)llList2String(params, 0);
rotation anchorRot = (rotation)llList2String(params, 1);

vector globalPos = anchorGlobalPos+relativePos*anchorRot;
rotation rot = relativeRot*anchorRot;

llSetPrimitiveParams([ PRIM_POSITION, globalPos-llGetRegionCorner(), PRIM_ROTATION, rot ]);
}
}
}
Chaz Longstaff
Registered User
Join date: 11 Oct 2006
Posts: 685
04-07-2008 20:48
You might be able to do this with Builder's Buddy, too. Just never hit the "clean" button.