Torque Scripting Language
From TorqueWiki
Contents |
[edit] Intro
What and Why is Torque Script? ->[1]
[edit] Practiale Issues and Things to know before you start
- Capital letters in Script filenames are ignored by Torque, thus on UNIX system (that care about case) you better stick to lower case letters in filenames.
[edit] Language Basics
[edit] Links
http://tdn.garagegames.com/wiki/Torque_Console_Objects_TOC
Quick_Reference: http://tdn.garagegames.com/wiki/TorqueScript_Quick_Reference_2
Programming sections from The Game Programmer's Guide to Torque by Edward Maurina
Interfacing with the C++ Engine
Torque Script 1.3 (has more detail when newer docs)http://torque.realinfo.de/index.php?title=Torque_Script&action=edit
Console Functions: http://tdn.garagegames.com/wiki/TorqueScript_Console_Functions
[edit] Hello World
(3DGP p.61)
Create the file demo/HelloWorld.cs:
echo("Hello World");
Start the TGE demo, switch to the console "~" or "^":
exec("demo/HelloWorld.cs");
[edit] Variables
- alphanumeric and "_"
- not start with number
Scope: $ is global and % is local to a function.
[edit] Strings
String constants can be enclosed by single quotes or double quotes. A single-quoted string is a "tagged string". Tagged strings should be used for any string constant that is transmitted across a connection; the entire string is only sent once, then on subsequent transmissions a short tag identifying that string is sent instead.
Escape Sequences:
\n (newline)
\r (carriage return)
\t (tab)
\c0...\c9 (colorize subsequent text)
\cr (reset to default color)
\cp (push current color on color stack)
\co (pop color from color stack)
\xhh (two digit hex value ASCII code)
\\ (backslash)
As in C, TorqueScript allows you to create new-line and tabs using the tried and true backslash character. These are called "escape sequences". Escape sequences are used to indicate to the string processing system that a special character is being read.
Additionally, for data that is printed to the console and GUIs, you can colorize by using '\cn', where n is a value between 0 and 9, representing a pre-defined set of colors.
[edit] Special Values: NULL, null-string, none, 1/0, true/false and the empty string
- If you call a function and pass fewer parameters than the function's definition specifies, the un-passed parameters will be given an empty string as their default value.
- If you try to read an object field and the field is not found, TorqueScript will simply return an empty string, and no dynamic field will be created.
- "true" evaluates to the number 1 in TorqueScript, and the constant "false" evaluates to the number 0.
- the empty string is also called null-string
- Some function return "none" as a string. This is just a regular string.
[edit] Arrays
Arrays:
$MyArray[n] (Single-dimension)
$MyMultiArray[m,n] (Multi-dimension)
$MyMultiArray[m_n] (Multi-dimension)
TorqueScript is extremely flexible with arrays.
TorqueScript does support multi-dimensional arrays.
The reason many people get confused about multi-dimensional arrays in TorqueScript is that there are multiple-ways to address the array:
- you can separate the dimension indices m and n with commas, or even underscores.
- $a and $a[0] are separate and distinct variables.
$a = 5;
$a[0] = 6;
echo("$a == ", $a);
echo("$a[0] == ", $a[0]);
Run this code, and you will see that $a and $a[0] are distinct in the output.
- $MyArray0 and $MyArray[0] are the same.TorqueScript allows you to access array indices without using the common bracket [] syntax.
$aryMyArray[0] = "slot 0";
echo ($aryMyArray0);
$aryMyArray[1] = "slot 1";
echo ($aryMyArray1);
$aryMyArray[0,0] = "slot 0-0";
echo ($aryMyArray0_0);
It is advisable to use some kind of naming convention so it is clear when you are dealing with an array.
[edit] Vectors
"1.0 1.0 1.0 1.0" (4 element vector)
Vectors are stored as strings and interpreted as "vectors". There is a whole set of console operations for manipulating vectors. Vectors are taken as input for many game methods.
[edit] Operators
All as you expect (see [2]) with the following specials:
- @
- Concatenates one or more values together to form a new value.
- NL
- Concatenates one value together with a new line to form a new value.
- TAB
- Concatenates one value together with a tab to form a new value.
- SPC
- Concatenates one value together with a space to form a new value.
- $=
- Evaluates whether string1 is equal to string2
- !$=
- Evaluates whether string1 is not equal to string2.
[edit] Control Statements and Loops
- if-then-else
- switch
switch(expression)
{
case value0:
statements;
break;
case value1:
statements;
break;
...
case valueN:
statements;
break;
default:
statements;
};
switch only (correctly) evaluates numerics. There is a special statement, 'switch$', for strings.
break statements are superfluous. TorqueScript will only execute matching cases.
In TorqueScript, switch statements are no faster than if-then-else statements.
- switch$ -- like'switch' like only for strings.
- for-loop
for(%count = 0; %count < 5; %count++)
{
echo(%count);
}
- while-loop
[edit] Functions
Basic functions in TorqueScript are defined as follows:
function func_name([arg0],...,[argn])
{
statements;
[return val;]
}
- TorqueScript functions can take any number of arguments.
- If you define a function and give it the same name as a previously defined function, TorqueScript will completely override the old function. Even if you define the new function with a different number of parameters, if it's name is exactly the same as another function, the older function will be overridden. This is important to note: TorqueScript does not support function polymorphism in the same way C++ does. However, TorqueScript provides packages.
- If you call a function and pass fewer parameters than the function's definition specifies, the un-passed parameters will be given an empty string as their default value.
- TorqueScript supports recursion.
[edit] Packages
Packages provide dynamic function-polymorphism in TorqueScript. In short, a function defined in a package will over-ride the prior definition of a same named function when the package is activated. Packages have the following syntax:
package package_name()
{
function function_definition0()
{
[statements];
}
...
function function_definitionN()
{
[statements];
}
};
- The same function can be defined in multiple packages.
- Only functions can be packaged.
- Variables, Objectes and Datablocks cannot be packaged.
Packages can be activated,
ActivatePackage(package_name);
and deactivated:
DeactivatePackage(package_name);
The standard way to use a package is to define a previously defined function inside the package, activate it as needed, and then deactivate it to go back to the 'default' case for the function.
TorqueScript provides a useful keyword, 'Parent::'. By using the 'Parent::' keyword in a packaged function, we can execute the function that is being over-ridden. Parent:: keyword is not recursive, i.e. Parent::Parent::fun() is illegal.
It is important to understand that packages are, essentially, stacked atop each other. So, if you deactivate a package that was activated prior to other packages, you are in effect automatically deactivating all packages that were activated after it.
[edit] Objects
In Torque, every item in the game world is an object, and all game world objects can be accessed via script. For example, Player, WheeledVehicle, Item, etc are all accessible via script, though they are defined in C++.
Objects are created in TorqueScript using the following syntax:
%var = new ObjectType(Name : CopySource, arg0, ..., argn)
{
<datablock = DatablockIdentifier;>
[existing_field0 = InitialValue0;]
...
[existing_fieldM = InitialValueM;]
[dynamic_field0 = InitialValue0;]
...
[dynamic_fieldN = InitialValueN;]
};
This syntax is simpler than it looks. Let's break it down:
- %var
- Is the variable where the object's handle will be stored.
- new
- Is a key word telling the engine to create an instance of the following ObjectType.
- ObjectType
- Is any class declared in the engine or in script that has been derived from SimObject or a subclass of SimObject. SimObject-derived objects are what we were calling "game world objects" above.
- Name (optional)
- Is any expression evaluating to a string, which will be used as the object's name.
- CopySource (optional)
- The name of an object which is previously defined somewhere in script. Existing field values will be copied from CopySource to the new object being created. Any dynamic fields defined in CopySource will also be defined in the new object, and their values will be copied. Note: If CopySource is of a different ObjectType than the object being created, only CopySource's dynamic fields will be copied.
- arg0, ..., argn (optional)
- Is a comma separated list of arguments to the class constructor (if it takes any).
- datablock
- Many objects (those derived from GameBase, or children of GameBase) require datablocks to initialize specific attributes of the new object. Datablocks are discussed below.
- existing_fieldM
- In addition to initializing values with a datablock, you may also initialize existing class members (fields) here. Note: Note: In order to modify a member of a C++-defined class, the member must be exposed to the Console.
- dynamic_fieldN- Lastly, you may create new fields (which will exist only in Script) for your new object. These will show up as dynamic fields in the World Editor Inspector.
Example: One object that doesn't use a datablock and one that does:
// create a SimObject w/o modifying any fields
$example_object = new SimObject();
// create a SimObject w/ dynamic fields
$example_object = new SimObject()
{
a_new_field = "Hello world!";
};
// create a StaticShape using a datablock
datablock StaticShapeData(MyFirstDataBlock)
{
shapeFile = "~/data/shapes/player/player.dts";
junkvar = "helloworld";
};
new StaticShape()
{
dataBlock = "MyFirstDataBlock";
position = "0.0 0.0 0.0";
rotation = "1 0 0 0";
scale = "1 1 1";
};
[edit] Dynamic Fields
In addition to normal fields, which are common between all instances of an object type, TorqueScript allows you to create dynamic fields. Dynamic fields are associated with a single instance of an object and can be added and removed at will. Adding a dynamic field in TorqueScript is automatic. If you try to read an object field and the field is not found, TorqueScript will simply return an empty string, and no dynamic field will be created. However, if you try to write to an object field which doesn't exist, TorqueScript will automatically create a matching dynamic field for the object, and assign it the value you are trying to.
[edit] Dynamic Fieldnames
The Folling is possible (http://www.garagegames.com/mg/forums/result.thread.php?qt=32081):
("Heart"@%i).setVisible(1);
[edit] Console Methods
In addition to supporting the creation of functions, TorqueScript allows you to create methods that have no associated C++ counterpart:
function Classname::method_name(%this, [arg0],...,[argn])
{
statements;
[return val;]
}
The syntax breaks down as follows:
- function
- Is a keyword telling TorqueScript we are defining a new function.
- ClassName
- :
- Is the class type this function is supposed to work with.
- func_name
- Is the name of the function we are creating.
- %this
- Is a variable that will contain the handle of the 'calling object'.
- *
- ...- Is any number of additional arguments.
At a minimum, Console Methods require that you pass them an object handle. You will often see the first argument named %this. People use this as a hint, but you can name it anything you want. As with Console functions any number of additional arguments can be specified separated by commas. Also, a console method may return an optional value.
[edit] Namespaces
All objects belong to a namespace. The namespace they belong to normally defaults to the same name as the class.
// Player class Namespace
Player::
Namespaces provide separation of functionality, such that one may have functions with the same name, but belonging to separate namespaces. To use one of these functions, you must either manually select the appropriate namespace, or in some cases this is done automatically for you.
It is important to understand that the "::" is not magical in any way. In fact, you can create functions with "::" in their name. This doesn't mean they belong to a namespace. If the expression prefixing the "::" is not a valid class/namespace name, in effect, all you have done is create a unique name.
// Not really namespaces
function Ver1::doIt()
{
...
};
[edit] Namespace Hierarchies
http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=11888
For every object in Torque there is a namespace. Additionally, namespaces are chained. This means, that when the engine starts to search for something in the namespace, it begins at the entry point associated with the current object and seeks upward through all the parent's namespaces till it either finds what it is looking for or fails out.
It is important to understand, that a majority of the interesting methods that are called by the engine as a response to user action, like onCollision(), onAdd(), create(), etc., are not called on instances of objects. They are called on the datablocks of instances of objects that use datablocks. This is crucial because we can do some very special things with datablocks and their namespaces.
[edit] Datablocks
Some official definition of datablock are:
- Datablocks are special objects that are used to transmit static data from server to client.
- A datablock is an object that contains a set of characteristics which describe some other type of object.
- A datablock is a(n) object that can be declared either in C++ engine code, or in script code ... Each declared datablock can then be used as a "template" to create objects...
- Datablocks are templates and we use them to create new objects with the attributes specified by the template.
[edit] Why Objects and Datablocks?
Objects placed in the game world will fall into three broad categories:
- The object does not have much associated data and/or has few parameters.
- The object does have a lot of parameters, but these parameters are likely to be unique, or must be allowed to be unique, between instances of the object.
- The object has a lot of data or parameters, but it is OK for these datum/parameters to be shared between instances.
The first two categories fit the class of objects that do not need and are therefore not created from datablocks. Conversely, the third category fits the class of objects that could benefit from using datablocks. Unlike normal objects, you are only allowed to have a single instance of any datablock. Furthermore, objects that are created from datablocks all share the same instance of that datablock.
[edit] Using Objects with Datablocks
[edit] Interfacing with the Engine
[edit] Tranformations
getTransform: get the transform matrix for this SceneObject.
Returns a seven-element matrix/vector containing the following information:
“ PosX PosY PoxZ RotX RotY RotZ theta “, where theta is a rotation about the axis formed by “ RotX RotY RotZ “.
Notes: Use the getWord(), getWords(), and setWord() string functions for parsing the transform vector.
setTransform:
Set a seven-element matrix/vector containing the following information:
“ PosX PosY PoxZ RotX RotY RotZ theta “,
This will both translate and rotate the object,
where theta is a rotation about the axis formed by “ RotX RotY RotZ “.
The angle is in radiants (in the world editor the same angle is displayed in degrees).
getScale
returns a three-element vector containing the XYZ scale of this SceneObject.
setScale( scale ) sets the XYZ scaling factor for this object, where scale is an XYZ vector containing the new scaling factor for this object.
[edit] Math
functions and operators: GPGT p. 402
[edit] Functions on Vector
http://www.garagegames.com/docs/tge/engine/namespaceMathUtils.php
MatrixF MathUtils::createOrientFromDir ( Point3F & direction )
Creates orientation matrix from a direction vector. Assumes ( 0 0 1 ) is up.
Point3F MathUtils::randomDir ( Point3F & axis, F32 thetaAngleMin, F32 thetaAngleMax, F32 phiAngleMin = 0.0, F32 phiAngleMax = 360.0 )
Creates random direction given angle parameters similar to the particle system.
The angles are relative to the specified axis. Both phi and theta are in degrees.
void MathUtils::getAnglesFromVector ( VectorF & vec, F32 & yawAng, F32 & pitchAng )
Returns yaw and pitch angles from a given vector.
Angles are in RADIANS.
Assumes north is (0.0, 1.0, 0.0), the degrees move upwards clockwise.
The range of yaw is 0 - 2PI. The range of pitch is -PI/2 - PI/2.
ASSUMES Z AXIS IS UP
void MathUtils::getVectorFromAngles ( VectorF & vec, F32 & yawAng, F32 & pitchAng )
Returns vector from given yaw and pitch angles.
Angles are in RADIANS.
Assumes north is (0.0, 1.0, 0.0), the degrees move upwards clockwise.
The range of yaw is 0 - 2PI. The range of pitch is -PI/2 - PI/2.
ASSUMES Z AXIS IS UP
