Keep In Touch

From Accident Designs Wiki

Jump to: navigation, search

Development for Ida Grøns exhibition Keep In Touch a part of Virtual Moves.

Contents

Setup

The setup consists of 2 objects with a series of LSL scripts.

Screen 
Our moving screen displaying media with both external streaming and texture animation. The screen will contain 2 scripts the first we will call follow.lsl, and the second media.lsl
Sensor 
Our central object that will keep everything in order. The sensor will contain one script called sensor.lsl

Note that in the final setup it will basically consist of 1 prim since the screen will be in the contents of the sensor.

Implementation walkthrough

  1. Rez two prims, one for the screen and one for the sensor.
  2. Put sensor.lsl inside the content of the sensor prim.
  3. Put media.lsl in the screen prim.
  4. Change permissions of all scripts and objects to give next owner full permissions.
  5. Deed screen and sensor to group.
  6. Tick of Share with group to edit the objects and scripts after they are deeded.
  7. Replace the url list in media.lsl to your desired locations
  8. Put your "64 frame" texture in the contents of the screen and name it animatedtexture
  9. Put follow.lsl in the contents of the screen and quickly right click and select take from the pie menu! - It is important that you do this quickly else the screen will delete itself after a short delay However make sure the script has finished the compilation process properly.
  10. Find the screen in your inventory and put it in the contents of the sensor.
  11. Reset the sensor and screens should come flying at you or anyone else entering the sensors radius.

The Code

Sensor Object

The sensor object will contain sensor.lsl that keeps track of the screens, scans for new targets, rezzes new screens, and makes sure no screens are following the same target. The Sensor will contain the screen inside its content and rez it when a avatar is nearby.

sensor.lsl

 
//sensor.lsl
//Created by Sophie Zhu - accidentdesigns.com
//Put this in the sensor object
integer master_channel;
float dist = 46.; //distance to scan for new targets
 
key owner;
key targetID;
integer l1;
 
list targets;
 
integer isTarget(key id)
{
    list lid = [id];
    if(-1 == llListFindList(targets, lid) ) {
        return TRUE;
    }
    return FALSE;
}
 
init()
{
    master_channel = (integer)(llFrand(99999.0) * -1);
    l1 = llListen(master_channel, "", "", "");
    integer i;
    llSensor("","",AGENT,dist,PI);
}
 
reznew(key id)
{
    targetID = id;
    targets += [targetID];
    llRezObject(llGetInventoryName(INVENTORY_OBJECT, 0), llGetPos(), <1,1,0>, <0,0,0,0>, master_channel);
}
 
default
{
    state_entry()
    {
        init();    
    }
 
    sensor(integer total_number)
    {
        integer i = 0;    
        integer a = total_number;
        for(i = 0;i<a;i++)
        {
            key id = llDetectedKey(i);
            if (isTarget( id ))
            {
                reznew(id);
                jump out;
            }
        }
        llSleep(2.0);
        llSensor("","",AGENT, dist ,PI);
        @out;
    }
 
    no_sensor()
    {
       targets = []; 
       llSleep(2.0); 
       llSensor("","",AGENT, dist, PI);
    }
 
 
    listen(integer channel, string name, key id, string message)
    {
        if( channel == master_channel )
        {
            list tmp = llParseString2List(message, [","], []);
            string setting = llList2String(tmp,0);
            if (message == "ready") {
                llWhisper(master_channel, (string)targetID);
                llSensor("","",AGENT,dist,PI);
            }
        }  
    }
}
 
 

Screen

The screen contains two scripts follow.lsl will make it follow its target and take care of physic functions and media.lsl will play media streams and texture animations. The first script will kill(delete) the object after a short delay so be sure to right click and select take from the pie menu quickly after implementing this script in its contents. Thereafter the screen should be dragged to the contents of the sensor.

follow.lsl

 
 
//follow.lsl
//Created by Sophie Zhu - accidentdesigns.com
//put this in the screen
float tau = .4;
float strength = 0.8;
integer master_channel = -3125;
integer l1;
integer deathtime = FALSE;
 
key targetID;
string targetName;
 
suicide()
{
    llDie();
}
 
WarpPos(vector destpos) { 
    //R&D by Keknehv Psaltery, ~05/25/2006 
    //with a little pokeing by Strife, and a bit more 
    //some more munging by Talarus Luan 
 
    // Keep us at ground level at the destination; assumes it is the same sim 
    vector startpos = llGetPos(); 
    float groundheight = llGround(destpos - startpos); 
    if (destpos.z < groundheight) 
        destpos.z = groundheight; 
    // Limit to max setpos height 
    if (destpos.z > 768.0) 
        destpos.z = 768.0; 
    // Compute the number of jumps necessary 
    integer jumps = (integer)(llVecDist(destpos, startpos) / 10.0) + 1; 
    // Try and avoid stack/heap collisions 
    if (jumps > 100 ) 
        jumps = 100;    //  1km should be plenty 
    integer count = 2; 
    list rules = [ PRIM_POSITION, destpos ];  //The start for the rules list 
    while (count < jumps) { 
        rules = (rules=[]) + rules + rules;   //should tighten memory use. 
        count = count << 1; 
    } 
    llSetPrimitiveParams(rules + llList2List( rules, (count - jumps) << 1, count)); 
} 
 
 
follow(key id)
{
    //llSay(0, "following key: " + (string)id + " named: " + llKey2Name(id));
    targetID = id;
    llSetStatus(STATUS_ROTATE_X | STATUS_ROTATE_Y, FALSE);
    llSetStatus(STATUS_PHYSICS | STATUS_DIE_AT_EDGE | STATUS_ROTATE_Z | STATUS_PHANTOM, TRUE);
    llSleep(0.1);
    llSensorRepeat("",id,AGENT,96,PI,0.4);
    targetName = llKey2Name(id);
    llSetObjectDesc("I'l catch you! " + targetName);
}
 
