English (United Kingdom) Hebrew

Advanced guide: Monkey tale

This guide includes an advanced sample program for a thorough understanding of Mama development environment and language.
Contents
Topics covered in this guide:
  • moving the camera, fade-out, fade-in
  • dividing the program code into modules
  • more about 3D movement, moves and turns
  • more about parallel execution of instructions
  • defining events
  • using functions


Editing the stage

We first have to insert number of object into the stage:
  • insert trees and flora
  • insert a television, an armchair and a remote controller - add the TV and the controller from the folder Objects, and the armchair from the folder Furniture. Locate the objects as in the image above.
  • insert monkeys - add 2 monkeys from the folder Animals. Locate the first monkey to the right of the TV, and the second one to the left of the TV, as in the image above.
  • insert characters - from the characters folder characters/kids add the characters trevor and kristen. Add the dog sam from characters/pets.
Since the last characters you just added will enter the stage only during the animation, locate them to the left, outside the camera view. You can do this by doing zoom-out, then dragging the characters to the left side, and then returning to the original zoom. This is a common technique for setting the stage with objects that are getting into the scene during the play. It is quite similar to theater real actors who wait behind the curtain, and get into the stage during the play.
A convenient technique to bring the camera back to it's original position is by placing a tripod at the camera: in stage editing mode, the right panel contains the button place tripod at the camera. If you click that button, a dialog will be displayed, asking you to name the tripod which is placed in the current camera position. If you move the camera, you can always return to the saved position by selecting it from the scene selection box (above the 3D window).


The program script

As in a theater play, we need to write our animation script. We will do it in steps:
  • black screen, display introduction title, fade-in
  • camera starts at treetop, then slowly goes down to the original stage level
  • the opening scene: two monkeys on the tree, a television between them laid on a branch, the remote controller and the armchair are on the ground, the armchair is turned on its side.
  • the monkey to the right of the TV (monkey1) screeches
  • trevor and sam enter the stage (from the left side)
  • trevor looks at the remote controller, then at the screeching monkey, and back to the remote controller - he understands that the monkey wants the remote controller
  • trevor bounces the remote controller to the monkey using his foot
  • the monkey stops screeching, trevor and sam leave the stage (from the right side)
  • monkey2 jumps on the armchair and starts watching the TV
  • monkey1 throws the remote controller over monkey2's head
  • monkey2 screeches and escapes (leaves the stage from the left side)
  • kristen enters the stage (from the left side)
  • monkey1 screeches again
  • camera goes up to the treetop
  • fade-out, ending title


Setting the program tasks as methods

As we can see, the script is too long to be written in the world main method. Dividing it into methods eases writing and maintaining the program code, and also simplify making changes or adding new features. The methods :
  • world.main_method() - main method of the program, calls other methods
  • intro() - does fade-out, displays opening title and does fade-in. Then it moves down the camera from the treetop to the ground
  • monkey1 screeches - we don't need to define a method, there's already a method named screech in the monkey object
  • world.trevor_enters() - trevor and sam enter the stage
  • world.trevor_meets_monkeys() - trevor meets the monkeys
  • trevor.switch_looks() - trevor switches looks between the monkeys and the remote controller
  • trevor.bounce() - trevor bounces the remote controller to the monkey's hand
  • world.trevor_leaves() - trevor and sam leave the stage
  • world.monkey2_jumps_on_armchair() - monkey2 jumps onto the armchair
  • world.monkey_throws_tv_controller() - monkey1 throws the remote controller over monkey2's head
  • world.monkey2_escapes() - moneky2 escapes
  • world.kristen_enters() - kristen enters the stage
  • world.end() - move camera up to the treetop, fade-out, display ending title


Most of the above methods are not specific to one specific object, but work on several objects, thus should be defined as methods in the World object. The two exceptional are trevor.switch_looks() and trevor.bounce(). Moreover, we might need to define more methods during writing of the program. In the rest of this tutorial, we will omit world from the world methods for simplicity.
For testing a method you've written you can use a useful technique - simply add event in the event window by clicking create new event, and select event of type When the world starts. Then select the method you created to be ran when the world starts. For the testing time, disable the original event (which calls the main method). After completing the test, you can either delete the new event you created (and enable the original), or simply disable it, so that it will be available for future tests. This kind of test is called unit testing, as we test one unit of the world in a single test.


Writing the methods

Now we are ready to write the world methods. Reminder: to create a method in the world object, select world in the object tree, and in the details area select create new method. In the opened dialog provide the method name.
Method specifications:

