Translations of this page:

This is an old revision of the document!
—-

2. Survivor's guide to WME scripting

So we’ve managed to get over the first couple of WME tests, we’ve mastered the developers environment and now you’re surely eager to know how to advance! As you’ve probably guessed, the core of all WME operations lies in the scripts. But what IS the script?

Let’s start from the very beginning. Every software is in its core “action / reaction” based. This means that something happens and the program somehow responds to it. The action can be anything ranging from player’s mouse clicks and ending with, for example, time which passes. So back to my question – what is a script? It’s a program, which defines what actions to take care of and how to respond to them.

Now your typical WME game will be constructed from many scripts. Let’s say that you click with your mouse on a door. You’d need a script which would make your game avatar say “The door is locked.” I hope you get my point here. As we dive deeper into this chapter, you see a lot of WME magic, but let’s start right at the beginning.

The core of the WME programming lies in commands. Command tells WME to perform an action. We can have plenty of different commands ranging from simple mathematic operation (addition , substraction , etc) to complex commands like for example

Game.ChangeScene("some_scene.scene");

which makes WME to change actual scene. But let’s look at the very basics of scripting. We’d start with something which is called variable. What is a variable? It’s a container in which you can store information. In WME (unlike for example in C++) you can store any type of information into your variable (string, object, number).

Let’s look at an example:

var myvar = "Hello World";

The keyword var declares a local variable called myvar which has been filled by the text Hello World. Later on we can reference the text in the variable for example with:

Game.Msg(myvar);

This line would print Hello World on the game screen.

Syntax rule no.1
As you can see, every command ends up with a semicolon ;
Also WME is case sensitive! hello is not equal to Hello. Keep this in mind!

Very important rule is that in each script we declare variable only once. Then we reference it without keyword var.

Now let’s have a look at some basic work with variables:

var myvar = "Hello World"; 
Game.Msg(myvar); 
 
myvar = 1;		// we store number 1 in our variable 
myvar = myvar + 1;  // we add 1 to the stored number 
Game.Msg(myvar);	// we print result (number 2) 
 
myvar = myvar * 2; // multiple by 2 
myvar = myvar / 4; // Divide by 4 
 
myvar = "The result is " + myvar + "!"; 
Game.Msg(myvar); //prints out The result is 1!

Syntax rule no.2

If we want to comment out something, we use // for single line comments  
or /* */ for block comments Commented blocks or commands won’t be executed. 
 
Example: 
 
var a = 1; // we store 1 into variable a 
 
/*  This block  
   var a=1; 
   a = a +1; 
   a = 0; 
   will never get executed */

TIP: Always name your variable in an intelligent way so you find out later what is being stored inside. It’s of course funny to name a variable littleRedDwarf but if you look into your code 5 months later, you’ll be desperately trying to figure out why is your funny variable in there. Another common praxis is using lowerCamelCase or UpperCamelCase which is just a way how you capitalize letters in your variable name. So for example variable which should hold number of ingredients added to a kettle can be called for example kettleIngredients.

As you read, we’ve been speaking about something called local variable. The local means, that the variable is valid only in the script it's declared in. So imagine that we have two scripts which gets executed as test1.script followed by test2.script:

file test1.script

var a = 10; 
Game.Msg(a); //prints 10

file test2.script

var a = a + 1;  
Game.Msg(a); //prints 1, because the variable is valid for the current script only so default value is 0

But what if we want to share some value from one script to another? For that we have another kind of variable called global variable. This variable is declared using keyword global and is valid for the whole game!

Syntax rule no.3
In every script in which we want to use a global variable, we have to declare this variable through the keyword global.

And now for some arithmetic time:

  var a = 1 + 3;  // a = 4 
  a = 3 - 3;  // a = 0 
  a = 3 * 3; // a = 9 (* multiplies by) 
  a = 3 / 3; // a = 1 (/ divides by)

Let’s look at our previous example again assuming that first test1.script got executed and later on test2.script:

file test1.script

  global a = 10; 
  Game.Msg(a); //prints 10

file test1.script

   global a = a + 1;  
   Game.Msg(a); //prints 11, because the variable is valid for the whole game.

As the Real life example let's say that you have a button in some scene and if you press this button, you want some door in completely different scene to open. You simply declare a global variable and set it to true if the button was pressed. In the scene, where you find the door, you simply test this global variable and if it's set to true, you open the door. Just to clarify the term "true", there are two special values which you can set to variable - true and false. More about those in the conditions.

