View this PageEdit this PageAttachments to this PageHistory of this PageHomeRecent ChangesSearch the SwikiHelp Guide
Hotspots: Admin Pages | Turn-in Site |
Current Links: Cases Final Project Summer 2007

The Squeak Wonderland Tutorial

Wonderland: The wonderful world of Squeak 3-D

Wonderland is essentially Squeak's support for 3-D characters and animations. It consists of a bunch of classes which let you make little scenes with 3-D characters, then alter and move them at will.

CREATING A WONDERLAND

The easy way to create a Wonderland is by simply typing:

Wonderland new.

Uploaded Image: JustinSqueakTutorial1.jpg
(A happy new wonderland)

This will open a default wonderland, with a camera, a light source, and the ground. It will also bring up a wonderland editor, in which you can make quick edits to things, and a WonderlandCameraMorph, which is essentially the little box in which you see everything. One important thing to know is that if you want to do send messages to this Wonderland in the Editor, it is, by defalut, called 'w'. (Go to the section in which a camera is made in the 'SIMPLE ACTIONS IN WONDERLAND' for an example of this.

IMPORTANT NOTE: This is likely the best place to put this. When you're done with a Wonderland, you NEED to close it with the Quit button (or the Wonderland release function). Otherwise, the Wonderland won't clean up completely, and you might have to do extra clean-up work. (Or, it might slow down, or even crash Squeak if it goes unchecked for too long.


ADDING ACTORS TO A WONDERLAND

Next come the WonderlandActors. These Actors are basically all the little people, animals, vehicles, etc. which you mess around with in your Wonderland.

Unfortunately, Squeak doesn't really come with any good actors. I reccomend you download the file:


This comes with a lot of actors for you to mess with, and should be enough to start tinkering with your new wonderland. Also, the examples that follow will use these models. These models are in the .mdl format, which is the easiest format with which to make WonderlandActors. There are other formats which can be used, like .a2c files, but they don't work quite as well.

Okay, so unzip the above file somewhere in your Squeak directory, and you should end up with a bunch of folders, full of wonderful models for you to use. Now, to add one of these models to your wonderland, so you can begin to have fun with your Wonderland, you'll need to use the makeActorFrom message. The Wonderland sends this message, and the parameter should be a string containing the path to the .mdl file. For example, my squeak.exe file is in the 'D:\Squeak' directory, as are all the folders with my models. So, if I created my Wonderland with the message 'w := Wonderland new.' then I would make a actor by typing in messages like:

copter := w makeActorFrom: 'Vehicles\Helicopter.mdl'.
alice := w makeActorFrom: 'Animals\AliceLiddell.mdl'.

Uploaded Image: JustinSqueakTutorial2.jpg
(Now featuring Choppy the Helicopter!)

And so on, with or without the assignment statements to keep a handle on the actors. Notice that when you make a model, an actor is displayed in the camera window, and the actor's information and parts are displayed in the editor. For example, if you make an actor out of the Helicopter model, then a cute little helicopter will appear in the window, and the editor will have a new variable, which is by default named 'helicopter'.

Note: If you create multiples of the same actor, they might recieve different default names. This can happen even if you destroy the old instances before you make new ones. For example, if you make the helicopter Actor, then destroy it, and then make another one, it will likely be called 'helicopter1' instead of 'helicopter'. Remember that you can always see the name of all your actors in the editor window.


SIMPLE ACTIONS IN WONDERLAND

Wonderland operates on a couple of simple principles. The first, is the principle that 'vocabulary matters'. Because Squeak was intended for use by children and other people not experienced with programming languages and technical terms, most of the commands in Wonderland use very simple terminology, as you shall soon see. A few examples include using terms like 'left' and 'right' instead of 'x', 'move' instead of 'translate', and so on.

The other interesting idea is the controlled exposure to power. The idea was that you should be able to teach people simple functions, and as they get more experienced, you should teach them new things without making their old knowledge obsolete or useless.

To see these ideas in action, create a Wonderland, and make an actor out of Vehicles\Helicopter.mdl. Then, go to the Wonderland editor, and try typing in each of the following commands. (Pressing undo between each command, so you can see what's going on.)

helicopter move: left.
helicopter move: left distance: 3/2.
helicopter move: left distance: 3/2 duration: 2.
helicopter move: left distance: 3/2 duration: 2 style: abruptly.

This is the controlled exposure to power in action. You can teach someone how to move the helicopter, then you can teach them how to affect the distance moved, without having to reteach them how to move, and so on. When someone calls the helicopter move function, the program actually calls the 'move: distance: duration: style:' method, and puts in default values for anything you didn't input. As you gain more experience, you can use your own values instead of the defaluts, withough having to relearn anything.

Also notice the simple terminology. The people who made Squeak found that people were confused by standard technical terms; 'the helicopter translates one meter in the x direction' and 'the helicopter moves one meter to the right' are the same thing, but far more people understand the second scentence. This is why Wonderland uses such simple terminology. Also note the lack of units on measurments. This is another way of simply letting people do neat things with Wonderland without having to expose them to stuff they might not know. There's no need to have to explain radians to someone, just so they can turn the helicopter around once.

Enough of that, let's get to a few more examples.

All of the following functions should work as you might expect they would. Try them out.

helicopter turn: left.
helicopter turn: left turns: 2.
helicopter roll: right.

helicopter resize: 2.

helicopter pointAt: camera.

There's many, many more things you can do with WonderlandActors. Look at the WonderlandActor class in a browser to see all the messages they can take.

Another interesting thing to notice is that everything in Wonderland is an actor, even the camera and the ground. So, commands like:

camera move: back distance: 1.

Are perfectly legal. They can also be created, just like other actors, with commands like:

w makeCameraNamed: 'myCamera'. "At this point, you'll have to access the halos of the CameraMorph and move it, but if you do, you'll see that you have two cameras."
myCamera move: left distance: 5.
myCamera pointAt: helicopter.

Uploaded Image: JustinSqueakTutorial3.jpg
(Multiple cameras = I know Kung Fu! Notice the name of the camera... That's a little Squeak annoyance. See the problems section at the bottom of the page.)

Now, just like in The Matrix, you too can have 60 cameras in every scene. (Just don't blame me when you crash Squeak...)

Notice also that the Helicopter object is made up of a lot of parts. rotor is a part of topShaft, which is a part of helicopter. They're all WonderlandActors, just some are children of others. You can perform actions on these parts individually, by running commands like:

helicopter topshaft turn: left.
helicopter rightSkid roll: left turns: 1.

Just remember that you have to type in all of the parents in the heirarchy.

You can also change the parent of an Actor, for example, with:

helicopter topShaft rotor becomeChildOf: scene. "Now, try 'helicopter turn: left.' and see what happens."
rotor becomeChildOf: (helicopter topShaft). "This undoes the above line. Try 'helicopter turn: left' one more time."

And, of course, we had to save the best function for last, right? If you want to delete WonderlandActors in a truly spectacular way, then use the destroy command. For example:

helicopter destroy.

Didn't that feel good?


COMPOSITE FUNCTIONS

Now, I can hear everyone out there saying, "That's nice and all, but how do I do stuff cooler than making helicopters turn around abruptly?". Wonderland a few useful tools for letting people combine simple animations

These two functions work about as expected. doInOrder takes multiple simple animations, and does them in order, starting each one when the previous one ends. Try these on for size: (If you blew up the helicopter, you'll need to make one again.)

w doInOrder: {helicopter turn: left. helicopter turn: right.}.

A couple of things of note. You have to use the curly braces for doInOrder, and the delimiter for each individual action is the period.

doTogether works the same way. Try something like this:

w doTogether: {helicopter turn: left. helicopter move: left.}.

You can get creative with these and make some interesting animations; try this animation of the helicopter taking off:

w doTogether: {helicopter topShaft turn: left turns: 50 duration: 5. helicopter move: up distance: 5 duration: 5.}.

You don't have to only perform actions on the same object either... doTogether's and doInOrder's can make multiple different actors perform actions together. For example, try this:

w doTogether: {helicopter turn: left turns: 1. camera roll: right turns: 1.}.

Combining a lot of animations can make for very hairy-looking function calls. Fortunately, Squeak allows us to assign any animations we make to variables. This can save us a lot of space and make things more readable, especially if we want to chain together very long animations. For example, the function.

w doInOrder: {helicopter move: up distance: 2 style: abruptly. helicopter move: up distance: 2 style: abruptly. helicopter move: up distance: 2 style: abruptly. helicopter move: up distance: 2 style: abruptly. helicopter move: up distance: 2 style: abruptly. helicopter move: up distance: 2 style: abruptly.}.

Pretty ugly, but it can be made more readable (and shorter) by assigning the repeated action to a function.

hop := (w doInOrder: {helicopter move: up distance: 2. helicopter move: down distance: 2.})
w doInOrder: {hop. hop. hop.}


And that's basically it for composite functions. Remember that doTogether and doInOrder are messages sent by the wonderland itself, and you should be fine. Try a few things out to see what you can do.


WONDERLAND INTERACTING WITH SQUEAK

Now comes the interesting part. Wonderlands and their actors, like almost everything else in squeak, are objects that can interact with each other. It may seem like Wonderland is its own little world, with these cute little actors that spin around each other in their little box. However, you'd be surprised to know that with a little effort, you can have Wonderland Actors dragging windows around, following your mouse, and doing loops around the trash can.

First, just to drive that point home, try this command out:

helicopter doEachFrame: [ helicopter pointAt: (camera transformScreenPointToScenePoint: (Sensor mousePoint) using: helicopter) duration: rightNow ].

Some of the funtions in here might have been a little hard to find, had you tried to do this yourself, but it should all make sense when you look at it. The helicopter is sitting there interacting with something that isn't in the Wonderland (your mouse pointer) with absolutely no problems. Now, if you want him to stop looking, run:

helicopter stop.

Note: To make these examples look even more natural, try removing the background stuff with the following:

ground destroy.
camera turnBackgroundOff.


Wow, we've got a little guy who can interact with the world, right? Not quite. See what happens if you run this:

helicopter pointAt: camera.
helicopter move: left distance: 2.


Hmm. He just sorta slides off into nothingness... (You may have also noticed this happening if you tried to drag the helicopter around with the mouse.) Don't worry, that's to be expected. Even though the background is invisible, that little camera window is still there. But then, how do we get these things to move around? The answer is that the little helicopter itself doesn't move, the camera window moves. It's a little tricky to get a handle on the camera window, so here goes. Try out these lines of code to access the camera window so you can mess with it.

worldmorphs := World submorphs.
window := (worldmorphs select: [:morph | morph class = WonderlandCameraMorph]) at: 1.


Essentially, this command looks at all the morphs currently open in the world, picks out all the WonderlandCameraMorphs (The little boxes which show what the camera is seeing) and returns the first one it finds. Unfortunately, there's no real better way to do this. If you have multiple camera windows, it'll grab the morph it sees which is a WOnderlandCameraMorph. If you want to grab other ones, the only way to do so is by guess-and-check, because of how Squeak handles its objects. Oh well. Either way, now we have a handle on the actual WonderlandCameraMorph, named 'window'. Now try out the following commands.

window sendToFront.
window moveTo: (200@400).


Much better. If you want to make things look even nicer, you could do something like:

window sendToFront.
window moveTo: (200@400).
w doTogether: {helicopter pointAt: (200@400). helicopter topShaft turn: left turns: 10.}.


Uploaded Image: JustinSqueakTutorial4.jpg
(The now-backgroundless helicopter pointing something out for us. Notice that the tail is cut off. Just because the background is gone doesn't mean that there's no longer a window framing the scene.)

Run all three together, and you'll see the helicopter fly over to the point 200, 400 on the screen. Isn't that cute? Remember that you can't compose windows moving and stuff like that using the doTogether and doInOrder commands... Only actions in wonderlands can be composed in that way, not the movements of things outside wonderlands, like windows.

Now, let's try something a LOT more complex. Try this one out.

helicopter pointAt: camera. "Run this first, so it doesn't look dumb."
helicopter resize: 1/2. "Otherwise, bits of the helicopter go over the boundaries of the window and disappear."

spin :=
w doTogether: {
helicopter turn: left turns: 1 duration: 8 style: abruptly.
helicopter topShaft turn: left turns: 80 duration: 8 style: abruptly.
w doInOrder: {
w doTogether: {
helicopter do: [window sendToFront.].
window move: right distance: 650 duration: 4.
w doInOrder: {
helicopter move: back distance: 1 duration: 2 asSeenBy: camera style: endGently.
helicopter move: forward distance: 1 duration: 2 asSeenBy: camera style: beginGently.
}.
}.
w doTogether: {
helicopter do: [window sendToBack.].
window move: left distance: 650 duration: 4.
w doInOrder: {
helicopter move: forward distance: 1 duration: 2 asSeenBy: camera style: endGently.
helicopter move: back distance: 1 duration: 2 asSeenBy: camera style: beginGently.
}.
}.
}.
}.
"The spin around once function."

spin loop. "To start the loop."
spin stopLooping. "To stop the loop."

Uploaded Image: JustinSqueakTutorial5.jpg
(The helicopter looping. You'll just have to do it yourself to see that it works.)

Why helicopter do? Because the simple action of sending a window to the front can't be used in doTogether and doInOrder, but making it an action of the helicopter makes it work. Silly Squeak. Everything else should be pretty self explanatory. Notice that Squeak's World still goes on, and you can even type in the window and edit code. That's one of the things that's truly neat about Squeak.


WORKING WITH WONDERLANDS OUTSIDE THE EDITOR

So, let's say that you want to integrate things into a program, and not just mess around with a little editor window. In Squeak, this isn't too difficult. Firstly, you'll likely want to assign things to variables, so that you can mess with them. Stuff like:

wonder := Wonderland new.
copter := wonder makeActorFrom: 'Vehicles\Helicopter.mdl'.

And so on. The only other thing you'll need to know is how you access a few commands. Most of these have obvious names, and shouldn't be that hard to find in the class browser. For example, closing your Wonderland without using the editor can be done by calling 'wonder release'. Hiding the editor window can be accomplished with '(wonder getEditor) hide.' There's a lot of stuff like this, and there's no way I can go through every function that might be useful to you. Just realize that you can find them all in the class browser, and that they've usually got obvious names. The Wonderland stuff should be easy, and most of the other functions you need will be under WonderlandCameraMorph or WonderlandEditor. Just remember that if you right click on a class and view its protocol, you can see EVERY message it can send.

And that's about it. The rest of this stuff is easy, because of Squeak's flexibility. You can take blocks of code affecting your wonderland and set it as a variable, a function, almost anything you want. You can assign Wonderland animations as animations for a scheduler, with something like, '(wonder getScheduler) addAnimation: animation1.'. You can externally call them in your code, with something like, '(index = 9) ifTrue: [animation1].'. You can do all sorts of things with your Wonderland animations, and again, there's a lot more than I can describe here. If you want to see some of this stuff in action, try looking under the swiki for past projects and see what past groups have done. There's a lot of stuff out there, take a look, and get a feel for all that can be done with Wonderland.


A FEW ERRORS

Obviously, I can't predict every error anyone will ever make in Squeak and cover them here. However, here are a few common errors in Squeak and how to solve them.

One frequent error is that sometimes, Squeak won't recognaize the messages you're sending in. First of all, make sure that you can indeed send the messages you're attempting to send to the object. (If you're trying to make a WonderlandCameraMorph roll instead of the WonderlandCamera, you won't get very far.) Sometimes, you might also get things out of order. (Squeak has no problem with 'helicopter turn: left turns: 2.', but will screw up on 'helicopter turns: 2 turn: left.' It's just picky like that. Also, make sure that you're using the correct name for the object you're sending the functions to. Things frequently don't have the same name as their mdl file ('Helicopter' vs. 'helicopter') and sometimes, if you've made many of the same object, Squeak will append numbers to the name without telling you. Another annoying Squeak thing. If helicopter doesn't respond to your messages, and you've been making multiple helicopters, try sending the message to helicopter1.

If Squeak messes up on your composite functions, check a couple of things. You'll get an error message if your brackets don't match up, so take a look at those. (Don't ask me how many times I wrote the loop function above...) Also remember that Squeak is picky with including non-WonderlandActors in your composite functions. If you have that problem, try making the action a function of a wonderland actor (think 'helicopter do') or simply running it at the same time as your wonderland actions. If you do two lines of code, like in the case of:

window moveTo: (200@400).
w doTogether: {helicopter pointAt: (200@400). helicopter topShaft turn: left turns: 10.}.


Squeak is still evaluating lines of code in tiny fractions of a second, so it will move the window at essentially the same time it starts the animation.

If Squeak says it can't understand a hideously long funtion you didn't write, like 'helicopter move: distance: duration: asSeenBy: style: move: distance: duration: asSeenBy: style:' you likely left out a period somewhere. You have to be careful with the periods in these huge composite functions.


IN CLOSING

Wonderland is a fun tool, and probably one of the most interesting things in Squeak. With a little bit of effort, you can do some powerful things with it. Look at old projects and code around this page for examples, and keep checking the www.squeak.org and www.alice.org sites for updates.

Good luck, and (relatively) happy Squeaking!

Links to this Page