This course will teach you how to write simple scripts for Planet.
In each 3D object, you can add scripts that run and make the object come alive.
To create a script:
// my first script event start () { say ("Salut les amis !"); say ("Comment allez-vous ?"); }
Click on the "Apply" button: the script compiles and runs and displays on the Conversation dialog :
Salut les amis ! Comment allez-vous ?
There, you have written your first script!
Let's take a closer look at this first program.
// mon premier script
The first line begins with the // sign, indicating a comment. It is therefore ignored.
event start ()
The second line is a trigger.
Event means happening, so if something happens, the script wakes up and executes the lines between braces. The start event is triggered automatically when the script starts.
{ say ("Salut les amis !"); say ("Comment allez-vous ?"); }
The braces { } surround a sequence of instructions to be executed. the say() instruction is used to display text on the chat. Each instruction must end with a semicolon (;).
say is actually a function. To execute it, you simply give its name (here say) and any arguments in brackets (here "Salut les amis !"). If there are no arguments, simply add a pair of empty parentheses ().
During the compilation of the script, it is fully checked and verified, which can make syntax errors appear.
For example if you had forgotten the final brace } at the end,
you would get an error message at the bottom
which tells you exactly where the problem is:
line 5 col 1 : syntax error : '}' expected here
Then just go to line 5 column 1 of your script, correct the text, and click "Apply" again.
To avoid syntax errors and also to facilitate reading it is important to have a clear writing style.
Example :
// my second script event start () { string(32) s; int i; s = ""; for (i=0; i<16; i++) { s = s + chr(0,i); } say ("icons : " + s); }
You can see, in the example above, that the lines between braces { } are each time shifted by two blanks to the right. In addition, a curly bracket { is always located vertically above a curly bracket }. This is a habit you should definitely get into, it prevents you from forgetting braces!
The following script also works but is not recommended because it is not understandable!
Example :
// my 3rd script (not recommended) event start () { string(32) s; int i; s = ""; for (i=0; i<16; i++) { s = s + chr(0,i); } say ("icons : " + s); }
When you post a script on a group or a forum, change the font to "Courier New" because with this font
because with this font the offsets are preserved.
Feel free, to clarify a script, to add lots of comment lines anywhere in your script.
It is enough to start a line with //.
These lines are ignored by the compilation.
Example:
// here is my first script // that I created to animate // a little bit my room. // Copyright the scriptwriter event start () { // the say command will display a text on the chat ! say ("Salut les amis !"); }
A variable is a cell in the PC's RAM memory that is given a name.
Each numeric variable contains a value between -2147483648 and +2147483647 (a little over 2 billion).
This value usually changes as the program runs.
To create a numeric variable, it must be 'declared', i.e. reserve memory space for its contents, using an 'int' declaration.
int compteur; // I create my counter
To put a value in a variable, we write an 'assignment' that looks like this:
compteur = 2; // now, counter has the value 2
To change the value of a variable, you just have to give it a new value:
compteur = 5; // now, counter has the value 5
You can also make calculations.
In the following example you can see in each line:
. to the left of the = sign, the variable where the result of the calculation will be stored,
. to the right of the = sign, a formula for the value to be calculated.
compteur = 2 + 5 * 7; // now, counter has the value 37 compteur = 5 / 2; // now, counter has the value 2 compteur = -45; // now, counter has the value -45 compteur = 100 - 101; // now, counter has the value -1
You have probably guessed that the asterisk is used to multiply. Here is a list of commonly used symbols commonly used: (learn by heart!)
operation symbol ---------------------- ------- addition + subtraction - multiplication * division / remainder of the division %
If you are paying attention, you may also have been surprised that the previous example gives result 37 and not 49.
compteur = 2 + 5 * 7; // now, counter has the value 37
The reason is that, as in mathematics, multiplication and division are done first, while addition and subtraction come next. If you are not sure about the priority of the operations, you can add parentheses to force the order of the calculations, for example like this :
compteur = (2 + 5) * 7; // now, counter has the value 49
Also, the previous example must have puzzled you.
compteur = 5 / 2; // now, counter has the value 2
Indeed the result of 5 divided by 2 is 2, we ignore the fractional part because counter is of type 'int' and can only store integers.
Let's also mention the "shift" operators:
compteur = 3 << 3; // now, counter has the value 24 compteur = 35 >> 1; // now, counter has the value 17
The operators << and >> multiply or divide by a power of 2.
Thus (a << b) is equivalent in mathematics to a . ( 2 b )
and (a >> b) is equivalent to a / ( 2 b )
Here is how to increase the value of a variable by 1:
compteur = compteur + 1; // computes compteur + 1 and stores the result in compteur
However, there is an abbreviated way to do the same thing, the incrementing :
compteur++; // increases compteur by 1
In the same way, to decrease a variable by 1, we do a decrement.
compteur--; // decreases compteur by 1
Here is how to increase the value of a variable by 10:
compteur = compteur + 10; // calculates compteur + 10 and stores the result in compteur
However, there is an abbreviated way of doing the same thing, the assignment with addition:
compteur += 10; // increases compteur by 10
In the same way, to decrease a variable by 10 :
compteur -= 10; // decreases compteur by 10
To multiply a variable by 3 :
compteur *= 3; // multiplies compteur by 3
There is an operation that stops the script with an error, it is to divide by zero, it is prohibited!
compteur = 3 / 0; // error compteur = 3 % 0; // error
After having studied the 'int' type in the previous chapter, we will now see the 'float' type which is used to store fractional numerical variables.
Example:
float f; f = 15.2476; f = 67.762 + 87.126; f *= 1.2;
You will notice that with the 'float' type, the numbers always have a mandatory dot, even if there is no part after the comma. For example to specify the value 12 you would write 12.0
A variable of type 'float' can store very large numbers, up to 38 digits. However, it takes the same space in RAM as a variable of type 'int'. How is this possible?
In fact a 'float' variable only stores the 6 or 7 most significant digits of the value, as well as an exponent which indicates how many zeros to add.
f = 3.12345678901234567890; // will be stored as 3.12345600000000000 f = 3.12e8; // f equals 3.12 x 10_exponent_8, so 31200000.0 f = 0.5; // f equals a half f = 5.0e-1; // f equals a half too
On Planet, the 'float' type is widely used, to store distances in meters, rotation angles or times in seconds.
Type 'float' allows the following operations :
operation symbol ---------------------- ------- addition + subtraction - multiplication * division /
Furthermore, the following functions are available :
float fabs (float value); // absolute value float sin (float angle); // sin, with angle in degrees float cos (float angle); // cos, with angle in degrees float atan2 (float y, float x); // arc tangent, calculates an angle in degrees float sqrt (float angle); // square root float trunc (float angle); // remove the fractional part by truncating float round (float angle); // remove the fractional part by rounding string ftos (float value, int width=0, int decimals = 3); // convert a float to a string
Example:
event start() { float n = sin(34.0); say ("sin(34) = " + ftos(n)); } // which will display : sin(34) = 0.55919
There is a 3rd kind of variable : string variables.
These do not contain numbers but strings of characters (letters, numbers, punctuation, etc ...).
Example:
string(100) nom; // I create a string variable of maximum 100 characters
To change the value of a string variable, we perform an 'assignment which looks like this:
nom = "Bonjour"; // now, name has the value "Bonjour"
Note that the value is enclosed in quotation marks.
To change the value of the variable, simply give it a new value:
nom = "Bonsoir"; // now, name has the value "Bonsoir"
You can paste several strings together with the "+" operator.
nom = "Bon" + "soir"; // now, name has the value "Bonsoir" nom = nom + " mes amis"; // now, name has the value "Bonsoir mes amis"
Warning: the length of a string variable cannot exceed 1024 characters.
To delete a string variable, you can assign an empty string to it.
nom = ""; // now, nom is empty
Le type 'string' permet les opérations suivantes :
int len (string value); // calcule la longueur de la chaine string chr (int c1, int c2, int c3, ..., int c16); // convert ascii codes to string int asc (string value, int index=1); // convert the nth character of the string into ascii code string left (string value, int count); // take the first N characters string right (string value, int count); // take the last N characters string mid (string value, int index, int count=); // take the N characters starting at the ith int pos (string phrase, string word); // find the position of a string in another string dup (string value, int count); // duplicate a string N times string upper (string value); // removes accents and converts to uppercase string lower (string value); // removes accents and converts to lower case string trim (string value); // removes spaces before and after string ltrim (string value); // removes spaces before string rtrim (string value); // removes spaces after
We can convert a numerical variable into a string variable using the itos() function. This name actually means i to s, so int to string.
Example:
int compteur; string(32) nom; compteur = 12; nom = itos(compteur); // now, nom is "12" nom = "compteur = " + itos(compteur); // now, nom is "compteur = 12"
Conversely, a string variable can be converted into a numeric variable using the stoi() function.
int compteur; string(32) nom; nom = "12"; compteur = stoi (nom); // now, nom is 12 compteur = stoi ("13"); // now, nom is 13 compteur = stoi ("ab"); // this will give an error that stops the script, // because "ab" cannot be converted to a numerical value!
The display in the Conversation window is done with the say() procedure
Example:
say ("Bonjour !"); say (nom);
It is not allowed to give say() a numeric variable, for example this will not work:
say (compteur); // error
To display the counter value, you must first convert it into a string:
say (itos(compteur));
This can be combined by pasting several strings together:
say ("la valeur de compteur égale " + itos(compteur));
Conditions are used to "test" variables.
We can for example say "If the variable is equal to 50, do this"...
But it would be a shame to be able to test only the equality!
It should also be possible to test if the variable is less than 50, less than or equal to 50, greater than, greater than or equal to...
Don't worry, the scripting language has foreseen everything (but you didn't doubt it)
Before you see how to write an "if... else" condition, you need to know 2-3 basic symbols. These symbols are essential to create conditions.
Here is a small table of symbols to know by heart:
Symbol Meaning ======= ============= == Is equal to > Is greater than < Is less than >= Is greater than or equal to <= Is less than or equal to != Is different from
Be very careful, there are 2 symbols "==" to test the equality. A common mistake that beginners make is to put only one = symbol. I'll talk about this a little further down.
Now let's get started without further ado. We'll do a simple test, which will tell the computer:
IF the variable is this THEN do this
For example, we could test a variable "age" which contains your age. Here, to practice, we will test if you are of age, i.e. if your age is higher or equal to 18 :
Example:
if (age >= 18) { say ("You are of age!"); }
The symbol >= means "Greater than or equal to", as seen in the table earlier.
If there is only one statement between the braces, then they become optional.
So you can write :
if (age >= 18) say ("You are of age!");
If you want to test the previous codes to see how the if works, you have to place the if inside a start event and don't forget to declare a variable age to which we will give the value of our choice.
It may seem obvious to some, but apparently it wasn't to everyone so I added this example:
// Example: event start () { int age; age = 20; if (age >= 18) say ("You are of age!"); }
Here, the age variable is 20, so the "You are of age!" will be displayed.
Try changing the initial value of the variable to see. Put for example 15 : the condition will be false, and so "You are of age !" will not be displayed this time.
Use this base code to test the next examples in the chapter.
It doesn't matter how you place the braces, your program will work just as well if you write everything on one line.
For example :
if (age >= 18) { say ("You are of age!"); }
However, even if it is possible to write like that, it is not recommended ! Indeed, writing everything on the same line makes your code difficult to read.
If you don't get into the habit of airing out your code now later on when you write bigger programs you won't find your way around!
So try to present your source code the same way I do: a brace on one line, then your instructions (preceded by two blanks to "shift them to the right"), then the closing brace on one line.
There are several good ways to present your source code.
It doesn't change the way the final program works, but it's a matter of "computer style" if you will. If you see someone else's code presented a little differently, they are coding with a different style.
The main thing is that its code remains clean and readable.
Now that we know how to do a simple test, let's go a step further: if the test didn't work (it's false), we'll tell the computer to execute other instructions.
In English, we will write something like this:
IF the variable is this THEN do this ELSE do this
Just add the word else after the closing brace of the if.
Small example :
if (age >= 18) // If age is greater than or equal to 18 { say ("You are of age!"); } else // Else ... { say ("Oh it's silly, you are a minor!"); }
Things are quite simple: if the age variable is greater than or equal to 18, we display the message "You are of age!", otherwise we display "You are a minor".
We have seen how to make an "if" and an "else". It is also possible to make an "else if".
In this case we say to the computer:
IF the variable is this THEN do this ELSE IF the variable is this THEN do this THEN do that
Translation:
if (age >= 18) // If age is greater than or equal to 18 { say ("You are of age!"); } else if (age > 4) // Otherwise, if the age is at least 4 { say ("Well, you're not too young after all..."); } else // otherwise... { say ("Aga gaa aga gaaa gaaa"); // Language Baby, you can't understand ;o) }
The computer runs the tests in order:
First it tests the first if : if the condition is true, then it executes what is between the first braces.
If not, it goes to the "else if" and tests again: if this test is true, then it executes the corresponding statements between the braces.
Finally, if none of the previous tests worked, it executes the "else" instructions.
The "else" and the "else if" are not mandatory. To make a condition, you just need at least one "if" (logical, you might say, otherwise there is no condition!)
Note that you can put as many "else if" as you want. So we can write :
IF the variable is this THEN do this ELSE IF the variable is this THEN do this ELSE IF the variable is this THEN do this ELSE IF the variable is this THEN do this THEN do that
It may also be useful to run several tests at once in your yew.
For example, you would want to test if the age is greater than 18 AND if the age is less than 25.
To do this, you'll need to use some new symbols:
Symbol Meaning ======= ============= && AND || OR ! NOT
If we want to do the test I mentioned above, we have to write :
if (age > 18 && age < 25)
The two symbols "&&" stand for AND.
Our condition would be said in English:
"If age is over 18 AND age is under 25"
To make an OR, we use the 2 signs ||. I must admit that this sign is not easily accessible on our keyboards. To type it on a French AZERTY keyboard, you have to press Alt Gr + 6. On a Belgian keyboard, you have to press Alt Gr + &.
Let's imagine a stupid program that decides if a person has the right to open a bank account. It is well known that to open a bank account, it is better not to be too young (we will say arbitrarily that you have to be at least 30 years old) or to have a lot of money (because even at 10 years old you will be accepted with open arms)
Our test to see if the client has the right to open a bank account could be :
if (age > 30 || argent > 100000) { say ("Welcome to Scrooge Bank!"); } else { say ("Get out of my sight, you wretch!"); }
This test is only valid if the person is over 30 years old or has more than 100,000 euros.
The last symbol we have left to test is the exclamation mark.
In computer science, the exclamation point means "No".
You must put this sign before your condition to say "If this is not true":
Example:
if (!(age < 18))
This could be translated as "If the person is not a minor".
If the "!" had been removed in front, it would have meant the opposite: "If the person is a minor".
If you want to test if the person is just 18 years old, you should write :
if (age == 18) { say ("You just came of age!"); }
Don't forget to put 2 "equal" signs in an if, like this : ==
Another common beginner's mistake: you sometimes put a semicolon at the end of the line of an if. However, an if is a condition, and you only put a semicolon at the end of a statement, not a condition.
The following code will not work as expected because there is a semi-colon at the end of the if :
if (age == 18); // Note the semicolon here that should NOT be there say ("You've just come of age");
The computer will interpret the above erroneous example as follows:
if (age == 18) ; // Note the semicolon here that should NOT be there say ("You've just come of age");
This means that the say() will always be executed, regardless of the result of the if!
We will now go into more detail on how an if... else condition works.
Indeed, the conditions involve something called Booleans in computer science.
This is a very important concept, so open your ears (or rather your eyes)
In Physics and Chemistry class, my teacher used to make us start with some small experiments before introducing a new concept. I'm going to imitate him a little today.
Here is a very simple source code that I ask you to test:
if (true) { say ("It's true"); } else { say ("It's false"); }
Result:
It's true
But ??? We didn't put a condition in the if, just true. What does that mean that it doesn't make sense?
Yes, it does, you will understand.
Do another test now by replacing the true with a false :
if (false) { say ("It's true"); } else { say ("It's false"); }
Result:
It's false
In fact, every time you do a test in an if, that test returns true if it is true, and false if it is false.
For example :
if (age >= 18)
Here, the test you are doing is "age >= 18".
Suppose that age is 23. Then the test is true, and the computer somehow "replaces" "age >= 18" with true.
Then the computer gets (in its head) an "if (true)".
When the value is true, as we have seen, the computer says that the condition is true, so it displays "This is true"!
In the same way, if the condition is false, it replaces age >= 18 by false, and so the condition is false: the computer will read the "else" instructions.
Now try another trick: send the result of your condition to a variable, as if it were an operation (because for the computer, it is an operation!).
Example:
int age; bool majeur; age = 20; majeur = age >= 18; if (majeur) say ("adult"); else say ("minor");
As you can see, the condition age >= 18 has returned true because it is true. Therefore, our majeur variable is true.
Do the same test by setting age = 10 for example. This time, majeur will be false.
This "majeur" variable is a boolean! You can see that we declared it with :
bool majeur;
Remember this: We say that a variable which is given the values false and true is a boolean.
Often, we will do an "if" test on a boolean variable:
bool majeur; majeur = true; if (majeur) { say ("You are of age !"); } else { say ("You are a minor"); }
As majeur is true, the condition is true, so we display "You are of age !"
What is very convenient is that the condition is easily read by a human being.
We see "if (majeur)", which can be translated as "If you are majeur".
Tests on booleans are therefore easy to read and understand, as long as you have given clear names to your variables.
Here's another imaginary test:
if (majeur && garcon)
This test means "If you are of age AND you are a boy".
garcon is here another boolean variable which is true if you are a boy, and false if you are... a girl! Congratulations, you've understood everything!
Booleans are therefore used to express whether something is true or false.
This is very useful, and what I have just explained will help you understand a lot of things later.
The "if... else" condition we just saw is the most commonly used condition type.
In fact, there are not 36 ways to make a condition. The "if... else" handles all cases.
Example:
if (age == 2) { say ("Hi baby !"); } else if (age == 6) { say ("Hi kid !"); } else if (age == 12) { say ("Hello young person !"); } else if (age == 16) { say ("Hi teenager !"); } else if (age == 18) { say ("Hi adult !"); } else if (age == 68) { say ("Hi Grandpa !"); } else { say ("I have no sentence ready for your age "); }
If you need to test a sequence of equalities as in the example above, there is also the 'switch' instruction which allows you to rewrite this more cleanly:
switch (age) { case 2: say ("Hi baby !"); break; case 6; say ("Hi kid !"); break; case 12: say ("Hello young person !"); break; case 16: say ("Hi teenager !"); break; case 18: say ("Hi adult !"); break; case 68: say ("Hi Grandpa !"); break; default: say ("I have no sentence ready for your age "); break; }
Conditions can also be applied to 'float' and 'string' types.
For example we will write (f >= 1.0 && f <= 2.0) to test if f is between 1 and 2.
In the same way (name >= "TREE" && name <= "CROCO") will test if name is between TREE and CROCO in lexicographical order (dictionary order).
What is a loop?
It is a technique that allows you to repeat the same instructions several times.
As with conditions, there are many ways to make loops.
In the end, it all boils down to doing the same thing: repeating the same instructions a certain number of times.
In all cases, the pattern is the same:
<---------- Instructions ^ Instructions ^ Instructions ^ Instructions ^ -----------^
Here is what happens in order:
The computer reads the instructions from top to bottom (as usual)
Then, when it reaches the end of the loop, it starts again at the first instruction
It then starts reading the instructions again from top to bottom...
... And it goes back to the beginning of the loop.
The problem in this system is that if you don't stop it, the computer is able to repeat the instructions ad infinitum!
It is not the kind of computer to complain, you know, it does what it is told to do.
And that's where we find... conditions! When we create a loop, we always indicate a condition.
This condition will mean "Repeat the loop as long as this condition is true".
There are several ways to do this as I said. Let's see without further ado how to make a "while" loop.
Here is how to build a while loop:
while ( Condition ) { // Instructions to repeat }
It's as simple as that. While means "As long as".
So we tell the computer "As long as the condition is true: repeat the instructions between braces".
We want our loop to repeat a certain number of times.
To do this, we will create a "counter" variable which will be 0 at the beginning of the program and that we will increment as we go along.
Do you remember the incrementation? It consists in adding 1 to the variable by doing "variable++;".
Look carefully at this piece of code and, above all, try to understand it:
int compteur; compteur = 0; while (compteur < 5) { say ("Salut !"); compteur++; }
Result :
Salut ! Salut ! Salut ! Salut ! Salut !
This code repeats the "Salut!" display 5 times.
How does it work exactly ?
At the beginning, we have a counter variable initialized to 0. It is therefore 0 at the beginning of the program.
The while loop orders the repetition AS LONG AS the counter is lower than 5.
As the counter is 0 at the beginning, we enter the loop.
We display the sentence "Salut!" via a say.
We increase the value of the variable counter, thanks to the instruction "counter++;".
compteur was worth 0, it is now worth 1.
We arrive at the end of the loop (closing brace), we thus start again at the beginning, at the level of the while.
We redo the test of the while: "Is the counter always lower than 5?
Well yes, compteur is 1 So we start again the instructions of the loop.
And so on... compteur will be progressively 0, 1, 2, 3, 4, 5.
When compteur is 5, the condition "compteur < 5" is false.
As the instruction is false, we leave the loop.
We can see that the compteur variable increases as we go along in the loop, by displaying it with a say :
int compteur; compteur = 0; while (compteur < 5) { say ("the counter variable is " + itos(compteur)); compteur++; }
This will display:
the counter variable is 0 the counter variable is 1 the counter variable is 2 the counter variable is 3 the counter variable is 4
There, if you understood that, you've got it. You can have fun increasing the limit of the number of loops ("< 10" instead of "< 5").
When you create a loop, always make sure that it can stop at some point! If the condition is always true, your program will never stop!
Here is an example of an infinite loop:
while (true) { say ("infinite loop"); }
Remember booleans. Here, the condition is always true, so this program will display "infinite loop" all the time!
So be very careful : avoid at all costs to fall in an infinite loop.
In theory, the while loop allows you to make all the loops you want.
However, in some cases it is useful to have another loop system that is more "condensed" and faster to write.
For loops are very much used in programming.
I don't have any statistics at hand, but you will probably use as many for loops as while loops, so you will have to know how to handle these two types of loops.
As I said, for loops are just another way of doing a while loop.
Here is a while loop beispiel that we saw earlier:
int compteur; compteur = 0; while (compteur < 10) { say ("Salut !"); compteur++; }
Here is the equivalent in a for loop:
int compteur; for (compteur = 0 ; compteur < 10 ; compteur++) { say ("Salut !"); }
What are the differences?
There are many things between the parenthesis after the for (we will detail this later)
There is no more counter++; in the loop.
Let's look at what is between the parentheses, because that's where all the interest of the for loop lies. There are 3 condensed instructions, each separated by a semicolon:
The first one is the initialization: this first instruction is used to prepare our counter variable. In our case, we initialize the variable to 0.
The second one is the condition: as for the while loop, it is the condition that says if the loop must be repeated or not. As long as the condition is true, the for loop continues.
Finally, there is the increment: this last instruction is executed at the end of each loop to update the counter variable.
Almost all the time we will do an increment, but we can also do a decrement (variable--;) or any other operation (variable += 2; to advance from 2 to 2 for example).
In short, as you can see the for loop is nothing more than a condensed version of the while loop. Know how to use it, you will need it more than once!
The break instruction is used to abandon and leave a loop.
for (i=0; i<5; i++) { if (i == 3) break; // exit here say (itos(i)); }
will display
0 1 2
The continue instruction is used to go straight to the next loop.
for (i=0; i<5; i++) { if (i == 1 || i == 3) continue; say (itos(i)); }
will display
0 2 4
In the previous chapters, you were able to write scripts that ran by themselves and completely ignored the avatars.
Now we'll move on to another kind of script: those that interact with avatars and respond to them!
Indeed, avatars cause actions, for example :
- they click on the object
- they write lines of text
etc ...
Each time an action occurs, the corresponding event is executed.
Example :
// react with a message when the chatter touches the object event touch() { say ("Bienvenue " + avatar_name(touched_avatar())); }
In the event, we have access to a whole bunch of parameters about the action: for example touched_avatar() returns a key about the avatar that touched. We can pass this key to the avatar_name() function to get the name of the touched avatar.
You should know that 99% of the time, a script does nothing, it sleeps!
But as soon as an avatar causes an action, the script wakes up!
It then executes the few instructions contained in an event (for example it displays a message), and when it is finished, the script goes back to sleep waiting for the next action.
Between two actions, so while it sleeps, the script has completely lost its memory, i.e. all variables are reset to zero!
There is only one exception to this rule, and that is the global variables (those declared at the top of the script). These are very useful because they keep their value as long as the script is running!
However, you should know that global variables increase the cost of the script, while those declared at the bottom of the script cost nothing. So you should only use global variables if their value must be kept between 2 events.
The following script tells each avatar how many avatars have touched the object before him. To do this, it uses a variable declared at the top of the script.
// a script that counts the chatters int g_compteur = 0; event touch() { say ("Bienvenue " + avatar_name(touched_avatar())); g_compteur++; say ("you are the " + itos(g_compteur) + " person who touches me since my script is running"); }
Often, variables declared at the very top of the script start with g_ to indicate global.
This is not mandatory but is a convention among computer scientists.
Instead of reserving a single variable, you can also reserve a whole array of variables.
Example:
int[100] compteur; // I create 100 counters
In fact, the above example creates the following 100 counters:
compteur[0] compteur[1] compteur[2] compteur[3] ... compteur[99]
To clear the whole table at once (set all counters to zero), we use the clear instruction :
clear compteur;
You can store values in these counters, like this:
compteur[5] = 12; // store 12 in counter number 5 compteur[5]++; // increase counter 5 by 1 compteur[i] = 13; // store 13 in the counter i
The last example above will give a script error if the variable "i" does not have a value between 0 and 99.
Structures are another mechanism to declare several variables, but of a different type. For example here we will create an INFO structure composed of two fields : name and cost :
struct INFO { string(32) name; int cost; }
Once the structure is created, we can declare variables of it, for example :
INFO info;
and it can be assigned values:
info = {name => "Marc", cost => 10};
To access only one field of the structure, a dot is used followed by the name of the field. Example:
say (info.name);
We can combine structure and array, for example we can declare an array of 100 INFO structures:
INFO[100] table;
To delete a large variable at once, the clear instruction is convenient:
clear table;
To write the value 2 in the cost field of the 5th element of the table, we will write :
table[5].cost = 2;
What is a function? Well, for example "atan2()", which allows you to calculate the arc-tangent.
float f = atan2 (30.0, 40.0);
You also know "say()", which allows to display a text on the screen.
say ("hello");
These two functions are declared with the following formalism:
float atan2 (float y, float x); void say (string s);This formalism indicates that :
In fact a function that starts with void is a command, while a function without void calculates a result. Apart from that, the two are very similar.
Let's look at some common functions to see how they work:
date_time now (); // function that calculates the current date int rnd (int a,int b); // returns a random number between a and b
The now() function is simple: it has no parameters and calculates the date and time of the PC. For example we can write :
event start() { date_time ma_date; ma_date = now(); // put the date in my_date say (itos(ma_date.day, 2, "0") + "/" + itos(ma_date.month, 2, "0") + "/" + itos(ma_date.year, 2, "0")); }
which will print for example:
02/12/2020
The rnd() function allows to draw a random number, which is very useful for games.
Example:
event touch() { int i; i = rnd (1, 100); // choose a number from 1 to 100 to put in i say ("on choisit " + itos(i)); }
In the documentation of the script language, you will find lists of all the predefined procedures and functions.
You can also create your own functions. For example, if we wanted to create a function tan() that calculates the tangeant, we could write this:
float tan (float a) { float t = sin (a) / cos (a); return t; }
You can see that we declared the function with the formalism (but without a semicolon at the end), then between braces we put a sequence of statements to calculate the value, and finally we end the function with the statement "return" which terminates the function and specifies the value of the result.
Here is another function that says hello:
void say_hello (key k) { say ("Hello " + avatar_name (k)); } event touch() { say_hello (k => touched_avatar()); }
The event touch will call the say_hello function by giving an avatar key as parameter, and this function will display on the screen Hello and the name of this avatar.
If you want to end a void function, you can simply write "return;"
// say hello to women only void say_hello_to_female (key k) { if (avatar_gender (k) != 1) return; say ("Hello " + avatar_name (k)); } event touch() { say_hello_to_female (k => touched_avatar()); }
Here the function tests the gender of the avatar. If it's not a woman the function ends immediately
with the return without displaying anything. Otherwise we continue to display the hello.
When you use the same value several times in a long script, you can declare this value at the top of the script by a constant. If you change the value, you only have to change it in one place and you can find it easily.
Example: numerical and string constants
const int NOMBRE_DE_PLACES = 4; const float SECONDES = 30.0; const string ACCUEIL_1 = "Bonjour, j'ai "; const string ACCUEIL_2 = " places"; say (ACCUEIL_1 + itos(NOMBRE_DE_PLACES) + ACCUEIL_2);
Often constants are written in capital letters, this is a convention among computer scientists.
Example: array constants
const string(23)[3] MENU1 = {"Jeu contre l'ordinateur", "Play against computer", "Spiel gegen Computer"};
Example: constants of arrays of structures
struct BOISSON { string(16) name; } const int MAX_OBJECTS = 5; const BOISSON G_BOISSON[MAX_OBJECTS] = { {name => "Bière"}, {name => "Soda coca"}, {name => "Soda orange"}, {name => "Becher Kaffee"}, {name => "Becher Tee"}, };
Here is a script that repeats a text every 10 seconds.
event start() { start_timer (0, 10.0); } event timer (int nr) { say ("Salut les amis !"); say ("J'espère que vous allez bien :p"); start_timer (0, 10.0); }
The procedure start_timer(0, 10.0); means: "start timer number 0 in 10 seconds".
When event timer is executed, it writes the text, and the start_timer retriggers it for in 10 seconds, etc... and it loops!
The say() procedure allows you to display a text, for example :
say ("Bonjour !");
You can paste several pieces of text together using the + (plus) operator, for example:
say ("Bonjour " + "Chers Amis !");
well, in this case, we could also have written :
say ("Bonjour Chers Amis !");
But here is a more interesting case:
say ("Bonjour " + userid + " !");
here, we paste the hello and the name of the chatter together.
Note that if you write :
say (count);
you will get an error because say() only accepts string variables!
To display a value, you must first convert it into text with the itos() function.
Example :
say ("tu es la " + itos(count) + " personne qui me touche depuis que mon script tourne");
To write in different styles, you can use these functions :
color (0xFFFFFF) : changer de couleur font (5) : numéro de font style (underlined => true, italic => true, bold => true) : changer de style souligné italique ou gras
Example:
// welcome message string font(int f) { return chr(1, f); } string style(bool underlined, bool italic, bool bold) { int s=0; if (underlined) s++; if (italic) s+=2; if (bold) s+=4; return chr(2, s); } string color(int col) { return chr(4, col & 0xFFFF, col>>16); } event touch () { say ("big " + color(0x8080FF) + "kiss" + font(9) + color(0x00FF00) + style(underlined => true, italic => true, bold => true) + " from Didi"); }
This example displays the welcome message in red!
But well, if you display a lot of red text it is not practical.
Because the day you want to change the color, you have to change all the color(0x8080FF) in your program.
What you can do is to write your own color change function.
Example:
// message d'accueil string font(int f) { return chr(1, f); } string style(bool underlined, bool italic, bool bold) { int s=0; if (underlined) s++; if (italic) s+=2; if (bold) s+=4; return chr(2, s); } string color(int col) { return chr(4, col & 0xFFFF, col>>16); } string ftitle () { return color(0x8080FF) + font(8); // couleur rouge + font Impact } event touch () { say (ftitle() + "Bonjour !"); }
So if you want to change the colors or the font, you just have to modify the ftitle function.
Here is another example that shows that you can put a whole text in function :
Example:
// message d'accueil string font(int f) { return chr(1, f); } string style(bool underlined, bool italic, bool bold) { int s=0; if (underlined) s++; if (italic) s+=2; if (bold) s+=4; return chr(2, s); } string color(int col) { return chr(4, col & 0xFFFF, col>>16); } string red () { return color(0x8080FF); } string Impact () { return font(8); } string Bienvenue (string userid) { return red() + Impact() + "Bienvenue " + userid + " !"; } event touch () { say (Bienvenue (avatar_name(touched_avatar()))); }
Notice in the example above that the userid parameter was passed to the Bienvenue() function because it needed it!
Another solution would have been to use a procedure instead of a function. The difference between the two is very small: a function returns a value or a text, a procedure returns nothing ! (so void)
Example:
// message d'accueil string font(int f) { return chr(1, f); } string style(bool underlined, bool italic, bool bold) { int s=0; if (underlined) s++; if (italic) s+=2; if (bold) s+=4; return chr(2, s); } string color(int col) { return chr(4, col & 0xFFFF, col>>16); } string red () { return color(0x8080FF); } string Impact () { return font(8); } void Bienvenue (string userid) { say (red() + Impact() + "Bienvenue " + userid + " !"); } event touch () { Bienvenue (avatar_name(touched_avatar())); }
Above, you can notice that the say() procedure is no longer in the touch event, but in the procedure Bienvenue.
How to display a random welcome message?
Using the rnd() function !
Example:
// random welcome message event touch () { int n; n = rnd (1, 3); // draws a random number between 1 and 3 if (n == 1) say ("salut, ça va ?"); else if (n == 2) say ("oula, toi je ne t'aime pas !"); else say ("reviens plus tard, j'suis pas là :p"); }
Notice here that the variable 'n' has not been declared at the top of the script but in the procedure: it therefore loses its value between two actions while the script is sleeping, this is ok since we do not want to keep it.
LThe following script will choose a random welcome text from a file you have placed in the script folder of the object :
// random welcome text event touch () { // counts the number of lines in the bienvenue.txt file int count = count_lines ("bienvenue.txt"); // draws a random number between 1 and count int n = rnd (1, count); // extracts the selected line from the file string(128) s = read_line ("bienvenue.txt", n); // displays the line say (s); }
You know that the variables declared at the top of the script keep their value between two actions. But what happens when the script is changed? They are obviously deleted .
What we need is a way to keep data permanently, on the hard disk ...
We use for that the functions store and fetch which allow to write information on the Planet server then to read them again later.
store (tiroir, valeur); // stores the value in the server drawer // Example: store ("JEU-DEVINE", "1 35 16 32 89 12"); s = fetch (tiroir); // returns the value contained in the drawer // Example: fetch ("JEU-DEVINE") == "1 35 16 32 89 12"
How does it work?
Imagine you are in a large library with a wall of drawers in front of you.
On each drawer is written a name.
When you open a drawer you can put a value in it and close it. Later, you can open the drawer again and retrieve the value you put in it.
This is exactly how store and fetch work.
Of course you are free to put whatever value you want in the drawer. This can be a score, points, the number of times a chatter has entered the room, the date and time of his last visit, or any other info.