intro()

  1. fade-out - using the camera's standard method fadeToBlack - drag this method into the beginning of the current method
  2. display opening title - using the camera's standard method showTitle - provide as arguments an introduction title, and set its duration to 2 seconds
  3. move camera up - call the camera's move, with arguments UP and 5.5 meters
  4. fade-in - using the camera's fadeUpFromBlack, and duration=2
  5. move camera down - again using camera's move with arguments DOWN and 5.5 meters, duration=5.5 seconds
Click here for the method code

trevor_enters()

  1. first, we tell trevor to walk 2 meters into the stage so that he is seen - do that using the method trevor.walk. Note: this method is available for certain characters (located under the object gallery in folder characters).
  2. we want to do the same for sam, but there's no such walking method! Create a method named walk in sam object according to the method code here. Then call this method with the argument 2 meters. Note that you have to create a parameter for the method of type Number.
  3. during trevor and sam walk:
    • make monkey1 screech using its method screech.
    • make both monkeys look at trevor using the standard method turnToFace with trevor as an argument.
  4. after walking, trevor notices the monkeys - turn his head to the screeching monkey using its method turnToFace. Also, turn his head to the screeching monkey using his method lookAt, with monkey1 as an argument.
  5. sam gets excited - to express that call his methods be excited, bark and wagTail with argument 2.
Hint: make 2 doTogether blocks, where the first contains instructions 1-4 and the second contains instructions 3-7. Notice that some methods are duplicated in the 2 blocks, that is essential for creating a continuous animation.

Click here for the method code

trevor_meets_monkeys()

Create 2 doTogether blocks. First block contains:
  1. trevor advances 1.5 meter
  2. monkey1 screeches
  3. the 2 monkeys turn (again) to face trevor
  4. make sam turn to face the screeching monkey
  5. as before, make sam look excited
Second block:
  • again, make the two monkeys turn to face trevor
Click here for the method code

trevor.switch_looks()

That is a simple method, but the special thing about it is that it accepts two arguments: the objects to look at. This is a better alternative over using explicitly the objects in the method, since it is more general, and it can be used in the future for other objects (reuse).
  1. create 2 arguments
  2. make trevor look on the first object: call trevor.lookAt, and as an argument select expressions, then select the first method argument.
  3. drag the instruction wait with an argument 1 second.
  4. as before, make trevor look at the second object.
  5. again, add the instruction wait with an argument 1 second.
  6. make trevor look at the first object.
Click here for the method code

trevor.bounce()

This method is defined on trevor object too, and it too accepts arguments: the object to bounce - what (the remote controller), the target object - whom (monkey1's left hand), and the whole target body - whom_body. We will make the animation as follows: trevor walks to the what object, then 3 things happen simultaneously: trevor kneels suddenly , the what object moves to the whom object, and the whom_body leans forward to catch the what object. Then trevor stands up, and the whom_body leans backward.
  1. create the above arguments
  2. make trevor look at what
  3. make trevor walk to what using his method walk. As an temporary amount parameter, give it 1 meter. What we actually want is to make trevor come right to the what object, how do we do that?
    • hint: select trevor in the object tree, and in the details area select functions. Find the function distanceTo, and drag it into the amount parameter of the call to walkTo. From the popup menu select expressions and then select what.
    • Click on more... then select spatialRelation, and then select ABOVE. This parameter determines how trevor should get to the what object, with relation to its location in the space.
  4. now do in parallel:
    • make trevor kneel - find the appropriate method - and give it a arguments one knee, and duration of 1/4 seconds.
    • move what to whom - drag what from its definition and drop, from the popup menu select moveToward, and give the argument whom. Set its parameter amount as before using the function distanceTo from the object whom.
    • now we need to add a little fix: from the amount you've just customized, select more..., then math and then select the subtraction operation. As as subtraction parameter set 0.07 meter.
    • to make monkey1 lean forward, call whom_body.turn with parameters FORWARD and 0.25 seconds
    • make trevor look at whom again, since it has moved.
  5. now return the monkey to its original position: since we want the remote controller to remain in his hand while leaning backward, we need to "attach" it to the whom somehow. The standard method set_vehicle does exactly that:
    • call what.set_vehicle and pass it whom as an argument. From now on, what is "attached" to whom, and will move and turn with it.
    • make :whom_body lean back to its original position using its turn method
    • now, call what.set_vehicle with the world object as an argument - that will detach it from whom.
  6. call trevor.standUp
Click here for the method code

trevor_leaves()

In this simple method trevor and sam leave the stage. Do in a doTogether block:
  1. call trevor's method walkOffScreen - that will cause him to walk out
  2. make sam turn to face trevor
  3. make sam walk 7 meters
Click here for the method code

monkey2_jumps_on_armchair() and jumpTo

We now want monkey2 to jump over the armchair, but he has no such method. He does have a method called monkeyJump, but it does only jump in place. In the next section we will make a copy of this method and edit it to match our needs. So go first to next section and complete creation of the method jumpTo.
  1. add a wait instruction for half a second
  2. call jumpTo for monkey2 and pass it the armchair as an argument
  3. add a wait instruction for 1/4 seconds
  4. make monkey2 turn to the TV.
  5. make moneky2 look at the TV: since monkey2 has no lookAt method, call the pointAt method on his head part. Do that by firs selecting monkey2 in the object tree, and open its sub-tree. Locate the monkey's head part, drag it and drop it into the editor area. From the popup menu select pointAt, with the TV as a parameter.
  6. call monkey2's MonkeyFace method so that the monkey will do faces to the TV
Click here for the method code

monkey2.jumpTo()

As said above, we need to write the method jumpTo for the monkey, to jump to a given target:
  1. when monkey2 is selected in the object tree, right-click on the method jump and from the popup menu select {ls:duplicate}}. Right-click on the newly created method, and change its name to "jumpTo".
  2. lets review the new method code:
    • the method contains 4 doTogether blocks: in the first the monkey leans down, in the second the monkey starts standing up while straightening his legs, in the third block the monkey leans back a little while moving up, and in the last block the monkey leans down to its original position.
  3. create a parameter of type Object named what
  4. make the monkey turn to face the target, what
  5. shorten the duration of all the instructions in the method to 0.25 seconds
  6. in the third block, while leaning back and moving up, call its method moveToward, with a parameter what. Set the amount parameter similarly to what we did for trevor.bounce to distance of 0.07 meter. Set the duration to 0.75 seconds.