As we see, we’ve successfully uncovered variables, but wait - there’s much more to them. We’re just at the beginning.

2.1 Magical Arrays

Before we start with talking about arrays, I’ll give you an example of the real game problem. Imagine that you have a door protected by a number code pad. You have to punch in 4 correct numbers and then the door opens. You have a couple of different ways how to do it. Let’s start with the worst one:

terrible choice: From the previous chapter you’d probably create 4 different variables (for example code1, code2, code3, code4) and set the punched numbers into them. Then you’d again check them one by one for a match.

overly complicated choice: you have one variable and by using multiplication and mathematics, you construct one number which will you then compare with the resulting number.

smart choice: you use an array.

You can imagine an array as a set of variables. You reference those variables through indexing the array variable. This index is a number which starts with 0. I bet the example is worth thousands of words. We’ll define a variable myArray and set 3 array fields.

var myArray; 
 
myArray[0] = "Hello World";  
myArray[1] = "I’m your first array"; 
myArray[2] = "WHEEEEE!";

And of course we can do:

Game.Msg(myArray[1]);

or even

var a = 1; 
Game.Msg(myArray[a]);

which prints out the same text because variable a contains number 1.

Syntax rule no.4
We tell WME that we want to access array by using item index enclosed in square brackets.

If we got back to our real life example with a door code, we can easily set the whole code in one variable.

var doorCode; 
 
doorCode[0] = 5;  
doorCode[1] = 2; 
doorCode[2] = 3; 
doorCode[3] = 7;

Okay. Now the inquisitive coders already wonder why we don’t use something like:

var doorCode = “5”; 
 
doorCode = doorCode + “2”; 
doorCode = doorCode + “3”; 
doorCode = doorCode + “7”; // the result being 5237 in one variable.

Well, we could, but then – what if you have more complex door code and wanted to change for example 3rd number when all 4 were set? It would make things much more complicated and also - we’re now demonstrating arrays so get over it.

As you will get used to scripting, you’ll find a lot of use for arrays. The critical strength of arrays lies in the index. You can access the index value programmatically and that’s why we’ll look now in another real life example.

You surely saw how better designed games use more different responses for one action so it won’t be boring. Let’s see how it can be done and let’s use an array for it. We’ll also incorporate a new command called Random.

Random is a function which returns a random number in specified range. We’ll speak about functions and how they work later, so for now take it as something which works and don’t wonder why.

var answerArray; 
answerArray[0] = "It’s stuck!"; 
answerArray[1] = "I can’t move it!"; 
answerArray[2] = "No chance. It won’t budge!"; 
 
var reply = Random(0,2); // we set the variable reply with a random number between 0 and 2 
 
Game.Msg(answerArray[reply]); //So we can easily print a random response from our set

I think you’re getting a bit tired of this variable talk so we’ll focus now on different things and return to the big strength called objects a tad bit later on.

2.2 Conditions

Usually we need to know what’s going on. If we spoke before about the example with a door and a button, we spoke about testing if the button was pressed. But how do we actually do this test? We have a condition command called if which does the work for us. Again let’s start with some code:

var a = 1; 
 
if (a == 1) Game.Msg(“A equals to one”); // this line can be read as: if a equals to 1 execute the following command

This completely unusable example gives you the first impression what’s going on with conditions. As testing is syntactically more complicated we’ll now focus on the basics of our tests.

As you can see, the condition is itself enclosed in parentheses.

if (insert some condition here) do something;

Testing itself is done by the following logic:

  1. If we want to test that something equals to something else we use
    ==

    Example:

    if (a == 1)
  2. If we want to test that something isn't equal to something else we use
    !=

    Example:

    if (a != 1)
  3. If we want to test that something is greater than something else we use
    >

    Example:

    if (a > 1)
  4. If we want to test that something is lesser than something else we use
    <

    Example:

    if (a < 1)
  5. If we want to test that something is lesser or equal to something else we use
    <=

    Example:

    if (a <= 1)
  6. If we want to test that something is greater or equal to something else we use
    >=

    Example:

    if (a >= 1)

