Showing posts with label Scripter/Builder. Show all posts
Showing posts with label Scripter/Builder. Show all posts

Monday, September 17, 2007

SL Scripter/Builder: Random thoughts on LSL and Scripting Quality Attributes

I'm digging lately into the LSL jungle. So there were a number of things that came to my attention: I will summarize some of them:

  • LSL scripts are finite state machines in general. It's very intuitive trying to map the states from the problem doman to states in LSL. Let's say, we have to develop a door , which have to open when avatar is detected and then closed automatically. From the problems doman(a door) we know that the door may be open or closed , e.g. we have two states: OPEN, CLOSED. Using LSL will looks like that:

    default
    {
    state_entry()
    {
    state closed;
    }
    }

    state open
    {
    state_entry()
    {
    //allow avatars to get through the door
    llSetStatus(STATUS_PHANTOM,FALSE);
    //make it invisble
    llSetAlpha(ALL_SIDES,0.2);
    //hook to the sensor event
    llSensorRepeat("",NULL_KEY,AGENT,SCAN_RANGE,PI,SCAN_RATE);
    }

    sensor(integer num_detected)
    {

    }

    no_sensor()
    {
    //close the door if nothing is detected
    state close;
    }
    }

    state closed
    {
    state_entry()
    {
    //block avatars to get through the door
    llSetPrimStatus(STATUS_PHANTOM,TRUE);
    //make it visible
    llSetAlpha(ALL_SIDES,1);
    //hook to the sensor event
    l lSensorRepeat("",NULL_KEY,AGENT,SCAN_RANGE,PI,SCAN_RATE);
    }

    sensor(integer num_detected)
    {
    //open the door by using state transition
    state open;
    }
    }

    Note that event hooks(llListen,llSensor,llSetTimerEvent, etc) are valid within the state they are started. State transitions make event hooks unavailable. If you want the door to respond to chat commands, you should invoke llListen and implement listen() event on every state. However you may place the listen logic in a global routine and invoke it in every state's listen event in order to avoid duplicate code sections.

  • Note that llSensor and llSensorRepeat support event no_sensor . It may be used to trigger processing, when nothing is detected. Event sensor is raised only when something is sensed. In other words the following snipset is useless:


    sensor(integer num_detected)
    {
    if(num_detected>0)
    {
    //something is sensed, process it here
    }
    else
    {
    //script flow will never reach here.
    }
    }

    instead use the following one:
    ...
    llSensorRepeat("","",SCAN_RANGE,PI,SCAN_RATE);
    ...

    sensor(integer num_detected)
    {
    //num_detected is always greater than 0, e.g. something is detected
    }

    no_sensor()
    {
    //nothing is detected withing the SCAN_RATE seconds
    }
  • Faciliating communication between multiple scripts in a single prim should be done via llLinkedMessage. Routines llSay and llRegionSay do not work in this case
I've looked into a lot of scripts published into the Script Library , freebies and commercial objects, lately. I found it strange that most of them lack of coding practicies, which are considered as must for the software industry these days. Some of them are:
I'm aware that LSL has its own limitations and that these practices on max will increase the memory and performance preassure during runtime. However, this may not be an argument to fully forget about these concepts. We have to find the balance between maintability and usabilty.
I just don't understand, how a quality product and customer service(in-world) with a longer life cycle may be provided, when the unerlying code base does not have basic quality attributes.

Saturday, September 8, 2007

SL Scripter/Builder: How to rotate an object to a target direction, when the object has STATUS_PHYSICS

If you're going to be a scripter in SL , soon or later you will crash into a bunch of problems, when trying to rotate objects/prims.
A good start for every scripters in the jungle of rotations, quaternions and vectors and other 3D space related manupulations are the following resources:
http://wiki.secondlife.com/wiki/Rotation
http://www.cprogramming.com/tutorial/3d/quaternions.html
http://www.euclideanspace.com/maths/index.htm


I had a problem like this lately. I'm working on a new product called Star Glider - a kind of stylish flying vehicle and needed to implement a feature called auto-landing.
During the auto-land sequence the vehicle needed to rotate its self(around the Y axis) and become parallel to the ground. The idea behind this is to avoid landing on the vehicle nose or tail, when the pilot approaches the ground.



So, here comes the problem - How to rotate an object to a target direction.
In the problem given up, I will consider (for simplicity) that the ground rotation is equal to zero. Looking up the image:

  • V1 represents a ZERO vector <0,0,0> - a vector with ZERO angle relative to the Y axis. It is our target vector (note the image is not exact from a mathematical point of view)
  • V2 represents the current direction of the object in the Y-Z plane

What we need is to calculate the angle between the two vectors , generate a rotation quaternion based on the angle and apply the quaternion over the object.
The following script may be used:

//getting current rotation of the object(global rotation of the root prim)
rotation currentRot = llGetRot();
//getting vector V2 - the direction in the Y-Z plane
vector v1 = llRot2Left(currentRot);
vector v2 =<0,0,0>;
//generate rotation based on the angle between two vectors
rotation targetRot = llRotBetween(v1,v2);
//apply rotation
llRotLookAt(targetRot,1,1);

If you have a situation like in the image, the object will rotate untill becomes parallel with the ground - e.g. untiul the angle become ZERO;


NOTE:
Instead of llRotLookAt one may try to use llSetRot. However llSetRot does not work over physical prims (STATUS_PHYSICS).

Links:
http://wiki.secondlife.com/wiki/Rotation
http://www.cprogramming.com/tutorial/3d/quaternions.html
http://www.euclideanspace.com/maths/index.htm