
|
|
|
|
|
|
|
|
|
|
This is written as a quick reference for people who have programmed and have used Lingo a little. It was originally written fro Director 4, however apart from not needing to use 'birth' in 5, the object rules are unaffected. Lingo is not case sensitive.
These are very useful. As in any other programming language, the computer completely ignores all comments, which are used to make notes to yourself and others what is going on. In Lingo a comment starts with a -- and is active until the end of the line.
Need not be defined before they are used. The usual sort of identifier conventions (start with a character, not a number) apply. Lingo appears to allow spaces in symbol names, though I would suggest that you do not put spaces in variable names. Use set or put to create a variable.
set something = something_else
put something_else into something
To view the contents of a variable at any time, type
put something
which will put the something into the message window. The put something may be part of a script, or may be typed into the message window.
Because there is no need to declare variables in advance, you will find that odd things happen if you mis-spell a symbol name, e.g.
set fred = fref + 1
which was supposed to increment the contents of "fred" by 1, will either produce an error or (probably) assume that "fref", being non-existent, has a value of zero.
There are various types of variable, but there is no need to tell Lingo what type a variable is. Strings are enclosed in double quotes, numbers are not.
set fred = 20.3
set fred = "Dis am de string"
Variables are local to a handler, unless you make them global, as in
global fred
Global variables can be seen in any handler in any script, but you should use the global keyword in any handler where you need to access a global variable.
Global variables are useful for holding values which will affect all your scripts.
Property values (of objects) are local to that object, i.e. they can be seen in any handler within the object's (cast) script. They cannot be seen outside the object's cast script.
Many people tend to prefix global variables with a "g" and properties with a "p", so that it is obvious that they are global or properties. I fear that I don't....
The "the" keyword can be used to set/inspect the properties of objects from outside the object's parent script.
put the stageRight --displays stage right in the message window.
the general format is put the property of the instance_of_the_object
Message handlers process either a system generated event (such as mouseUp), or an event which you create. They are defined as follows
on someEvent A, B, C, D ....
..
.. (program code)
..
end
A, B, C etc. are "formal parameters", which you don't need to include, but which are a useful way of passing data to your handler. You can invoke this handler, if it is not for a system event, by
someEvent(1, 2, 3, 4)
The (1, 2, 3, 4) are termed "actual parameters", and will be copied into your script's formal parameters, i.e. A becomes 1, B becomes 2 etc. It is the position of the parameters which determines what is copied into where, and you should ensure, of course, that the number of actual and formal parameters are the same. Lingo will not (unlike many other languages) do this for you, and tends to be very bad at telling you that you have done something silly. It tends to sulk and do nothing...!
Function handlers are very similar to message handlers, except that they return a (one only) value as well. You define them as
on someOtherEvent A, B, C, D ....
..
.. (program code)
.. calculate something
return something
end
The something is returned by the handler, so you must tell it where you want it to put the returned value to be stored
set fred = someOtherEvent(1, 2, 3, 4)
if ... then ... else
There are various permutations; see the on line help system.
Repetition
Repeat with
repeat with counter = start to finish
..program code
..
end repeat
This construct us useful if you know exactly how many times you want an action performed. See the help system for examples.
Repeat while
repeat while testCondition
..
..program code
end repeat
This construct us useful if you do not know exactly how many times you want an action performed, but the action must be repeatedly performed while some condition holds true. See the help system for examples.
exit and exit repeat can be used to force Lingo to exit either sort of repeat loop.
All an object is, is a collection of data (properties) and program code (handlers, but these are termed methods on object oriented jargon - remember Smalltalk?). As you can create as many instances of the same object as you like, you must pass a parameter to each handler saying which instance of the object you are referring to. You create an object with a birth script. A primitive object might look like as below.
You must tell the object what it is on birth (the me parameter), and where you have placed it in the score (the birthSpriteNum parameter).
property X, Y, spriteNum
on birth me, birthSpriteNum, birthX, birthY --Give birth to me
set X = birthX --at birthX, birthY.
set Y = birthY
return me
end
on nextFrame me --compute where to go on next frame - a
set X = X + 20 --Nigel generated event.
set Y = Y + 20
set the puppet of sprite spriteNum = true
set the locH of sprite spritenum = X --I believe you know
set the locV of sprite spriteNum = Y --about puppet
set the puppet of sprite spriteNum = false --sprites.
end
You can see from the "the" keywords that puppet, locH, locV are all "built in" properties of a sprite. You can use read all and alter most of these properties.
See some separate examples which actually give birth to objects...
Sprites and Cast Members are Objects
Sprites and cast members have a list of properties, many of which you can read or change from various check boxes. You can also use the "the" keyword in conjunction with set or put to read and set most of a sprite or cast member's properties, such as:
set the locH of sprite 3 = 300
the .... of sprite .... You can use set or put to read or alter a property.
Sprite properties are below; I have put comments against the properties I use. T/F indicates that the value of the property is true or false only.
backColor
blend
castNum Number of the cast member displayed as your sprite.
editableText T/F
foreColor
height
ink Determines how your sprite is drawn.
lineSize
locH Location horizintal on the stage.
locV Location vertical on the stage.
moveableSprite T/F. True if your sprite is moveable
puppet T/F. If true your sprite is a "puppet sprite" controlled by a script.
scriptNum Script number for the sprite. Can't be set.
stretch
type
trails T/F. T leaves a snail trail.
width
the ... of cast ... Properties are:
backColour
depth Colour depth of cast member, e.g. 256 colours.
foreColour
hilite T/F. Highlights some types of cast member, e.g. Radio Button.
modified T/F
name
number Cannot be set.
pallette
picture
preload
scriptText The text of the script, if any, assigned to the cast member. The scriptText of cast property can be tested and set.
These are two built in functions, sprite ... intersects and sprite ... within.
sprite ... intersects ...
compares the position of two sprites, and returns true of false. See the help system for how the boundary of a sprite is defined.
sprite ... within ...
compares the position of two sprites. It returns true if the bounding rectangle of the first sprite is entirely inside the bounding rectangle of the second, otherwise it returns false. See the help system for how the bounding rectangle of a sprite is defined.
Lists are extremely useful data structures for creating objects dynamically, i.e. as your movie is playing. You can add as many objects to a list as there is memory for them. If you look in the help system you will find that there are several types of list, the simplest being a linear list.
set thisList = [1, 2, 3, 4] Creates a list.
set thisList = [] Creates an empty list.
add thisList, thisThing Adds thisThing to the end of the list thisList.
count(thisList) Returns the number of items in the list thisList.
deleteAT(thisList, number) Removes the item numbered number from thisList.
getAt(thisList, position) Returns the item in the position position in the list thisList.
getPos(ThisList , value) Returns the position of the value specified by value in the list specified by thisList. When the specified value is not in the list, the getPos command returns 0. For values in the list more than once, only the first occurrence is returned.
setAt List, Position, Item Inserts the item into the list at position.
Note: Some of these keywords seem to need brackets, some do not. I think I have the brackets correct here, and if you don't use them correctly odd things happen!! A powerful way to process an entire list is to use the repeat with construct
repeat with variable in someList
..
.. (program code)
end repeat
This keyword assigns successive values from the specified list to the variable. You will a handler in one of my examples which moves all objects (which could be many) by simply:
on exitFrame
global animalList
repeat with animal in animalList
nextFrame(animal)
end repeat
end
This applies more to "drag and drop" sprites. The position of a sprite can be constrained by using a sprite's constraint property.
set the constraint of sprite spriteToBeContained to containingSprite
When the constraint of sprite property is turned on, the sprite specified by spriteToBeContained is constrained to the bounding rectangle of another sprite.
The constraint of sprite property affects moveable sprites, and the locH and locV sprite properties. The constraint point of a moveable sprite cannot be moved outside the bounding rectangle of the constraining sprite.
To remove a constraint of sprite property, set it to 0:
Getting the Frame Tempo
the frameTempo will get this (but you cannot set it within a script), and you can use it to set the timeStep variable in most of my examples.
set the timeStep = 1.0/the frameTempo
Beware that if you do not use 1.0, then Lingo will assume that you are using integer arithmetic and return a result of Zero!!
One powerful feature of this type of programming is that you can create child objects which inherit all the characteristics of their ancestors, except for characteristics you wish to change or add.
To create a child object, you must create a property ancestor, and set the ancestor to the birth script of your ancestor object, like this:
property ancestor --A special property, the ancestor object.
--**** The birth script. As the sprite channel number is passsed ****
--**** as a parameter to this object, we must pass it to the birth ****
--**** script of our ancestor as well. Clear as mud? ****
on birth me, birthSpriteNum
set ancestor = birth(script "animalObject", birthSpriteNum)
set the speed of me = 80
set the castNum of sprite (the spriteNum of me) = cast "predatorCast"
return me
end
Our child object has inherited everything from its parent, except for the things which have been changed.
The rules of scope appear to change now. If the ancestor object has properties such as X and Y, you must refer to these properties specifically as the X of me or the X of ancestor. Either seems to be acceptable.
Your child object inherits all the properties and handlers of its ancestor.
If you create a method (handler) with the same name as one in the parent object, your child's new method overrides the parent one.
If you create a method with a name not used in the parent, then you have created a method which is only understood by your child object. There follows an example:....
Animals example ("herbpred.dir")
Below is the family tree of my objects, with their properties and methods (handlers). See the program itself for a more detailed explanation of what each method does.

