LiveStage's Qscript is a 'high level' programming language, similar
to other popular multimedia and web scripting languages like Lingo
or Javascript. It is a comparitively small language which maps
the QuickTime 'wired action atoms' provided by Apple onto a simpler,
more accessible form.
People who have used scripting languages before will have no trouble
entering Qscript. Newcomers to programming may find it a bit of
a challenge. One problem is understanding the 'coarse' structure
of a scripting language - the grammar. The Qscript reference palette
solves many of the usual problems with spelling mistakes by providing
drag and drop symbols, but still does not and can not help with
constructing your Qscripts.
This document is intended to provide a quick reference to that
coarse structure, including a few underdocumented gotchas, so
that such people can begin to grasp the grammar of Qscript. I
hope also that people with some experience with programming will
be able to skim over this document and get up to speed more rapidly.
There is no substitute for trying things out. Be prepared for
a certain amount of frustration when you have errors, and terrific
exhiliration when you get your scripts working. Start small, even
the most meagre Qscripts can have broad effect on a QuickTime
movie.
How Qscript relates to QuickTime
Qscript Elements
Actions
Expressions
Targets
Assignments
Control Statements
Declarations
Comments
Handlers
Mouse Events
MouseDown
MouseUp
MouseClick
MouseEnter
MouseExit
MouseMoved
FrameLoaded
KeyPressed
ListReceived
Idle
Custom Events
Using Expressions
Expressions
With Operators
Mathematical
Operators
Logical
Operators
Precedence
Datatypes
Integer
Float
Boolean
String
Array
'Valueless'
expressions
Variables
Movie
Variables
Global
Variables
Sprite
Variables
Local
Variables
Recursion
Issues
Constants
variableName=expression
See Using Expressions below.
An example assignment is
rightBorder = (TrackWidth - 10)
The expression is evaluated first, and the result is assigned
to the variable. This means that you may include a reference to
the variable itself in the expression. For example;
rightBorder = rightBorder + 10
Compare this use of the = symbol with the equality
operator.
Control Statements
Control statements are instructions which change the flow of your
scripts. Normally, your scripts are executed line by line, one
line after the other. Control statements allow you to skip over
or repeat some lines if a particular condition is met. Control
statements usually include boolean (logical)
expressions (described below).
An example control statement is
IF (MouseHorizontal
> TrackWidth)
TrackNamed("buttons").SetEnabled(TRUE)
ENDIF
Declarations
When you are going to use variables in
your scripts, the scope, or 'accessibility' of those variables
must be declared beforehand.
An example variable declaration is
SpriteVars speed
Constants, which are similar, need
not be declared in your scripts, but must be defined in the 'defines'
tab of the main project window.
Comments
Comments are another very useful kind of Qscript which do not
really form part of the language itself. They enable you to put
descriptions into your scripts so that it is easier to understand
what is going on. You may return to the script weeks or even months
later and by then you will almost certainly have forgotten what
the script was doing.
Comments are a good way to describe, in human language, what is
going on. They can also be used to experimentally 'deactivate'
lines of Qscript, so that you can see how the movie behaves without
those lines.
An example comment is
//This is where
the collision detection code starts...
Sometimes it is useful to make a comment which lasts for more
than one line. In this case, you may use the multiline comment
tag which starts like this
/*
and ends
like this..
*/
Note; There is a bug in LiveStage 2 where the auto-colouring of
multi-line comments does not work, but apart from this, multi-line
comments are treated correctly in that version.
| IMPORTANT Even though the LiveStage user interface might suggest otherwise, the FrameLoaded event is not sent to individual sprites, but to the sprite sample which contains them. References to ThisSprite, or relying on the sprite being a default target in a frameloaded handler will fail because the scope of frameloaded handlers is technically outside of the sprite itself. If you want a sprite to refer to itself inside a FrameLoaded handler, use the special target form SpriteOfID($ThisSpriteID) This special target form is designed so that the preprocessor (which maps defined constants in your Qscripts before the compiler gets to work) will compile the target with the actual ID of the sprite instead. Useful Tip This form is a little longwinded to apply rigorously throughout a more complex Frameloaded handler, so a good tip is to call a custom initialisation handler in the sprite itself from the frameloaded handler. This means that you only need to use this special case once for each sprite. Inside the initialisation handler, you can assume that the sprite is the default target for sprite actions and properties, just as you would in any other handler, which makes your scripts quite a bit neater. For example your frameloaded handler can contain only the following line: SpriteOfID($ThisSpriteID).ExecuteEvent($"init") ...and then in the custom event, you can put the sprite's initialisation code without needing to use the special target form again. |
ListReceived
This handler (QuickTime 5 / LiveStage 3 and later only) is executed
when a QTList is received following an asychronous action such
as ExchangeList.
Idle
This handler is executed fairly regularly when the movie is not
'busy' doing something else. The idle 'frequency' is actually
just the minimum amount of time that QuickTime will delay between
sending idle events, and so can not be relied upon for accuracy,
but you can specify a preferred delay in the header of the sprite
track. The default is 1 idle event every 1/60 second, but in practice
it is very rare to achieve this many idle events, particularly
on slower computers. In QuickTime 5 and later, and in LiveStage
Pro 3 and later, it is possible to change this value at runtime
using the 'setIdleDelay' or (deprecated) 'setIdleFrequency' actions.
See also the document Idle Vs. Event
Trigger modifiers.
Custom Events
These handlers are not executed, or even present, unless you create
them by clicking on the 'New Event Handler' button, and arrange
for them to be called explicitly from another handler, or from
an event modifier. You can call a custom event by its ID, or (more
expressively) by giving it a name and using the name when you
call it, like this:
SpriteNamed("AlienController").ExecuteEvent($"StartSwarm")
See also the document Idle Vs. Event
Trigger modifiers.
See also the section Recursion Issues.
Request to Modify Movie
This event was included in earlier versions of LiveStage, but
has since been removed because it does not do anything.
Most operators are familiar mathematical symbols representing
arithmetical operations;
+ Add
Example: 5 + 2 (gives 7)
- Subtract
This can also be used to denote a negative value, which can also
be denoted with the operator NEG
Examples:
5 - 2 (gives 3)
-5 - 2 (gives -7)
/ or ÷ Divide
Either symbol is allowable, but the latter is not standard ASCII,
and (beware!) in some countries, the ÷ symbol is used for
the subtraction operator. If you intend to share your code with
other users, or even just put it in a plain ASCII email (for example
to the LiveStage Talk list) it is wiser to use the forward slash
character (/) instead of the high byte, non-standard ÷.
Note: The result of a division operation may be a floating point number even if the arguments are both integers (whole numbers).
Example: 5 / 2 (gives 2.5)
(See DIV
below).
* Multiply.
The 'cross' symbol (×) is not standard ASCII, and it is
easily confused with the letter X. Similarly, the 'middle dot'
(·), used to signify multiplication in some countries is
easily confused with the stop or point character and again is
a high-byte / non standard character, so the asterisk (*)
is traditionally (and pretty much exclusively) used as the multiplication
operator in programming, and Qscript is no exception.
Example: 5 * 2 (gives 10)
There are several other mathematical operators used in Qscript
which may be less familiar. They certainly have their uses, but
skip over them if they seem obscure at this point. Examples are
given to help you understand them;
DIV
integer divide.
Whereas / or ÷ may result in a floating point number, DIV is division
where the 'remainder' part of the answer is discarded. The result
is always an integer.
Example: 5 DIV 2 (gives 2)
REM
remainder of integer division.
This gives the 'remainder' part of the answer is discarded after
an integer division. The result is always an integer.
Example: 5 REM 2 (gives 1)
ABS
absolute value.
This gives the magnitude of a numerical expression regardless
of whether it is positive or negative.
Examples:
ABS -2 (gives 2)
ABS 2 (gives 2)
Equality and Inequality Operators
There are also some special operators for logical operations,
some of which might seem unusual if you have never used a scripting
or programming language before. Some of these operators are common
in everyday speech however, so they are very easy to understand,
others might be familiar from mathematics.
= is equal
Note. This is not the same use of this symbol as in an assignment
statement. Instead it is used to evaluate a boolean expression,
most commonly in an 'if' or 'while' control statement, for example
IF( livesLeft = 0 )
//Whatever
ENDIF
!= is not equal
Example:
IF( livesLeft != 0 )
//Whatever
ENDIF
< is less than
Example: IF( livesLeft < 0 )
<= is less than or equal to
Example: IF( livesLeft <= 1 )
> is greater than
Example: IF( livesLeft > 0 )
>= is greater than or equal to
Example: IF( livesLeft >= 0 )
Logical operators are also usually used in control statements, so that a particular sequence of instructions may or may not be executed if the logical expression is true.
AND
logical and
This is used to combine two boolean expressions into a single
boolean expression. Both sides of a logical 'and' expression must
be true for the whole expression to be true.
OR
logical or
This is used to combine two boolean expressions into a single
boolean expression. Either side of a logical 'or' expression may
be true for the whole expression to be true.
NOT
logical not
This is used to reverse a boolean expression. True becomes false
and vice versa.
Precedence
Using parentheses to group parts of an expression will influence
the order in which they are evaluated. In the example GoToTime((MaxLoadedTimeInMovie - 600) + x), the expression (MaxLoadedTimeInMovie
- 600) is evaluated before the variable x is added. This kind
of construction can have an enormous influence on the way your
expression is evaluated.
Datatypes
Like most scripting languages, Qscript is 'loosely typed'. This
means that it is not fussy about what type of data you store inside
your variables. Nevertheless, you should ensure that you use the
right type of data in the parameters of your Qscript actions.
The QuickTime wired engine can convert data types when it is necessary
or possible, but can not perform miracles or heuristics.
There are three basic or 'primitive' datatypes.
Integer
Commonly known as 'whole number'. Integers are numerical values
with no fractional parts, such as 4 or -3.
Float
Also known as 'floating point number' or 'real number'. Floats
are numerical values with a fractional part, such as 0.5 or -99.004
Boolean
This is used in logical operations. Boolean expressions must evaluate
to TRUE or FALSE.
(TRUE is identical to the integer literal 1, and FALSE is identical
to the integer literal 0).
In addition there are two more sophisticated types, but if you
have used other scripting or programming languages, you will notice
that support is currently very limited:
String
A string is a sequence of characters, such as a word, a sentence
or a url. Strings are denoted by double quote characters at the
beginning and end. If you need to include the " character
inside a string, use \" in its place and the Qscript preprocessor
will handle it properly. String variables can be created using
the SetString() action, and appended together
using the AppendString() action, which can be very powerful
when working with urls. You can also use string literals in your
scripts without needing to use the SetString()
action.
Array
An array is an indexed series of other values of a fixed size.
Arrays are declared in a similar fashion to other variables, and
can also have different scopes, but the size of the array must
be specified in the declaration:
SpriteVars inputs [10]
Then to access a value in the array, you use arrayName[index]
for example
firstinput = inputs[0]
IMPORTANT
Arrays are zero-indexed. This means that the first item in an
array will always have the index 0. If you want to use conventional
anthropoid finger counting, declare your array to be one bigger
than you intend it to be, so that you can start your index at
1 instead. (This is counter intuitive for many people, but has
some technical advantages apparently).
'Valueless' expressions
Sometimes you will find that a Qscript property has no value,
for example, the number of sprites in a track which does not exist.
In many scripting and programming languages, such values are assigned
a particular datatype, void, null, nil or some such, or even generate
errors. QuickTime has no such datatype, and does not generate
error messages when wired actions are nonsensically organised.
So, you have to be careful when assigning a valueless expression
to a variable which already has a value because that variable
will still contain the value it had before the 'failed' assignment
statement. If the variable had no value in the first place, it
will still have no value afterwards.
Advanced technique using 'valueless' expressions;
This can actually be used to your advantage. For example, if you
wanted to know whether a particular sprite exists or not, you
could assign a variable to a known value, then immediately assign
it to a property of the sprite you are checking the existence
of. If the contents of the variable still contains the old, known
value you can be pretty sure that the sprite does not exist.
It's very important to realise that you can not modify
a constant as you can with a variable. Even so, constants will
usually be faster than variables for QuickTime to handle at runtime
so there is some advantage to using them in every case where you
know that a variable will not change its value at runtime.
By convention, many Macintosh programmers prefix constants with
the letter 'k'. You are not in any way required to follow this
convention, but some people find that it helps. You will notice
that many of the predefined contstants in Qscript are prefixed
with the letter k.
b |
a |
c |
k |
s |
t |
a |
g |
e |