Difference between revisions of "LSL 101/Variables"

From Second Life Wiki
Jump to navigation Jump to search
m (<lsl> tag to <source>)
 
(21 intermediate revisions by 5 users not shown)
Line 1: Line 1:
[[Category:LSL 101]]
[[Category:LSL 101]]
{{NavNextPrev|prev=String Concatenation|next=}}
{{NavNextPrev|prev=The touch start Event|next=Strings and Simple Output}}
{{LSL Wikibook Index}}


In our previous example, each time the touch_start event handler is invoked we ask the server for the name of the region using ''llGetRegionName''.  If we know the object with the script isn't going to be moving between regions, we might like to get the region name from the server just once, and then reuse the name each time the object is clicked on.  To do that, we need to use a '''variable''' to store the region name.
==Data types - Variables ==


Here's a script that asks for the sim's name when the script is initialized, stored the name in a variable we have named ''RegionName'', and uses that as the source for the name each time it is needed.
LSL accepts seven types of [[LSL_Variables |variable]] data: string, key, integer, float, vector, rotation, or list. We will discuss each type below.  


<lsl>string RegionName;
The value of the variable is limited by its type.  There is more on this below, too. 
 
Constants are variables where the data doesn't change, they're defined by the system and you'll see them in CAPITAL letters throughout. The Boolean Constants TRUE and FALSE and there are many predefined constants in LSL. There is a list at [https://wiki.secondlife.com/wiki/Category:LSL_Constants  LSL Constants]
 
This page might seem too long, but the only other option was seven separate pages, so please bear with it, there's a lot of information, but every effort has been made to not be redundant or overly detailed. Each section head is a link to the official SL wiki page for that data type. 
 
===[[String|string]]===
 
A string is text data enclosed in " double quotes ".  Any character or number, symbol or sign can be used as text data. 
 
Strings can be joined together by using a + plus sign (called the *+ [[Operator|operator]]*)
 
If you need to use accents, new lines or other special characters and it's just not working out, read the notes on the [[String|string]] wiki page.
 
See [[LSL 101/Strings and Simple Output | Strings and Simple Output]] and [[LSL_101/String_Concatenation | String Concatenation ]] which are part of the LSL 101 and contain more information and examples for this heavily used type of data.
 
===[[Key|key]]===
 
Key data is the [[UUID|Universally Unique Identifier]] for every object, texture, sound, animation, and avatar inworld.  Each has some combination of 36 dashes, numbers or letters. 
 
Objects that are taken to inventory and re-rezzed get a new key on-rez.  This is why servers have to stay in the same place inworld to work with delivery systems.  If the server is taken to inventory, it loses its UUID and its  daughter prims can no longer find it, as the new UUID was selected by the system at random. 
 
Avatar keys as well as keys for imported sounds, animations & avatars remain constant, unless stored in a box and returned to inventory at which point they receive new keys.  An item must remain active in your inventory for its key to be accessible inworld. 
 
But how to get a key? 
* someone gives it to you
* use a function like [[LlGetKey|llGetKey]] and the one in the next example
* in inventory on full permission items by right clicking and selecting "copy asset UUID."
 
This script solves two problems: how to get the avatar keys of people who touch your stuff, and how to keep the prim from losing touch of the number of poky fingered friends of yours who just have to push the red button labeled "don't push this button".  It  will tell you the name & UUID key of each toucher in roughly the order of touching.
 
<source lang="lsl2">
default
{
    touch_start(integer total_number)
    {
        integer number = 0;  // start at zero
        do
            llOwnerSay(llDetectedName( number ) + "'s key is: " + (string) llDetectedKey(number));
// tell my owner each toucher's name & key
        while(total_number > ++number);
// while the total number from the touch_start event
// is greater than the incremented number ( ++number )
      }
}
</source>
 
 
===[[Integer|integer]]===
 
Integers are numbers, but only a limited set of numbers.  Integers in LSL are any numbers between −2,147,483,648 and +2,147,483,647, so long as they are 'whole' numbers (that is, they don't have a decimal point, like 1.5).
 
Integers are declared and defined like this
 
<source lang="lsl2">
integer myNumber = 42;
</source>
 
To a computer *TRUE* and *FALSE* are also integers.  In fact, almost all constants are integers, the ones that are can be expressed in TRUE (value of 1) or  FALSE = (value of 0). 
 
And because these are numbers we can use number [[LSL_Operators|Operators]] to manipulate them. 
 
LSL uses + for addition, - for subtraction, * for multiplication and / for division as long as the answer falls in between −2147483648 to 2147483647 the range of numbers available.
 
LSL also uses > Greater than and < Less Than as well as == equals (note the double =, a single = means an assignment, not a comparison) and the infamous "oh that's what that means" != which is does not equal.  LSL uses ++ for increment (count up) and -- for decrement (count down)
 
In addition there are &, %, ^, |, || which have more specialized uses as shown on the [[LSL_Operators| LSL Wiki Operators Page]].   
 
In string data, the + plus sign is also used to join two strings which is called "concatenation".
 
More information is coming later in this tutorial at [[LSL 101/LSL in Focus:Integers#Signed Integers|Arithmatic Operators]].
 
There is a lot more information on [[LSL_101/Integers |Integers]] which is part of this tutorial but not absolutely necessary to read right now.
 
===[[Float|float]]===
 
Floats are numbers with decimal points.  This example declares and uses float data.
<source lang="lsl2">
float min = 1.0;
float max = 10.0;


default
default
{
{
    state_entry()
    state_entry()
    {
    {
          // Store the name of the current sim for later use
        llOwnerSay("My minimum value is " + (string)min + "and my maximum value is " + (string)max);
          RegionName = llGetRegionName();
    }
    }
}
</source>
 
Notice the *typecasting* of the float to a string by the phrases
 
<source lang="lsl2">
(string)min
(string)max
</source>
 
In LSL typecasting from integer (1) to (1.0) is what is called *implicit* - meaning the system will let you get away with it, and I'll show you an example in the next section.
 
The following operators can be applied to floats:  + - * / .  You can not use % & | << >> ^  .
 
===[[Vector|vector]]===
 
Vectors use three floats enclosed in < pointy brackets > and set off by commas to express XYZ or RGB data and use the same Operators as floats. 
 
Example snippet:
<source lang="lsl2">
vector white  = <1,1,1>; // but wait you said floats ??
 
vector black  = <0,0,0>;  // yes I did, keep reading
 
vector grey  = < 0.5, 0.5, 0.5 >;  // oooh, it's an *implicit float*
//you can use an integer or a float and the system will accept it.
   
   
    touch_start( integer num_detected )
vector red    = < 1.0, 0.0, 0.0 >;
vector green  = < 0.0, 1.0, 0.0 >;
vector blue    = < 0.0, 0.0, 1.0 >;
vector yellow  = < 1.0, 1.0, 0.0 >;
vector cyan    = < 0.0, 1.0, 1.0 >;
vector magenta = < 1.0, 0.0, 1.0 >;
</source>
 
Vectors are often used for X,Y,Z data for [[LlGetPos | Position]], [[LlSetVelocity|Velocity]], and [[LSL Color|Color]] as in the example above, and they also hold data for things which only have two dimensions, the third one is given the value of zero.  One example of this is in Particles, where each sprite can only have sizes in X & Y so the third value is always zero or FALSE. Another is texture repeats, which only have X,Y data and are always shown in vector format such as <1,1,0> or <0.3,0.3,FALSE> .
 
If you need only part of a vector use this format
<source lang="lsl2">
default
{
    touch_start(integer total_number)
    {
vector test=llGetScale();
        llOwnerSay("My dimensions are: " + (string)test);
llOwnerSay("My Z dimension is: "  + (string)test.z); // Outputs only the Z size
    }
}
</source>
 
===[[Rotation|rotation]]===
 
Rotation data is expressed in quaternions, which consists of 4 float elements: x, y, z, and s. It looks like <0.0,0.0,0.0,1.0>, but many scripts use vector data for XYZ (known as Euler representation) and some mathematical function to convert them to rotations. 
 
Scripts involving angles or rotations often make use of the following float constants:-
PI_BY_TWO equals 90 degrees, expressed in radians
TWO_PI equals 360 degrees, expressed in radians
there is also a predefined rotation constant ZERO_ROTATION which effectively means 'no rotation'
 
Rotation scripts work differently if they are in the child prim of an object or in the root prim. 
 
Perhaps the most common rotating script uses llTargetOmega to make prims spin, although that simple function uses vector data and not a quaternion. Here's an example: 


  llGetRegionName() = RegionName;
<source lang="lsl2">
default
{
    state_entry()
    {
    // rotate one time per second around X axis.
        llTargetOmega(<1.0,0.0,0.0>, TWO_PI, 1.0);
    }
}
</source>


    {
That's super handy if you want perfect X Y or Z orientation, but to get an object to spin around a tilted center requires a bit of math. Don't worry, the system does most of it for you!
          // Announce the region where the script is running
          llOwnerSay( "Welcome to " + RegionName + "." );
    }
}</lsl>


When this script is executed, the sim server sees the line
Look at this script


<lsl> string RegionName;</lsl>
<source lang="lsl2">
default
{
    state_entry()
    {
        // rotate one time per second around local X axis
        // think globes !


and interprets this as a command to set aside a small chunk of this scripts available memory capable of holding a string. It then names that chunk of memory ''RegionName''. Henceforth, any time it sees the name ''RegionName'' in this script, it will know it is referring to this specific chunk of memory.
        llTargetOmega(<1.0, 0.0, 0.0>*llGetRot(), 0.1, 0.01);
    }
}
</source>


Next, the state_entry event handler will be executed, resulting in the execution of the line
Here the vector for XYZ of rotation is being multiplied by a function, llGetRot(), which *gets* the current rotation of the prim, giving it to you as a quaternion. (It's not a mathematical multiplication, '*' just happens to be the symbol used to combine rotations). 


<lsl> RegionName = llGetRegionName();</lsl>
You can also get only parts of the rotation and use that as shown in this snippet example
<source lang="lsl2">
float x = 0.0;
float y = 0.0;
float z = 0.0;
float s = 1.0;
rotation rot_a = <0.0, 0.0, 0.0, 1.0>;  //copies these values into the respective values of the rotation.
rotation rot_b = <x,y,z,s>;    //copies the values of the variable into the rot.
rotation rot_c = rot_b;  //copies the value of rot_b into rot_c


This will cause the string returned by ''llGetRegionName'' to be stored in that chunk of memory we have named ''RegionName''. (This is actually an oversimplification of what really happens, but conceptually, it's an appropriate description.)  The = sign is called the '''assignment''' operator, and the statement as a whole is called an '''assignment statement'''.  If you have need to say this line in English, you would say "RegionName is assigned the value returned by llGetRegionName" or "RegionName gets the value returned by llGetRegionName".
// this snippet brought to you by the [http://lslwiki.net/lslwiki/wakka.php?wakka=rotation *other page* on rotations].
</source>


Having stored the region name in memory, each execution of the line
There are ready made functions to help you with rotations including [[LlEuler2Rot|llEuler2Rot]] and  [[LlRot2Euler|llRot2Euler]]


<lsl> llOwnerSay( "Welcome to " + RegionName  + "." );</lsl>
If you're going to be brave enough to do rotations of objects other than these simple examples, please read the entire LSL Wiki page [[Rotation|rotation]] first.


will retrieve the region name from the script's memory instead of asking the sim each time. Since reading from memory is faster than calling a built-in function, the script will use fewer server resources.
One of the most interesting, and very accessible uses for rotations in SL is for [ http://www.heatonresearch.com/stories/encogia-ferris-wheel.html |Ferris Wheels], the scripts on that page from Jeff Heaton are excellent demonstrations of LSL rotations.


It's worth mentioning that variables in LSL (and other programming languages) are different than the variables you learn about in high school algebra.  In the context of an algebra problem, a variable represents a specific value, but what value is not known at the start of a problem.  You solve the problem in order to determine what the value is.  But even though it is called a variable, the value doesn't actually vary during the course of the problem.
===[[LSL List|list]]===


In LSL, we can easily determine what value is stored in a variable, but that value may vary during the execution of the scriptEach time an assignment statement for a variable is executed, the old value of the variable is replaced by the new value(Of course, if the old value and the new value are identical, no net change will have occurred.)
A list is a data type which can contain nothing or several *elements* or items. For example, when I start making my grocery list, it's empty, then I write all the things I need, and later when I get them, I will scratch them off the listMy list might never get empty, but it could.   


Also, the assignment operator = doesn't mean the same thing as ''equals'' in algebra.  Equality is symmetric.  That is, if a = b, then b = a.  But in LSL, the left and right hand side of the assignment play different roles.  The right hand side can be any value, but the left hand side  of the assignment refers to a chunk of memory, not the value that is stored there. The statement
Lists are set off from their world by [ square brackets ] and the items inside are separated by commas. 
 
Lists can contain all the other data types
<source lang="lsl2">
default
{
    touch_start(integer total_number)
    { 
      string clear = "8dcd4a48-2d37-4909-9f78-f7a9eb4ef903";
// we can define elements that go inside lists


<lsl> llGetRegionName() = RegionName;</lsl>
        list a = ["abc", 123 , 3.1416, < 1.0, 1.0, 1.0 > , <0.0,0.0,0.0,1.0>,clear];
        integer i;
        integer s = llGetListLength(a); // count it up
        do
        llOwnerSay(llList2String(a,i)); // list it out
        while(s>++i); // while the length of the list is greater than the number of items said
    }
}
</source>


is not the same as
Lists are really important in [[LlSetTextureAnim|texture animations]] and [[LlParticleSystem|particle effects.]]


<lsl> RegionName = llGetRegionName();</lsl>
==Conclusion==
Thank you for staying all the way to the bottom of the data types, much more information is available in the links. 


because the first of these is not even a grammatical LSL statement. There is an equality operator in LSL, but it is written as == instead of =.  We'll talk about it in more depth later.
'''Continue this tutorial with [[LSL 101/Strings and Simple Output|Strings and Simple Output]].'''

Latest revision as of 12:49, 24 January 2015

← The touch start Event ↑̲  LSL 101  ̲↑ Strings and Simple Output →

Data types - Variables

LSL accepts seven types of variable data: string, key, integer, float, vector, rotation, or list. We will discuss each type below.

The value of the variable is limited by its type. There is more on this below, too.

Constants are variables where the data doesn't change, they're defined by the system and you'll see them in CAPITAL letters throughout. The Boolean Constants TRUE and FALSE and there are many predefined constants in LSL. There is a list at LSL Constants

This page might seem too long, but the only other option was seven separate pages, so please bear with it, there's a lot of information, but every effort has been made to not be redundant or overly detailed. Each section head is a link to the official SL wiki page for that data type.

string

A string is text data enclosed in " double quotes ". Any character or number, symbol or sign can be used as text data.

Strings can be joined together by using a + plus sign (called the *+ operator*)

If you need to use accents, new lines or other special characters and it's just not working out, read the notes on the string wiki page.

See Strings and Simple Output and String Concatenation which are part of the LSL 101 and contain more information and examples for this heavily used type of data.

key

Key data is the Universally Unique Identifier for every object, texture, sound, animation, and avatar inworld. Each has some combination of 36 dashes, numbers or letters.

Objects that are taken to inventory and re-rezzed get a new key on-rez. This is why servers have to stay in the same place inworld to work with delivery systems. If the server is taken to inventory, it loses its UUID and its daughter prims can no longer find it, as the new UUID was selected by the system at random.

Avatar keys as well as keys for imported sounds, animations & avatars remain constant, unless stored in a box and returned to inventory at which point they receive new keys. An item must remain active in your inventory for its key to be accessible inworld.

But how to get a key?

  • someone gives it to you
  • use a function like llGetKey and the one in the next example
  • in inventory on full permission items by right clicking and selecting "copy asset UUID."

This script solves two problems: how to get the avatar keys of people who touch your stuff, and how to keep the prim from losing touch of the number of poky fingered friends of yours who just have to push the red button labeled "don't push this button". It will tell you the name & UUID key of each toucher in roughly the order of touching.

default
{
    touch_start(integer total_number)
    {
        integer number = 0;  // start at zero
        do 
            llOwnerSay(llDetectedName( number ) + "'s key is: " + (string) llDetectedKey(number));
		// tell my owner each toucher's name & key
        while(total_number > ++number); 
		// while the total number from the touch_start event 
		// is greater than the incremented number ( ++number )
      }
}


integer

Integers are numbers, but only a limited set of numbers. Integers in LSL are any numbers between −2,147,483,648 and +2,147,483,647, so long as they are 'whole' numbers (that is, they don't have a decimal point, like 1.5).

Integers are declared and defined like this

integer myNumber = 42;

To a computer *TRUE* and *FALSE* are also integers. In fact, almost all constants are integers, the ones that are can be expressed in TRUE (value of 1) or FALSE = (value of 0).

And because these are numbers we can use number Operators to manipulate them.

LSL uses + for addition, - for subtraction, * for multiplication and / for division as long as the answer falls in between −2147483648 to 2147483647 the range of numbers available.

LSL also uses > Greater than and < Less Than as well as == equals (note the double =, a single = means an assignment, not a comparison) and the infamous "oh that's what that means" != which is does not equal. LSL uses ++ for increment (count up) and -- for decrement (count down)

In addition there are &, %, ^, |, || which have more specialized uses as shown on the LSL Wiki Operators Page.

In string data, the + plus sign is also used to join two strings which is called "concatenation".

More information is coming later in this tutorial at Arithmatic Operators.

There is a lot more information on Integers which is part of this tutorial but not absolutely necessary to read right now.

float

Floats are numbers with decimal points. This example declares and uses float data.

float min = 1.0;
float max = 10.0;

default
{
    state_entry()
    {
        llOwnerSay("My minimum value is " + (string)min + "and my maximum value is " + (string)max);
    }
}

Notice the *typecasting* of the float to a string by the phrases

(string)min
(string)max

In LSL typecasting from integer (1) to (1.0) is what is called *implicit* - meaning the system will let you get away with it, and I'll show you an example in the next section.

The following operators can be applied to floats: + - * / . You can not use % & | << >> ^ .

vector

Vectors use three floats enclosed in < pointy brackets > and set off by commas to express XYZ or RGB data and use the same Operators as floats.

Example snippet:

vector white  = <1,1,1>;  // but wait you said floats ??

vector black  = <0,0,0>;  // yes I did, keep reading

vector grey   = < 0.5, 0.5, 0.5 >;  // oooh, it's an *implicit float* 
	//you can use an integer or a float and the system will accept it.
 
vector red     = < 1.0, 0.0, 0.0 >;
vector green   = < 0.0, 1.0, 0.0 >;
vector blue    = < 0.0, 0.0, 1.0 >;
vector yellow  = < 1.0, 1.0, 0.0 >;
vector cyan    = < 0.0, 1.0, 1.0 >;
vector magenta = < 1.0, 0.0, 1.0 >;

Vectors are often used for X,Y,Z data for Position, Velocity, and Color as in the example above, and they also hold data for things which only have two dimensions, the third one is given the value of zero. One example of this is in Particles, where each sprite can only have sizes in X & Y so the third value is always zero or FALSE. Another is texture repeats, which only have X,Y data and are always shown in vector format such as <1,1,0> or <0.3,0.3,FALSE> .

If you need only part of a vector use this format

default
{
    touch_start(integer total_number)
    {
	vector test=llGetScale();
        llOwnerSay("My dimensions are: " + (string)test);
	llOwnerSay("My Z dimension is: "  + (string)test.z); // Outputs only the Z size
    }
}

rotation

Rotation data is expressed in quaternions, which consists of 4 float elements: x, y, z, and s. It looks like <0.0,0.0,0.0,1.0>, but many scripts use vector data for XYZ (known as Euler representation) and some mathematical function to convert them to rotations.

Scripts involving angles or rotations often make use of the following float constants:-

PI_BY_TWO equals 90 degrees, expressed in radians
TWO_PI equals 360 degrees, expressed in radians

there is also a predefined rotation constant ZERO_ROTATION which effectively means 'no rotation'

Rotation scripts work differently if they are in the child prim of an object or in the root prim.

Perhaps the most common rotating script uses llTargetOmega to make prims spin, although that simple function uses vector data and not a quaternion. Here's an example:

default
{
    state_entry()
    {
    //  rotate one time per second around X axis.
        llTargetOmega(<1.0,0.0,0.0>, TWO_PI, 1.0);
    }
}

That's super handy if you want perfect X Y or Z orientation, but to get an object to spin around a tilted center requires a bit of math. Don't worry, the system does most of it for you!

Look at this script.

default
{
    state_entry()
    {
        // rotate one time per second around local X axis
        // think globes !

        llTargetOmega(<1.0, 0.0, 0.0>*llGetRot(), 0.1, 0.01);
    }
}

Here the vector for XYZ of rotation is being multiplied by a function, llGetRot(), which *gets* the current rotation of the prim, giving it to you as a quaternion. (It's not a mathematical multiplication, '*' just happens to be the symbol used to combine rotations).

You can also get only parts of the rotation and use that as shown in this snippet example

float x = 0.0;
float y = 0.0;
float z = 0.0;
float s = 1.0;
rotation rot_a = <0.0, 0.0, 0.0, 1.0>;  //copies these values into the respective values of the rotation.
rotation rot_b = <x,y,z,s>;    //copies the values of the variable into the rot.
rotation rot_c = rot_b;  //copies the value of rot_b into rot_c

// this snippet brought to you by the [http://lslwiki.net/lslwiki/wakka.php?wakka=rotation *other page* on rotations].

There are ready made functions to help you with rotations including llEuler2Rot and llRot2Euler

If you're going to be brave enough to do rotations of objects other than these simple examples, please read the entire LSL Wiki page rotation first.

One of the most interesting, and very accessible uses for rotations in SL is for [ http://www.heatonresearch.com/stories/encogia-ferris-wheel.html |Ferris Wheels], the scripts on that page from Jeff Heaton are excellent demonstrations of LSL rotations.

list

A list is a data type which can contain nothing or several *elements* or items. For example, when I start making my grocery list, it's empty, then I write all the things I need, and later when I get them, I will scratch them off the list. My list might never get empty, but it could.

Lists are set off from their world by [ square brackets ] and the items inside are separated by commas.

Lists can contain all the other data types

default
{
     touch_start(integer total_number)
    {   
       string clear = "8dcd4a48-2d37-4909-9f78-f7a9eb4ef903"; 
		// we can define elements that go inside lists

        list a = ["abc", 123 , 3.1416, < 1.0, 1.0, 1.0 > , <0.0,0.0,0.0,1.0>,clear];
        integer i;
        integer s = llGetListLength(a); // count it up 
        do
        llOwnerSay(llList2String(a,i)); // list it out
        while(s>++i); // while the length of the list is greater than the number of items said
    }
}

Lists are really important in texture animations and particle effects.

Conclusion

Thank you for staying all the way to the bottom of the data types, much more information is available in the links.

Continue this tutorial with Strings and Simple Output.