|
John Cletheroe's
Trainz Hintz - TRS2004 Scenario Creation Tutorial |
The programming language used to write TRS2004 scenarios goes by two names, GameScript and TrainzScript.
GameScript/TrainzScript is based on the "C" language, with many additional features that are required to control all aspects of Trainz. It is to some extent an object-oriented version of "C".
GameScript/TrainzScript does not have an Integrated Development Environment. Instead, programs are written using a text editor program such as Notepad (or any of its superior alternatives). GameScript/TrainzScript programs can only be run in Trainz.
Some programming languages do not require compilation. Instead, programs are converted into machine as they are run. Such languages are called interpreters. Most traditional (pre-Windows) versions of BASIC are interpreters.
Compiled languages tend to run their programs faster than interpreters. On the other hand, debugging a program in an interpreter is much easier and faster than with a compiler.
Although GameScript/TrainzScript has a compiler, it can be ignored because Trainz has a built-in interpreter for the language, or perhaps it compiles when loading a scenario which has the same effect.
Therefore, if you are reading a book on "C" with the aim of it helping you to learn GameScript/TrainzScript, totally ignore the sections referring to the compilation process.
The word "instruction" is usually reserved to mean a machine code instruction.
The word "command" is usually reserved to mean a textual instruction to a traditional operating system such as MS-DOS.
In GameScript/TrainzScript, as in "C", most statements must be terminated with a semi-colon (;). Learning when to include a semi-colon and when not to is one of the more frustrating aspects of "C".
In all programming languages, including GameScript/TrainzScript, it is very highly recommended to indent statements which lie within a FOR loop or a WHILE loop, or which are conditional on an IF/THEN statement. (These concepts are explained later in this document.)
In all programming languages, including GameScript/TrainzScript, it is very highly recommended to add meaningful comments such as headings for each part of the program, and explanations of any unusual techniques used or tricky sections. Bear in mind that you may have to debug a program months or years after writing it. In GameScript/TrainzScript, a comment is prefixed by two forward slashes (//) and runs to the end of the line.
User input to scenarios in GameScript/TrainzScript is possible within a mini-browser window but as this is a fairly advanced topic it is best ignored here.
Output of text to the user from a scenario can be to the scenario objective panel, or to the radio text box. It is also possible to output to a mini-browser window but that is considerably more complicated.
To output to the scenario objective panel, use the Interface.SetObjective function. Rather confusingly, this function doesn't set an objective, it merely displays some text.
To output to the radio text box, use the Interface.Print function. To make the radio text box visible from within a scenario, use the Interface.SetMessageWindowVisible function.
These functions are documented in the API. The API (Application Programming Interface) is an exceedingly useful document supplied and installed with TRS2004. It can be found here:
C:\Program Files\Auran\TRS2004\Scripts\docs\index.chm
In early programming languages, the only things which could be stored were numbers, and the names of the places where they could be stored were pre-defined by the language, typically the twenty-six letters of the alphabet.
For example: A = 6 puts the number 6 into the variable called A, or if you prefer, sets the value of A to 6.
For example: C = A + B looks up what numbers had previously been stored in variables A and B, adds them together, and puts the result into variable C.
In all cases, putting a value into a variable replaces its previous value. For example A = A + 1 would add one to the current value of A. Although this is nonsense in maths, it is perfectly legitimate in programming. The value of the expression on the righthand side of the equals sign is calculated, and then stored in the variable specified on the lefthand side of the equals sign.
Modern programming languages differ from the above relatively simple concepts in several very important respects.
Firstly, the names of variables are chosen by the programmer, but limited by some rules. In GameScript/TrainzScript most words and combinations of words can be used. In all languages, including GameScript/TrainzScript, it is not allowed to put spaces or most other punctuation characters in the names of variables. Either capitalise the first letter of each word (for example AltonaSignal) or use an underline character instead of a space (for example Altona_Signal). It is highly recommended to use meaningful variable names, to assist in understanding a program. Bear in mind that you may have to debug a program months or years after writing it.
Secondly, different types of variables can be used. These include different types of numbers (integers and floating point numbers), strings (sections of text), Boolean variables (which are either true or false) and sometimes additional types.
Thirdly, in GameScript/TrainzScript, as in "C", each new variable must be declared before it can be used. This is done by prefixing its name with its type, for example int a would declare an integer variable called a. The declaration can be combined with giving the variable a value, for example int a = 6 would both declare a as an integer variable and give it a value of 6. Each variable must only be declared once (subject to the next paragraph).
Fourthly, variables are only defined in the area in which they are declared and lower. Therefore the same variable name could be used in different parts of the program, require separate declarations, and have different values. This is both useful (to avoid variable name clashes) and also potentially exceedingly confusing. This concept is called variable scoping.
Fifthly, many modern languages can handle objects, which can be thought of as variables that have two or more separate values.
In GameScript/TrainzScript the subscript is put inside square brackets after the name of the array. For example A[5] and A[6] refer to two different elements within the A array. The subscript can be a numerical variable or a numerical expression.
In GameScript/TrainzScript, array subscripts start at zero.
As an example, in GameScript/TrainzScript it is often very useful to handle the set of rolling stock vehicles in a train as an array.
Expressions can also involve strings and other types of variables.
GameScript/TrainzScript, like "C", allows a wide variety of complicated multiple operations to be specified by writing two arithmetical operators next to each other, for example ++. If you are happy using these then do so. For those who find the idea nothing but a useless confusion, it can be ignored.
Functions operate in programming languages in much the same way as they do in maths. They have arguments (also called parameters) and they return results. The arguments are specified in round brackets, and separated from each other with commas.
GameScript/TrainzScript, like most programming languages, has a number of built-in functions to perform mathematical operations, for example Math.Sqrt will return the square root of a number, and Math.Rand will return a pseudo-random number.
GameScript/TrainzScript also has a vast number of built-in functions to set and get the properties of objects in Trainz. These functions are documented in the API. It is very important that each of the arguments used in a function is of the correct type (numeric, string, Boolean, an object of the correct kind, etc).
GameScript/TrainzScript, like most programming languages, also allows the programmer to create their own functions. While this concept can be very powerful, it can also easily lead to a complicated hierarchy of functions which is very difficult to maintain and almost impossible for any other programmer to understand.
If the program will know how many times to execute the loop before the loop starts, use a FOR loop. If the program won't know this, use a WHILE loop. In neither case need the programmer know how many times to execute the loop.
With a FOR loop, a control variable is given an initial value, an end condition, and an increment statement which specifies how much it should be incremented or decremented each time the loop is obeyed. These three items are placed inside round brackets and separated from each other with semi-colons. The statements within the loop are surrounded by curly brackets. For example, the following program segment will display the numbers 1 to 10 in the radio text box:
int i; // declare i as an integer variable
Interface.SetMessageWindowVisible(true); // make the radio text box visible
for ( i = 1; i <= 10; i = i + 1 )
{
Interface.Print( i ); // output to the radio text box
}
<= means "less than or equal to".
It is very highly recommended to indent the statements inside the loop.
With a WHILE loop, all that is required is the condition under which the loop will continue to be executed, for example:
bool finished = false; // define finished as a Boolean variable and set its value to false
while ( finished == false )
{
// many statements can go here
}
When testing for equality, two equals signs are needed (==). When setting a value, only one equals sign is needed (=).
Interface.SetMessageWindowVisible(true); // make the radio text box visible
if ( a > 6 )
{
Interface.Print( "a is greater than six" ); // output to the radio text box
}
An object is a variable which has multiple associated values, called properties. For example, in Trainz a rolling stock vehicle is a type of object which has mass, length, velocity and other properties. In Visual BASIC a text box has properties including its left and top (which define its position), width and height, and text.
Whereas in Visual BASIC the properties of objects can be referenced directly (for example TextBox1.Text = "Hi there" sets the Text property of the TextBox1 object), in GameScript/TrainzScript in most cases built-in functions must be used. Get.... functions retrieve properties, Set.... functions set properties. These numerous functions are documented in the API.
A class is a set of related functions, in most cases all the functions which get and set the properties of a specific type of object.
The theory of object-oriented programming, including topics such as inheritance, encapsulation and polymorphism, can be ignored except by very advanced GameScript/TrainzScript programmers.
Most recently modified 16-Apr-10