You can see that "herbivoreObject" inherits everything from "animalObject", and therefore is effectively "animalObject". "ManicAnimalObject" differs from "animalObject" in that its speed and heading are calculated by a different method. "PredatorObject" is the object which differs the most from its parent. It has its own "calcNewHeading" and "calcNewSpeed", and it also has a new method "killAnimal". This object can kill! If you are into violence, then a thought would be to cut and paste this method into the parent "animalObject". All these animals would then inherit the ability to kill.....
Three function handlers which you might want to cut and paste for yourself:
findFirstFreeSprite() Returns the first available sprite (score) position.
calcDistance(X1, Y1, X2, Y2) Returns the distance between the positions X1, Y1 and X2, Y2.
calcBearing(X1, Y1, X2, Y2) Returns the bearing of the position at X2, Y2 from the position X1, Y1.
The example is based on a global list of animals, "animalList", which starts as an empty list. Animals are added to the list as they are created. Animals are inserted in the next available score position, as found by findFirstFreeSprite. This handler looks for the first sprite with a castNum of zero. Dead (eaten by predators) animals are removed from this list as they are eaten. The castNum of the sprite a dead animal occupued is set to zero, marking that position as vacant.
AnimalObject
Î Travels in a straight line (defined by its "speed" and "heading" properties until is wanders near the edge of the stage.
Î It then always alters course by +0.2 radians, until it has wandered away from the side of the stage. This is a pretty crude rule, try to think of something better.
HerbivoreObject
inherits everything from "animalObject", and is therefore identical.
ManicAnimalObject
Inherits everything from "animalObject" except:
Î It calculates its speed and heading differently. Approximately every 3 frames in 10 it changes its speed and heading to random values.
Î It retains the "off the stage" rule from its parent.
PredatorObject
inherits everything from the parent "animalObject" except:
Î It calculates its heading finding the nearest animal and sets its heading to the bearing of the nearest animal. i.e. it chases the closest animal.
Î It may be borne hungry, or not hungry.
Î If it is hungry it will eat any animal it intersects, and:
Î It removes the eaten animal from "animalList".
Î It increases its size.
Î It moves fster
Î It becomes not hungey
Î If a predator hasn't eaten for 10 seconds, it becomes hungry.
You will see that odd things can happen as animals are eaten (removed from "animalList"). I strongly suspect that this is because I do not update the score (remove dead animals, change the "spriteNum" property of the surviving ones accordingly). I have created a global "deadAnimalList" for this purpose, but I do nothing with it at present.....
"Herbpred.dir" Bug fixed!
Simple solutions are often the best. There is now no need for a list of dead animals.
Î As before, the example is based on a global list of animals, "animalList", which starts as an empty list. Animals are added to the list as they are created.
Î Animals are inserted in the next available score position, as found by findFirstFreeSprite. This handler looks for the first sprite with a castNum of zero.
Î Dead (eaten by predators) animals are removed from "animalList" as they are eaten.
Î The castNum of the sprite a dead animal occupued is set to zero, marking that position as vacant.
