This section goes over how common programming concepts are implemented in the tile scripting system. Article references to viewer categories are in bold text and scripting tile properties and methods are enclosed in quotation marks. For more detail on Etoys objects and the scripting system please refer the Etoys manual.
Variables are added to the viewer's variable category by left clicking on the light brown icon with the down arrow on the viewer's top menu bar. The types available on the pop up list are dependent on the class of object or what main preferences have been set but there is a basic set always available. Etoys does do explicit type checking. You can replace
tiles inside scripts with variable name tiles. A green highlight appears around the receiving tile if the types match.
Some Variable Types
Variable names are alphanumeric only. I've gotten in the habit of using lowercase and capitalizing the first letter of any additional words when naming variables, scripts, objects etc. Etoys will append a number to any reserved words used in a name. Variables can be removed or modified using the options menu on the left. Be sure to remove them from any scripts before doing so. Variables can be assigned values in the viewer, in a watcher or in an assignment statement inside a script and they may be passed as parameters to other scripts.
Numbers can have up to 10 decimal points. The value display will round up if assigned to a number with more decimal points than currently set. This is something to be mindful of when doing comparisons. The round function from the script editor menu will round numbers to the closest integer. Large numbers are displayed in scientific notation. Inside scripts, number variable types can be increased, decreased or multiplied by a value or assigned a value, the result of an expression or another variable. Tiles inside expressions can be replaced with number type tiles.
The Point type is a bit specialized. Points describe an x and y location and are assigned in the form 0@0. They can be increased, decreased and multiplied by another point value but cannot be used in expressions and can only be compared for equality.
The String type can be assigned alphanumeric characters from the keyboard or character strings inside other objects. Strings are immutable meaning that strings cannot be altered through expressions and are replaced completely when reassigned. They can only be compared for equality. However some objects have methods for manipulating strings. See Objects that Contain Collections for more information.
The Player type can be assigned objects in your project. Etoys documentation often refers to objects, morphs and players. All are object classes and there are distinctions between them but for the user, player is the most relevant term to scripting. When you create a player type variable you'll see a black dot inside the value display. A little black dot does exist hidden up in the top left hand corner of the main menu bar. This dot is the default value for player variables. Any tile containing the word dot can be replaced with an object reference tile. Inside the viewer you can assign a value by clicking on the image in the value tile and selecting an object on screen with the cross hair. Or drag the variable tile out by the assignment symbol and drop. The value tile now says dot. Right click on the desired object and click the orange rectangle halo icon to get a reference tile and replace dot with it. That object's properties, methods, scripts and variables can now be accessed using the variable. This is a very powerful feature better demonstrated than explained. See Dynamically Creating Sibling Objects for an example.
Color variables display the current color of the object and must be assigned with the color picker. They can only be compared for equality. To manipulate object colors use numeric properties in the color category instead.
The graphics type is useful for Sketch objects and can be used to change costumes for animation. Assign inside scripts by clicking on the image value and selecting an object on the screen or assign a pen trail graphic from the world or a Playfield object to a Sketch's graphic property.
Other variable types are assigned through drop down lists and can only be compared for equality. Boolean types are either true or false. ScriptName variables can be used to replace values in tiles from the scripting category.
Any variable type can be passed to another script as a parameter but scripts can accept only one parameter. It's name in the script is it's type so make sure you select the correct type in the script editor menu. Clicking the parameter name in the script editor menu gives you tiles that you can use in your statement tiles. This is the one serious limitation in the tile scripting system. If you are really determined to have multiple parameters you can pass a holder containing the values you want and fetch them out of it but this won't usually work well if you're using recursion to send a parameter in an expression.
Remember when I was going on about how all the objects in your project are instances of objects inside an instance of a world object? That means that all objects are local to the world object. Variables can be modified by scripts belonging to any object including the world object. That doesn't mean however you shouldn't think about scope. Even though you can define variables anywhere you like, scripts and variables you intend to share with sibling objects must be defined inside siblings. I try to define variables all objects might use inside the world object (global scope) and define others in relevant objects (local scope). If you intend to define a constant value, it might be good to remind yourself by prefacing the name with const such as constVariableName. It does make it a little more difficult to explain the concept of scope to a novice because it takes discipline to practice. Discipline I often lack.
Any variable can be displayed on screen in a watcher tile.
All objects can display speech and thought bubbles and the bubbles can be assigned string and numeric variables through statement tiles.
Text objects can accept string and numeric values and are very useful for building formatted forms and interfaces. Right click on a Text object and you'll see font and style options. Although strings are made up of keyboard character values, Text objects will attempt to convert consecutive numeric characters to a number type. When you look at the basic category for a Text object, you will see a tile for text "characters" and a tile for the "numeric value". The "numeric value" defaults to zero if the text string contains no numeric characters. Type in 123 and the result is the number 123. Type a12b and the result is 12. A12b3 still results in a numeric value of 12. To sum up, Text objects can treat numbers as character string types or number types.
Etoys does not have a list or array type. However several objects contain collections that behave similiarly to arrays. Holder objects accept a collection of any type of object, arranges them in a row and displays a rectangular cursor surrounding the currently selected object on screen. The cursor can be moved using script tiles.
To create a number array, you need to create a text object to hold each number. This can be done using a script but for this example just get a text object and a holder out of the supplies flap and drop the text object inside the holder using the black embed halo icon. Next right click the text object, select the options menu, siblings..., make multiple siblings then type in the number of objects you need. The holder is now full of text objects and the holder's cursor should be on its first element. Click on the individual text objects and type in the desired numbers.
Open the viewer for the Holder, select the collections category and you'll see some tiles relating to the object collection. One tile displays the numeric value of the object at the cursor. You can move the cursor by clicking on the up/down arrows in the Holder's "cursor" tile and view the values for every element. The cursor will wrap to the beginning element when you go past the last element. This is very important to remember when moving the cursor inside scripts. There are tiles for adding elements or removing all of them. If you need to remove one element through a script all objects know how to erase themselves and the holder will adjust automatically if one leaves.
Now you can write scripts to manipulate the numbers in the collection. The Holder "count" property is useful for setting up loops to move the cursor through the collection and access each value. You can write scripts to sort them, assign them to variables or other objects, add themselves together etc. There is a tile that will call a script inside every object. This is where siblings come in handy because they share scripts and variables so you could create for example a mapping function where they all increase themselves by a value.
Holders can contain other Holders so technically you can create multidimensional or associative arrays but that involves manipulating multiple cursors and could be more trouble than its worth depending on how badly you want to do it. For more on collections see Objects that Contain Collections.
Holders can have objects added to them using script tiles in the collections category. The process of creating sibling objects and assigning values to them is described in the article Dynamically Creating Sibling Objects. To create a numerical array using scripts add a Text object and a Holder object, create sibling copies of the Text object, assign a number to each sibling's numeric value and add a scripting tile from the Holder's viewer collections category to add or insert the sibling Text objects. This can be done inside a loop or on the fly as needed. An example project numberArrayMorph.040.pr can be downloaded from my GitHub repository, saved to your Etoys directory and loaded into Etoys. This project demonstrates user input forms and dynamic number array creation.
Rather than an if..then type construction, Etoys has a "test" tile found in the tests viewer category and in the Script Editor gold box. I am ok with this because it does have clarity. Is this true?..yes or no. Drag a variable or property name tile (not the assignment symbol) onto the test section of the tile. Cycle the up/down arrows or left click to select available comparison operators. Most types except number and boolean can only be compared for equality. The comparison value display box will accept variables and property names for all types and expressions for number types. Compared values must match type. Drag statement tiles into the yes and/or no branches that will run depending on the result of the comparison.
There are no boolean operators logical AND, logical OR or logical NOT. Logical constructs are built using nested "test" tiles.
Switch statements are just a matter of piling "test" tiles on top of each other with a default action stuck in the No branch of the last "test" tile. If you wish to use Boolean operators you can convert the script to text using the Script Editor menu options and type them in. The Terse Guide to Squeak is very helpful.
The "repeat" tile is the only other control tile available for scripting. It can be found in the miscellaneous viewer category or by clicking on the gold box icon in the Script Editor menu bar. The value box accepts number types only and will accept variables and expressions. It will run the statements inside the do section the specified number of times.
This brings me to one of the key things to understand about scripting. Scripts run on a unit called a tick. I'm not sure how exactly that's defined but it doesn't matter, more importantly when a script is run each and every statement tile is processed and executed in one tick. A tick cannot be interrupted or paused. Test branches and repeat loops are followed but are processed in one tick like any other statement. Any statement tile following a "test" or "repeat" tile is processed. No matter how many statements are stuffed in, it all happens in one tick.
This makes "repeat" tiles fine if you just need a result and can calculate the repeat value ahead of time but if you want a conditional loop or need to watch a gradually changing condition they won't do. The Etoys manual explicitly explains these things in the scripting category section but of course I didn't read the manual right away and because the "repeat" tile was the only other obvious control tile I could see, I persisted in trying to make it do what I wanted.
It turns out that Script Editors themselves are quite versatile. When set to ticking status they run continuously and multiple scripts can tick at the same time. The tick rate control sets how many times per second the script will run. It has nothing to do with how long a tick is. This makes ticking scripts useful as timers, script event listeners and handlers or animation controllers. Here's a link for a discussion on timers. Or you can dowload project simpleTimer.004.pr from my GitHub repository. Save it to your Etoys directory and load it in Etoys.
There are two methods for creating conditional loops and you guessed it one involves ticking scripts. The scripting category contains tiles to start, stop and pause ticking scripts. It is important to understand that these tiles are like any other and are executed along with any other statement tile in the script so they cannot be used to interrupt the current tick. However, they will affect the target script in the next tick.
You will need to set up a stopping condition and put the "pause" or "stop" script tile in a branch inside a "test" tile. Creating a variable for a counter is the simplest way to do this. Initialize the variable to a starting value in the script that calls the ticking loop script. Add a "start script" tile to tell the loop script to start ticking. Add a "test" tile to the loop script and set it to test for a value. For example, to run the loop 10 times, start the counter variable at 0 in the calling script, set test to variable = 10, put the "stop script" tile in the Yes branch and put a variable "increase by" 1 tile in the No branch. Set the "stop script" tile to act on the loop script containing it. The tick rate defaults at 8 ticks per second but you can set it slower or faster if you like. Remember that even if the test condition is met (variable = 10) any other statement tile in the Yes branch or any statement tiles following the "test" tile will still be acted on once. On the next tick, the loop script will get the message to stop, reset the Script Editor's status to normal and do nothing further until called again. If you need a new script to run put a "script", "do script"or "start script" tile in the Yes branch.
Creating loops this way can be a little slow. The tick rate is set through the clock icon on the Script Editor menu. Although you can set a custom tick rate, the maximum seems to be 100 per second. If you are rotating an object 360 degrees at 1 degree per tick it will look slow even at maximum so you may have to optimize your animation logic to get the results you want. Rotating 10 degrees per tick instead of 1 will only loop 36 times and speed up the animation. You'll need to find a balance between speed and smoothness. If you want to control ticking scripts using the AllScripts tool, scripts should be set to paused status not stopped (normal).
For fast conditional loops, we need to turn to recursion. A recursive script contains a tile that calls itself so a stopping condition is necessary or the script will call itself indefinitely. Unlike a ticking script, recursive scripts continue to act in one tick and if they don't stop your Etoys image may lock up eventually. See How Do I Stop This Endless Loop or Other Rampaging Scripts? You can set up your recursive loop in a similar way as the ticking loop with a counting variable initialized in the calling script and a tile to call the loop script. Set up the "test" tile in the looping script the same way but in the No branch add a "script" tile for the looping script itself. Make sure this is added after the variable "increase by" tile or you will never reach the stopping condition. Either leave the Yes branch blank or add a tile to call or start a new script. Always save your project and double check to make sure that your statement tiles are in the correct order and the stopping condition you have set can be met before running recursive scripts.
Recursion is the only way to create a conditional loop with a script using a parameter. Check Creating a Linked List with Sibling Objects for an example of using a parameter and a recursive loop. Etoys scripts can only have one parameter set at a time. If you have a need for multiple parameters, you can pass a holder of objects and fetch values from them but this usually won't work well with recursion if you need to pass the parameter value in an expression. Lenny Pitt has shared two projects that demonstrate passing a parameter expression recursively at Etoys Illinois.
There are other methods of creating timers and event handlers. Playfield objects such as the World object have a "timer" tile inside the viewer Playfield category. This can be set to 0 but you will still need a ticking script to continually test the timer's value.
Etoys objects can respond to user created events. This feature may or may not be set in preferences but can be set if it's not available in your image. This is mostly useful to create events that affect a number of objects. An event can be created in any Script Editor. Left click on the status box in the Script Editor menu bar, select more and you will see an option to create a new event. You will be prompted to give your event a name and a description. All objects you would like to respond to this event require a script that sets up the object's actions in response to the event and the Script Editor Status must be set to the name of the event. A script containing the tile "trigger custom event" can be created inside any object. When this script is run, any script set to the custom event status will run from each containing object.
So in Etoys we learn to manage program flow with "script" and "scripting" tiles from the scripts and scripting category and manage state through Script Editor status. It takes some care to think through a solution. To sum up it all up, by default scripts have normal status and will run once when called by a script with a "script" tile from the scripts category. Tiles from the scripting category are used to start, pause and stop ticking status. When a script encounters a "pause script" or "stop script" tile it will continue processing statements until the end of the script and the script's status will be set to paused or normal on the following tick. Multiple scripts can have ticking status and run simultaneously. Scripts can also be set to respond to events.
There are three main types of collections (poor choice of word here not to be confused with variable types) and there are multiple objects that contain them.
Text
Several objects can be used to enter and display text but not all have a text category. The Text, Enhanced Text and Title objects do. Open a viewer on a Text object and you'll see text in the category list. This provides tiles for manipulating strings. Each character is an element in the collection. The numeric value is a conversion of any consecutive numeric characters into a number and is of a number type not string. In other words you cannot assign string variable value 123 to the Text object's numeric value. Any assignments must match type. Text object "cursor" and Text object "count" are also number types. The cursor can be moved to individual characters and Text "count" can be used in loop creation. All other properties are of type string and string variables can be inserted or appended. To remove characters you can assign a replacement string to an appropriate property. Formatting text has to be done manually through the object's halo options.
Playfield
The World, Playfield, Holder, Graph Paper, and X-Y Plane objects can contain any kind of object but they have individual options set that make them useful for different purposes such as the Holder for creating arrays. They have their own co-ordinate systems outside of the world object's and are very useful for assembling other objects. Playfields have a collections category and a playfield category. A cursor can be moved through elements like any other collection. Other than the "count", "cursor", "numeric value at cursor" and "string contents", values are of the player type. If you click on the menu icon to the left of the object's "player at cursor" property you'll see an option called tiles to get. This brings up a list of properties from the individual object at the cursor. Not everything from the list is available for every object but you can usually get number, string, color or player tiles from it. This means that you can directly manipulate objects inside collections from playfield type objects. You can also get an assignment tile out of the viewer of the object at the cursor and replace the identifier tile with the "player at cursor tile". This is great for looping through collections and setting or getting values for variables and properties in each object.
Books are special cases that contain pages. Pages themselves are a type of playfield that can contain any object. Books are rather like small presentation applications and have a number of features. I won't go into too much detail here because they are too much fun to explore on their own.
Polygon
Polygons are collections of vertices. Like points vertices have an x and y location but unlike the point type their location cannot be expressed as a point 0@0. Polygon, Curve, Triangle, Line, Arrow and Curvy Arrow all have polygon categories. Don't confuse Line, Arrow and Curvy Arrow with objects in the Connectors category from the catalogue. Connectors are intended for diagramming and have unique features. Hold the shift key down and left click on Polygon objects to see handles. Move an individual vertex around with the mouse or add vertices by clicking on the small green triangles and remove them by dragging a vertex over the next closest one. Vertices can only be added to Triangle and Arrow objects with scripting tiles and the Triangle object displays handles by default.
When handles are showing you'll notice that one vertex is blue. Open the viewer, select the polygon category and you'll see the cursor is located at the blue one. Move the cursor and the next vertex becomes blue. You can also see the X and Y value for each vertex. Fun thing to do. Run "shuffle" vertices with a closed polygon. The rest of the tiles are concerned with adding and removing vertices or setting options. I am certain you can do some pretty crazy math related things with these objects but I have done very little experimenting with them so far.
Notes on all Types of Collections
The cursor always wraps around to the first element if it gets moved past the last element so consider this when designing loops. Make sure decimal point settings match up in object values, variable values and numeric collection values or difficult to detect errors can occur. Forgetting to replace tiles everywhere needed can also cause puzzling errors.
An object's icon halo gives you the option to duplicate the object or make a sibling copy. Although duplicates are an exact copy of the original at the time, they are separate object instances. Changing the original has no further effect. Sibling copies on the other hand share variables and scripts. Add a variable or script in one and they all update. Siblings can have individual values set for properties and user created variables but they all have identical versions of scripts including script status and tick rate. Scripts can be called on to run in specific siblings or all of them. Both duplicates and siblings share the same name as the original with numbers appended in order of creation and can be renamed if you like. Copies created through scripting are always siblings which means you wind up working with siblings a lot. This is a powerful feature of the scripting system and it pays to understand how they work.
For this example I'm going to create copies of a Star object. Scripts and variables are created using the viewer for the original Star object.
Steps
Create Original Object:
Drag out a Star object from the Supplies Flap and right click on it. By default it's rather small so resize it holding down the shift key to preserve it's aspect ratio. Open it's viewer with the blue eye icon.
Create Reset Scripts:
Whenever I work with sibling copies, I like to set up a couple of scripts to remove them and start over if I need too. Believe me this saves a lot of grief.
Drag out an "empty script" tile from the scripts category and name it reset.
Get another "empty script" and call it delete.
Go to the miscellaneous category, drag out the "Star erase" tile and drop it in the delete script.
Now select the scripting category. Drag the "Star tell all siblings" tile to the reset script and select delete in the drop down box. Whenever the reset script is run all the siblings will run their delete script and remove themselves leaving the original. They will not go to the trash but will be gone forever. Objects only go to the trash when manually deleted with the halo icon so beware any tile or menu option that says erase or destroy. Be careful not to confuse the "tell all siblings" tile with the "send to all" tile because "send to all" will remove the original as well. After checking my scripts have the correct tiles, I usually send delete back to the viewer so I don't accidentally run it.
Create copy spawn scripts:
Inside Star's viewer we need to create a new player type variable. Click the light brown down arrow icon on the very top bar of the viewer. I am going to call it newStar. Remember to select type player. If you forget you can change it by clicking on the menu icon to the left of the variable in the variables category. This variable will hold a reference to the last copy created. The default value is the Dot object. Next drag the "newStar" variable out by the assignment symbol from the variables categorry and name the resulting new script. I'll call it spawn.
Now select the miscellaneous category and drag out the "Star's copy" tile and replace the variable value tile with it. The tile should read "Star's newStar <- Star's copy".
That's all there is to making sibling copies. Every time we run the spawn script a new star is created. Because they are copies of Star, they are all the same color and pile up on top of each other. They'll be easier to distinguish if we make them different colors and spread them out in a row.
Set the copy's unique values:
Get an "empty script" tile and call it randColor.
Go to the color category in Star's viewer, drag out the "red", "green" and "blue" tiles by the assignment icon and drop them on the randColor script.
Open the gold box on the script editor menu and you will see a tile for creating random numbers in a range from 1 to value. The default is 5. Replace the value tiles in all the statement tiles with the "random number" tile and set each one to 100. This will set the rgb values to a random number between 1 and 100 and combine to form a new random color.
Go to the script category and drag the "randColor" script tile to the spawn script. We want this script to run in the new Star not the original. When the spawn script runs player variable newStar is assigned the copy. So drag the variable name tile "Star's newStar" to the script and replace the tile "Star's" with it. Now the statement should read "Star's newStar randColor". The script will run in whatever player object is assigned to the newStar variable.
Now we want to move the copy to the right along the x-axis. 140 pixels should be enough. Each copy we make will be set to Star's values so we will need to increment the x location by 140 every time we make a copy or the stars will start to pile up on each other again. Make a new number variable in the Star viewer called xIncr and set it to 140.
We are going to want to reset that every time we start over so drag it by the assignment symbol over to the reset script.
Next go the basic category and drag out "Star's x" tile by the assignment symbol and drop it on the spawn script. Click on the "x" or the arrows to the left of it and select increase by. Replace the current "x" value with the "xIncr" variable tile. Replace "Star's" with the "newStar" variable tile so only the copy's x value increases by the value in xIncr. The statement should now read "Star's newStar x increase by xIncr". Now grab the "xIncr" statement by the assignment symbol, drop it in the spawn script and set it to increase by 140. It should now read "Star's xIncr increase by 140". Now each time the spawn script is run, a new star should appear 140 pixels to the right of the last one and should have a different color.
Run the script once and open Star's viewer. An image of the copy should be visible in the newStar variables value. xIncr should now be set to 280. Right click on the new star. It should be named Star1. Open it's viewer and you'll notice that the newStar variable and the xIncr variable are set to whatever Star's values were when it was copied. Drag out the "randColor" script and look at the statements. They all now automatically belong to Star1. So when the spawn script ran Star1 was first created and then assigned to variable newStar. The statements in the rest of the script are translated to "Star1 randColor" etc. Create another star and you should see the new copy in Star's newStar variable. Open the viewer for the new Star and look at it's values. When you run out of room for more stars you can run reset and start over and perhaps figure out how to start a new row in the spawn script. On a side note, you'll notice a star category added to Star's viewer. Playing with the options there changes the Star object in interesting ways.
There is one tricky thing to know about assigning values to player type variables inside objects and making copies. If you create a player type variable in the original object and assign the player object itself to the variable, the copy will automatically assign itself to the same variable. If you need the value for the variable to stay constant, that is not the behaviour you want. In that case, define and assign the variable outside of the object in the World object. That way you only need to assign it once. I'll go through that in the next post Creating a Linked List with Sibling Objects which is one example of what can be achieved with sibling objects.
Linked lists are just one of the many things siblings are useful for. In it's most basic form a linked list is a collection of items that each contain a reference to the next item. Linked lists are used in many familiar data constructions.
Collections allow for dynamically adding, inserting and removing objects but linked lists are an efficient way of tracking similar objects that are spawned randomly across the screen. To illustrate this we'll modify the Star copying project from Dynamically Creating Sibling Objects. To do this save the Star copying project under a different name. Now use the reset script to clear the sibling Star copies and start over.
Steps
This time we'll get the world object to track the first and last star created. Right click on the world Object and click on the blue eye icon. We need to create two new player type variables. Variables are created by clicking the light brown down arrow on the top bar of the viewer. Name the variables firstStar and lastStar. If you forget to set them to player type or name them, modify them using the menu icons on the left side of the variables category.
We only have one star available so click on the value boxes in the viewer and select the Star object with the cross hair for both variables. The firstStar variable must be created in an object other than Star to prevent the copies from updating it with their own value. We want the firstStar variable to remain constant.
Star reset script
Now drag the "world's firstStar" and the "world's lastStar variables' to the reset script by the assignment icon just to ensure these variables are properly set whenever we delete copies and start over.
We need one more player type variable in the Star object to store a reference to the next star. References in linked lists are usually called nodes so we can call it nextNode. Now somewhere in our scripts we need to assign an object to it that hasn't been created yet.
This where the world variable lastStar comes in. Get out a new script from the World object viewer and call it makeStars.
Drag out the Star's spawn script tile from Star's viewer and drop it in the new script.
world makeStars script
Now replace Star's with the tile for the lastStar variable. This means whenever makeStars is run the spawn script belonging to the player assigned to lastStar will run.
Star spawn script
We now have to make some changes in the Star's spawn script. If each copy is spawning the next copy we no longer need the increment variable to set the x axis location. Remove the tile that increases the xIncr variable.
Get a number tile out of the gold box, replace the xIncr variable tile with it and set it to 140.
Star spawn script
Now open the World viewer and drag the lastStar variable tile out by the assignment symbol. Replace the value with the newStar variable tile from the Star viewer.
Drag out the nextNode variable and assign variable newStar to it too.
Everytime makeStars runs, the spawn script runs in the object that the lastStar variable is assigned to. A copy is assigned to the newStar variable in that object, the copy gets a random color, gets moved 140 pixels right along the x-axis and then the copy is assigned to the lastStar and the nextNode variables in the object represented by lastStar. Make few stars and look at the values in the viewers for the World and the stars. firstStar's value should still be the original star because it was assigned once in the World object and not in any of the sibling stars. lastStar's value should be the last star in the row. Each Star object should show the next copy in the list as the value for nextNode unless it's the last star.
Count the Stars
If everything has worked out with our scripts we should now be able to work with our linked Star objects. Counting them is the simplest to illustrate.
Open the World viewer and create a number type variable called sCount (count is reserved for collections).
world startCount script
Drag out sCount by the assignment icon and set it to 1. Call the resulting script startCount.
We are going to use recursion for this. This means we'll use a script that calls itself somewhere in the script.
Get out another script, name it countStars, open the script editor menu options icon and select add a parameter. Use the up/down arrows to the left of the parameter to set it to type player.
world countStars
If we make sure that the nextNode variable in the last star is set to dot we can use dot to test if the script has reached the last star. Drop a test tile on the countStars script.In the test section, drop the nextNode variable tile from the Star's viewer. Click on the parameter and there should be a player tile stuck to the mouse cursor. Replace the star name tile with the player tile. The statement should read "Test player nextNode = dot".
Star reset script
Drag another "nextNode" variable tile by the assignment symbol to the reset script. Drag out the "world's lastStar" variable tile from the world viewer and replace "Star" with it. Go to the Supplies flap and drag out the Players Tool. The Players Tool displays all the player objects in the world. Click on the menu icon on the left of the dot object and select tile for this object. Drop the "dot" tile on the value on the right of the "lastStar nextNode" assignment statement. This way we can be sure that the last star's nextNode variable will be set to dot and the recursive loop will be able to meet it's stopping condition.
world countStars script
Now go back to the world countStars:dot script. Leave the yes branch blank because if that is true we can stop counting as there are no more Star objects.
Get the sCount variable from the World viewer by the assignment symbol and drop it into the No branch. Set it to increase by 1.
Now drag out the world "countStars:dot" script tile and drop it underneath the "sCount" assignment statement inside the No branch.
Get another nextNode variable from one of the stars and replace the parameter tile in the statement with it.
Click the parameter box on the script editor menu to get another player tile and replace the star's name with it. This statement should read "World countStars player nextNode".
world startCount script
Drag out the "world countStars:dot" script tile again but drop it in the startCount script this time. Replace the parameter tile with the firstStar variable tile from the World object. Make sure to save before running this script in case something goes wrong. Run startCount and check the sCount variable.
So what is going on here? This example demonstrates a process known as traversing a list using recursion. The startCount script initializes the counting variable and calls the countStars script passing it a reference to the first star in the list. The countStars script assigns this object to the player variable. The test tile checks the value for the nextNode variable inside that object. If it is equal to dot nothing more happens and the script stops because there are no more Star objects in the list. If the nextNode value is a Star object then the tiles in the No branch execute. The sCount variable value is increased by 1 and the countStars script is called again but is passed a reference to the object assigned to nextNode which should be the next star in the list. The script will repeat until the player nextNode variable equals dot.The sCount variable should equal the number of stars in the list.
Of course you could also count the stars at time of creation. By giving objects unique values, you can use these techniques to locate objects by testing for values and issue commands to them or change their properties. If you want to remove an object, you'll have to make sure to reassign the preceeding object's nextNode value. The countandremovestars.007.pr project file demonstrates how to remove the last Star object in the list. This file can be downloaded from my GitHub repository. Save it to your Etoys directory and load it into Etoys.
Although recursive processes, referencing objects and traversing lists are common programming tasks, they aren't the easiest to understand. Hani Awni's SnakeSpawn project at Etoys Illinois was my guide. This is an excellent example of how linked lists can be used in games.
Capturing mouse clicks is pretty easy in Etoys. There are several mouse events that can selected in the script editor status menu. The script will run whenever that mouse action is performed on the associated object. The mouse enter dragging and mouse leave dragging events seem to work best when you are dragging another object onto your object. Note that you may only be able to move objects with the move icon handle when one of their scripts is waiting for a mouse event. This example project someMouseEvents.003.pr can be downloaded from my GitHub repository. Save to your Etoys directory and open in Etoys.
You can also add mouse over balloon help text to objects through the menu options halo icon.
Get buttons to run your scripts in their script editor menu options. The buttons have a built in effect but you can customize their looks with their halo icons. If you want to create customized effects then use the button object in the object catalogue scripting category. Buttons have an icon in their halo to quickly bring up the script they are associated with.
All objects have an input category reporting keystrokes so keyboard input can be captured by scripts inside any object. Values are of type string so can only be tested for equality and cannot be assigned to any other variable type than string. The spacebar registers as a blank character. Non alphanumeric keys show their value between angle brackets, for example, the up arrow key looks like this <up>. The control key reports as <cmd- > and the alt key reports as <ctrl-> so be careful using key combinations other than shift as they can activate Squeak commands. The Enhanced Text object in the object catalogue connectors category can be set to respond to the enter key or the mouse cursor leaving it. Scripts created in Enhanced Text objects can have status set to acceptedTextContents meaning the script will run either when the enter key is pressed or the object loses mouse focus depending on what's been set.
The just for fun category in the object catalogue has a Key Press object. This object has an individual keyboard key assigned to it and reports true whenever that key is pressed and how long it has been pressed for. This is pretty useful for controls that accelerate for example. Scripts have no special status so other than when using the Enhanced Text object, scripts that capture keyboard input must be set to ticking.
If you want to restrict your user to entering numerical input, then you are best to use a watcher for the variable or property capturing the input or use a Slider object which can be found in the supplies flap or the basic category in the object catalogue. You can build nice forms by using simple watchers and labelling them however you want with adjacent Text objects.
Sliders have extra tiles in the viewer category slider. Capture Slider values either with a ticking script in the Slider or a script inside the Slider's Rectangle object set to Mouse Still Down status.
Some objects in the Multimedia category accept input from the pc microphone jack. The Sound Recorder and World Stethoscope work well with audio. The OLPC has a page on adapting a 3.5mm jack to connect other types of sensors but I have never tried this. The microphone jack is not a typical method of connecting sensors and this page is specifically about the XO laptop.
There is a Joystick object in the supplies flap. I have had success connecting an XBox 360 controller in Windows but it can also be used just with the mouse.