default
{
    on_rez(integer start_param)
    {
        master_channel = start_param;
        llSetPrimitiveParams([PRIM_PHANTOM, FALSE]);
        llSetStatus(STATUS_PHYSICS, FALSE);
        l1 = llListen(master_channel, "", "", "");
        llWhisper(master_channel, "ready");
    }
 
    state_entry()
    {
        llSetTimerEvent(12.);
    }
 
    listen(integer channel, string name, key id, string message)
    {
        if(channel == master_channel) {
            follow((key)message);
            llListenRemove(l1);
        }     
    }
 
    sensor(integer total_number)
    {
        llSetTimerEvent(0.0);
        deathtime = FALSE;  
        vector target = llDetectedPos(0);
        rotation targetrot = llDetectedRot(0);
        vector offset =<1.2, 0, 1.2>;
        llMoveToTarget( target + (offset*targetrot) ,tau);
        llLookAt(target,strength,0.8);
    }
 
    no_sensor()
    {
        llSetStatus(STATUS_PHYSICS, FALSE);
        WarpPos(<55.,112.,26.>);
        llSetStatus(STATUS_PHYSICS, TRUE);
        if(!deathtime)
        {
            llSetTimerEvent(10.);
            deathtime = TRUE;
        }
    }
 
    timer()
    {
        llSetTimerEvent(0.);
        suicide();
    }
}
 

media.lsl

This script takes care of media streaming and texture animation. The texture animation will divide a texture into 64 "cells", 8 across, and 8 down, and flips through them, left to right, top to bottom. Put this script in the follow screen along with the texture containing 64 cells in order. It detects who the the owner of the land is and if it changes it changes the media type (texture anim or media streaming) accordingly. If this fails you have probably forgotten to deed the screen to the group.


 
//media.lsl
//Written by Sophie Zhu accidentdesigns.com
//Put this in the screen
 
key mediatexture = "8b5fec65-8d8d-9dc5-cda8-8fdf2716e361";
string texture = "animatedtexture";
 
list mediaURL = ["http://6k.dk/idgron/SLvideo_01.mov","http://6k.dk/idgron/SLvideo_02.mov","http://6k.dk/idgron/SLvideo_03.mov","http://6k.dk/idgron/SLvideo_04.mov","http://6k.dk/idgron/SLvideo_05.mov","http://6k.dk/idgron/SLvideo_06.mov", "http://6k.dk/idgron/SLvideo_07.mov","http://6k.dk/idgron/SLvideo_08.mov","http://6k.dk/idgron/SLvideo_09.mov","http://6k.dk/idgron/SLvideo_10.mov","http://6k.dk/idgron/SLvideo_11.mov","http://6k.dk/idgron/SLvideo_12.mov","http://6k.dk/idgron/SLvideo_13.mov","http://6k.dk/idgron/SLvideo_14.mov","http://6k.dk/idgron/SLvideo_15.mov"];
 
 
integer switch = TRUE;
float n;
newMediaType(integer x) 
{
    if (x) {
        llSetTextureAnim (ANIM_ON | LOOP, ALL_SIDES, 0, 0, 0, 0, 0.0);
        llSetTexture(mediatexture, ALL_SIDES);
        //llSay(0, "new media url");
        newStream();
    } else {
        textureAnim();
    }
}
 
newStream()
{
    llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_URL, llList2String(mediaURL, (integer)llFrand(n + 1)) ,PARCEL_MEDIA_COMMAND_LOOP]);
}
integer is_home()
{
    list lstParcelDetails = llGetParcelDetails(llGetPos(), [PARCEL_DETAILS_OWNER]);
    if(  llSameGroup(  llList2Key( lstParcelDetails, 0 )  )  ) {
        return TRUE;
    }
    return FALSE;
}
init()
{
    llSetTexture(mediatexture, ALL_SIDES);
    n = (float)llGetListLength(mediaURL);
    llSetTimerEvent(1.0); // run loop to check if land ownership changes
    newStream();
}
 
textureAnim()
{
    //Say(0, "new texture");
    llSetTexture(texture, ALL_SIDES);
    llSetTextureAnim (ANIM_ON | LOOP, ALL_SIDES, 4, 4, 0, 0, 15.0);
}
 
default
{
    state_entry()
    {
        init();
    }
 
    on_rez(integer start_param)
    {
        llResetScript();
    }
 
    touch_start(integer total_number)
    {
        if(switch) {newStream();}
    }
    timer()
    {
        integer x = is_home();
        if( switch != x ) {  switch = x; newMediaType(x); }//if land owner changed check again what media type to play
 
    }
}
 
Personal tools