For variables (they're called boolean by the way) which are true or false we can use a shortcut:

var a = true; 
if (a) Game.Msg("It's true!"); 
if (!a) Game.Msg("It's false!");


But the fun doesn’t certainly end here! We can make much more complicated tests but to understand that, we have to look at another thing.
Let’s get back to the beginning:

Let's take our "if (a == 1)" and if we set variable a to 1 beforehand, we can read the command also as if 1 equals to 1. This statement is true.

If we set on the other hand variable a to 2, we can read the condition as if 2 equals to 1. This statement is false.

This trivial logic is the very elementary of the computing in general. Computers are filled to the brim with true/false logic and we have to get a grip of those.

WME reads the condition and makes an evaluation. If the statement was true, it executes the command, if the statement was false, WME doesn’t and goes on. Let’s look at this:

If we return about our real life example with button opening our door, we could use one script handling the event when the button was clicked like this:

global buttonClicked = true;

and then in the other script checking the door like this:

global buttonClicked; 
if (buttonClicked) do something which opens the door;

So now when we have the basics of conditions, we can look at how to test more than one thing at the same time.

  1. We use operator && if we want both conditions true. if (a > 1 && a < 10) means that a must be bigger than 1 and smaller than 10
  2. We use operator || if we want at least one of the conditions to be true. if (a == "John" || b == 1) means that a must contain the word John or variable b must be equal to 1.

If we want group some conditions we uses again parentheses:

if ( (a>1 && a<10) || (b =="John") ) is one of the more complicated tests. It will execute the following command if the variable a is bigger than 1 AND smaller than 10 OR if variable b contains the word John.

Syntax rule no.4
If you want to execute multiple commands in the condition, you use curly brackets to enclose the commands which will then take place.
Example:

if (a == 2) { 
  Game.Msg("Hi!"); 
  Game.Msg("Hi again!"); 
}

Both commands will be executed if variable a equals to 2

I think that you’ve already wondered if you want to test for some condition but also want to do the false statement some treatment. Here’s when the command else comes to play.

var a = 1; 
 
if (a == 1) 
{ 
	Game.Msg("It is true yet again."); 
	a = 10; 
} 
else 
	Game.Msg("Liars all over the code.");


You can of course branch the else with more if’s ad absurdum.

If is obviously practical, but there’s one example where you can solve the situation in more elegant manner. This elegant manner’s name is switch.

What switch does is to branch the program into different paths according to a variable.
Let me show you an example:

var a = Random(0,3); //we know this already! 
var b = ""; 
 
switch(a) 
{ 
	case 0: 
		Game.Msg("Branch 0"); 
		b = "Hello"; 
		break; 
	case 1: 
		Game.Msg("Branch 1"); 
		b = "Good Bye"; 
		break; 
	default: 
		Game.Msg("All other branches"); 
		b = "What to do?"; 
}

Okay. Here’s quite a lot of things going on. First we branch the code according to the variable a. This variable can be any number ranging from 0 to 3 (because of Random function). If a equals to 0 then we go through the first branch until we reach the command break; If this command wasn’t there, WME would go through all branches until it finds one! So if you want to terminate the branch use break;

Each branch is defined by the keyword case. The specific syntax of case is that you define what should variable in the switch contain if you want to take this route. And after this value is a colon ( : ).

We can also test for strings with for example *case "Sword":*

And again – we enclose the whole nesting in the curly brackets. We’ll see a lot of curly brackets later on.

BUG: Don’t use loops inside of the case branches. They don’t work. If you need, write a function (explained later) which will contain the loop. This workaround works.

2.3. Loops

There are many times when we want to use repeating actions. WME provides a couple of ways how can we accomplish that.

We’ll start with the first way how to cycle – with the command for. This command is usable if we know the exact number of repetitions. Let’s say that we want to 10 times print the word Hell.

for (var a=0; a<10; a = a+1) 
{ 
   Game.Msg(“Hell”); 
}

Let’s see what’s going on in here. The for command consists of 3 parts separated by semicolons. First part is where to start. In our case we start with a variable a set to 0. The second part is when to end. This is a bit tricky – for command ends when the second part, which is a condition, turns false! This means that it will loop until a<10. As soon as a turns 10, it will end. The last part is how to change the variable. We can use addition, substraction, multiplication, division, you name it… So in our case with each pass of the cycle, the variable a is increased by 1. Also note, that I’ve used curly brackets here even if it’s only one command in. Sometimes it’s more readable, but I’ll leave it to your preference.

Important: The cycle runs 10 times. We’re starting with 0. Get used to 0 based start logic. It’s the source of many coding problems.

Hmm. Printing ten times Hell isn’t THAT useful for game creating. Is it? Let’s see what more we can do. And this time we’re going to use Arrays for that.

var myArray; 
myArray[0] = "Hi!"; 
myArray[1] = "How’s it goin’!"; 
myArray[2] = "Bye!"; 
 
for (var a=0; a<3; a = a+1) 
{ 
   Game.Msg(myArray[a]); 
}

As you can see, we’ve easily printed all array elements on the screen. I hope you’re starting to get the right impression of the usage.

Another type of loop is so called while loop. This loop is used when we don’t know exactly how many times it should loop, but we know when it should stop.

var a = 0; 
while (a != 5) 
{ 
  a =  Random(0,5); 
  Sleep(1); 
}

This probably useless example again evaluates the expression in while and if it’s true, it executes the block. So in other words, while a is not equal to 5, set another random number to it.

Important:
Now you’re probably wondering what is going on with that Sleep(1); command. This is a bit more advanced, but if you tried the loop without the Sleep, your game would freeze and sometimes even your computer too. Why? Because the while loop would loop and loop and loop eating a lot of processor power. And the rest of the engine, which takes care of the timer and other things would never get the priority! So the whole WME would just loop. And if you’re unlucky and Random won’t be on your side returning all other numbers than 5, your computer will have serious problems. Function Sleep() which takes time in milliseconds doesn’t do anything obvious. Waiting one millisecond can hardly be noticed, but it returns control from this script to other processes! So your game will never get stuck

There’s also one more use for the while loop – so called infinite loop.

it can be defined by this for example:

while (1) 
{ 
   //do something here;// 
   Sleep(1); 
}

Those loops are very nice for some background processes you need to carry on for the whole game. For example you can check if the background music is playing and if it stops, you can play another song from the play list or in the demo project those processes handle caption displaying.

2.4. Functions

As you already saw in the case of Sleep() or Random(), there’s something called a function. Function is a big time saver because it can take care of many lines of code. Imagine this example: you want to print ten times the word hell. But you want to print it in more than one parts of your code. Without function you’d do this:

for (var a=0; a<10;a=a+1) Game.Msg("Hell"); 
Game.Msg("1"); 
for (a=0; a<10;a=a+1) Game.Msg("Hell"); // note that I had to put the var away as it was already declared before. 
Game.Msg("2"); 
for (a=0; a<10;a=a+1) Game.Msg("Hell"); // note that I had to put the var away as it was already declared before. 
Game.Msg("3");

Mess, isn’t it? So we’ll simplify our task using a function. Function is a piece of reusable code. It is defined by the keyword function, name of your preference and parentheses in which you can optionally put some parameters. The exit from the function is defined by a keyword return; Note that return forces function to leave immediately so you can use it with some logic code branching. So the basic declaration could look like this:

function Hell() 
{ 
  for (a=0; a<10;a=a+1)  
  Game.Msg("Hell");  
  return; 
} 
 
Hell(); 
Game.Msg(1); 
Hell(); 
Game.Msg(2); 
Hell(); 
Game.Msg(3);

See, it’s much more readable. But it’s just a start. Imagine that with each pass you want to write 10 times different word. That’s when the functions really start to kick in. We’ll redefine our function with adding two parameters and rename it to for example writeText.

function writeText(what,count)  
{ 
  for (a=0; a<count;a=a+1)  
  Game.Msg(what);  
  return; 
} 
 
writeText("Hell",10); 
writeText("on",2); 
writeText("Earth",5);

In the function the parameter works as a local variable which is valid only in the scope of the function. So our function has two parameters. First defines what to write and the second how many times it should be written. Our program would write 10 times Hell, 2 times on and 5 times Earth. As you can see, this function already simplified our task even more.

So we know how to pass some data to the function but functions can also return data for us. Typical example of such function is Random. As we saw earlier, Random expects 2 parameters and returns a result. We can do the same through the keyword return. Let's write a simple function:

function isBigger(number1, number2) 
{ 
     if (number1 > number2) return true; 
     return false; 
} 
 
if (isBigger(1,7)) Game.Msg("Number is higher"); 
else 
  Game.Msg("Number is smaller");


 
wmebook/ch2.1196935599.txt.gz · Last modified: 2007/12/06 11:06 by metamorphium
Recent changes RSS feed Creative Commons License Driven by DokuWiki