Click here for the method code

monkey_throws_tv_controller

This method implements the throw of the remote controller by monkey1 over monkey2's head. The throw is composed of turning monkey1's left hand back, then turning his left forearm further back, and then bringing the hand fast forward, while moving the remote controller to monkey2's head.
  1. attach the remote controller to monkey1's left hand using its set_vehicle method
  2. do in parallel: turn monkey1's left hand back 0.12 revolutions during 0.5 seconds, and move his forearm with the same arguments
  3. detach the remote controller from monkey1's left hand
  4. do in parallel: turn monkey1's left hand forard 0.12 revolutions during 0.25 seconds, and move the remote controller using its method moveToward to a distance of 0.3 meter from monkey2's head, using the function distanceTo as you did above.
  5. do in parallel: turn monkey2's head backward 0.12 revolutions, make him screech, and move the remote controller to a flower found near the tree on which the TV is found (if there's no such a flower, add one).
Click here for the method code

monkey2_escapes

In this method monkey2 escapes to the left side of the stage.
  1. turn monkey2 to face the left side of the stage. You can do that by placing a dummy flower on the left side of the stage, and then turning the monkey to face ti.
  2. call monkey2's method you created above with the flower you created as a target argument.
  3. if the distance to the left side is to big, you can place another flower in the middle, to which the monkey will jump as a middle step.
Click here for the method code

kristen_enters

In this method kristen enters the stage, and monkey1 starts screeching again. Build this method code as in the above trevor_enters. Click here for the method code

end

  1. move the camera up (6 meters) to the treetop
  2. fade-out
  3. display the title, e.g. "and so it goes on and on :)"
  4. display the title "The end"
Click here for the method code

Writing the main method

At complete of writing and testing the rest of the program methods, it is time to write the main method and call the other methods according to the animation script we wrote above.
it is possible - and also advisable - to write the main method along with writing the other methods, so that we can make partial tests or unit tests of parts of the program. For example, right after completing the method intro, you can call it from the main method and test its correctness. Likewise, after completing other methods you can call them from the main method and run the available portion of the program, to verify it is executed as expected. As noted above, you may use another technique for doing unit testing by creating when the world starts events.
  • write the method body as defined in the animation script
  • the method code:
  main_method ( )
    
       # introduction: camera move, fade-out, fade-in
  world.intro ( );
  monkey.screech ( );
  # Trevor and sam enter into the stage
  world.trevor_enters ( );
  # trevor and sam come closer to the monkeys
  world.trevor_meets_monkeys ( );
  trevor.switch_looks ( obj1 = remoteControl1 , obj2 = monkey );
  # trevor gets the remote control to the monkey
  trevor.bounce ( what = remoteControl1 , whom = monkey.leftArm.forearm.hand , whom_body = monkey );
  # trevor and sam leave
  world.trevor_leaves ( );
  # monkey2 jumps to the armchair and watches TV
  world.monkey2_jumps_on_armchair ( );
  # First monkey throws the TV controller on monkey2
  world.monkey_throws_tv_controller ( );
  world.monkey2_escapes ( );
  # Kristen enters into the stage
  world.kristen_enters ( );
  # camera moves up, fade-out
  world.end ( );


Click here for the whole program code