Learn to Program using Alice

Appendix G

By Popular Demand, Interesting Projects

Baldwin shows you how to complete several interesting programming projects for which he has received requests for information.

Published:  November 6, 2007
Updated:  October 27, 2007
By Richard G. Baldwin

Alice Programming Notes # 930


Preface

General

This document serves as an appendix to a series of programming tutorial lessons that are designed to teach you how to program using the Alice programming environment under the assumption that you have no prior programming knowledge or experience.  In case you have happened upon this document as a result of a web search, an index to all of the material contained in the series is available in Resources.

A work in progress

From time to time I receive email requests, or see requests posted in the Alice forum for information on how to solve a particular programming problem using Alice.  My plan is to respond to some of those requests by providing sample programs in this appendix.  Therefore, this document is a work in progress that will be updated as such requests are received and honored.

Viewing tip

I recommend that you open another copy of this document in a separate browser window and use the following links to easily find and view the figures and listings while you are reading about them.  Note that because material will be added to this document from time to time, the figures and the listings may not be in numeric order in the body of the document.

Figures

Listings

Supplementary material

Once you have mastered Alice, I recommend that you also study the other lessons in my extensive collection of online programming tutorials.  You will find a consolidated index at www.DickBaldwin.com.

Discussion and sample code

Two-dimensional projectile trajectory program

One of the earliest computer games that I recall seeing during my lifetime is a simple game involving the trajectory of a projectile.  The computer-game magazines of the sixties contained numerous such programs written in BASIC and other early programming languages.  I have recently seen several requests for information on how to program the trajectory of a projectile.

Many applications

The use of a ballistic trajectory has many applications in programming games.  For example, the path of a basketball after leaving the player's hands is probably a very close approximation to an idealized ballistic trajectory.  The same holds true for the path of the human cannonball at the circus, (which I just witnessed this past weekend).  An interesting animation would be to create a human cannonball using a Coach object from the gallery and finding something in the gallery that looks like a net to catch the coach.

General Ballistic Trajectory
The motion of an object under the influence of gravity is determined completely by the acceleration of gravity, its launch speed, and launch angle provided air friction is negligible. The horizontal and vertical motions may be separated and described by the general motion equations for constant acceleration.

The equations of motion

The first challenge in writing such a program is understanding the equations of motion for a projectile.  An excellent treatment is of the equations of motion is referenced in the accompanying sidebar.

The animation program

The Alice animation program shown in Listing 1 causes a safe (of the money storage variety) to be shot as a projectile across the screen in a two-dimensional universe.  The user specifies the launch angle relative to the horizontal axis.  Screen shots from this program are somewhat less than exciting, so I didn't provide any.  You can download a zip file containing the Alice world for this program, extract the world file from the zip file, load the world into your Alice programming environment, and play it to see the animated trajectory.

Improvements to the program

Paraphrasing the opening scene from an old TV show, your challenge, if you choose to accept it, is to extend this projectile-trajectory program into three dimensions.  If you are really ambitious, you could also add the effects of wind at some fixed velocity blowing from some particular direction in 3D space.

Approximate trajectory program

If you load and run the 2D projectile trajectory program you may find it to be a little jerky, depending on the speed of your computer. This is because computing and rendering the parabolic trajectory at a large number of closely spaced points places a significant computational load on the computer.

A smoother animation

This program produces an approximate trajectory that should run smoothly on most computers that are capable of running Alice programs.  While this trajectory is circular rather than being parabolic like a true ballistic trajectory, it is close enough that it should be suitable for most Alice animations.  When viewed in three dimensions, it is very difficult to tell the difference between this approximate trajectory and a true ballistic trajectory unless the viewer's line of sight is exactly perpendicular to the plane of the trajectory.

The source code

The source code for this program is shown in Listing 6.  The actual trajectory is produced by the two statements shown in Figure 7.  These two statements were copied from the method named jump belonging to the fish class in Listing 6.

Figure 7. Trajectory code.
fish.move(FORWARD,length meters);
  style = BEGIN_AND_END_ABRUPTLY
  duration = 2.5 seconds
fish.turn(FORWARD,0.25 revolutions);
  style = BEGIN_AND_END_ABRUPTLY
  duration = 2.5 seconds

Note that the two statements in Figure 7 (along with some other code) are inside a doTogether block so that they will execute concurrently:

Catching a bug

Figure 8 shows an image of a fish that has launched itself from the water in a long arc-shaped trajectory in an attempt to catch and eat a bug.

Figure 8. Jumping fish going after a bug.
The launch angle

Initially, the blue (forward) axis of the fish is rotated upward by 45 degrees.  The first statement in Figure 7 causes the fish to launch itself from the water at an angle of 45 degrees.

What produces the circular arc?

As the fish moves forward, the second statement in Figure 7 causes the fish to continuously rotate its blue axis downward toward the water.  Because it is continuously moving in the direction of the blue axis, this motion describes a circular arc with the fish entering the water at an angle of 45 degrees.  This approximate trajectory is circular instead of parabolic as in the case of a true ballistic trajectory.  However, this approach takes advantage of several primitive capabilities of Alice resulting in a smoother animation than is the case with the earlier trajectory program.

A rather long program

Although the code that actually creates the trajectory is very short, the entire  program shown in Listing 6 is rather long.  This results from the creation and animation of five similar bugs that fly around above the water as shown in Figure 8.  The bugs fly in a random manner, but one of the bugs has a predisposition to get closer and closer to the water.  When that bug lands on the water, the fish launches itself from some distance away and eats the bug.

You can download and play this world (see Resources).

An improved approximate trajectory program

The previous discussion of an approximate trajectory program was designed to be a lot of fun, but was short on mathematics and technical details.  Furthermore, some of the parameters used in the animation were designed to simply look good and were not based on mathematical accuracy.  Now it is time to step back and take a look at the mathematics involved and to show you how to compute the required parameters as a function of target distance and launch angle.

Implementing a parabolic arc in Alice

Recall that you learned earlier that the ballistic trajectory of a projectile under the influence of gravity (ignoring air resistance) is a parabolic arc.  However, Alice does not provide a primitive method for moving a projectile in a parabolic arc.  Therefore, it is necessary to write the code to move the projectile in short increments so that the overall shape of the trajectory is a parabolic arc.  This places a significant computational load on the computer and may cause the performance to be poor on some computers.

 
Limit launch angle to 45 degrees max
Note that for launch angles greater than 45 degrees, the circular arc produced by this program is a very poor approximation of a parabolic trajectory.

A reasonable approximation

Alice provides two primitive methods that, when used together, make it possible to move a projectile in a circular arc with very smooth animation on most computers.  The circular arc is a reasonable approximation of a parabolic arc, particularly when viewed as a three-dimensional animation.  In 3D, it is difficult to visually distinguish between the circular arc and a parabolic arc unless the viewer's line of sight is perpendicular to the plane of the arc.

Computing the arc length

In order to use the circular arc as an approximation of a parabolic trajectory, it is necessary to compute the length of the arc as a function of the launch angle and the distance to the target.  This program will show you how to do that.

Some screen shots

Before getting into the technical details, lets look as some screen shots taken from the program while it is running.  Figure 9 shows shows the projectile in the aiming phase during which the launch angle is being established.

Figure 9. Projectile aiming phase.
What are those objects?

For this program, the flashlight object on the left in Figure 9 represents the projectile.  The flashlight object on the right represents the target, and the vertical magician's wand on the left is there simply to mark the launching point of the projectile for later reference.

The projectile in flight

Figure 10 shows the projectile in flight.  In Figure 10, the projectile is tangent to an invisible circular arc that intersects the point where the wand intersects the white line on the left (the launching point) and also intersects the point where the target intersects the white line on the right.

Figure 10. Projectile in flight.
The center, radius, and chord of the circle

The center point of the circle (of which the circular arc is a part) is somewhere below the white line midway between the launching point and the target.  The radius of the circle is greater than the distance between the launching point and the target.

The segment of the white line that connects the launching point to the target is a chord of the circle.  The actual distance that the projectile must travel along the circular arc to reach the target is the arc length or length of the arc.

Projectile impact on target

Figure 11 shows a screen shot of the projectile after it has impacted the target.

Figure 11. Projectile impact on target.
The ideal case

Ideally the projectile, the target, and the white line would intersect at exactly the same point.  The fact that they don't probably indicates some computational inaccuracies in the evaluation and execution of the two statements shown in Figure 7.

The required parameters

In order to cause the projectile to impact the target for a given launch angle and target distance, the value of length shown in the first statement in Figure 7 must equal the arc length.  The turning angle in the second statement in Figure 7 must be twice the launch angle.

Formula for computing arc length

If we represent the distance between the launching point and the target to be a chord of the circle, and represent the launch angle as angle, we can compute the arc length using the formula given in Figure 12.

Figure 12. Formula for computing arc length.
arcLength = (pi * chord * angle)/(180 * sin(angle))

If you are familiar with trigonometry, you should be able to derive this formula on your own.  If not, just accept it as fact.

Behavior of the program

This program requests the target distance and the launch angle from the user.  Then it computes the arc length and causes the projectile to move in a circular arc to impact the target as shown in the screen shots of Figures 9, 10, and 11.

Remember, even though the projectile will impact the target for launch angles greater than 45 degrees, the trajectory produced by such launch angles is a very poor approximation of the parabolic trajectory of a ballistic missile.

You can demonstrate this by running the program with a target distance of eight meters and a launch angle of 120 degrees as shown by the screen shot in Figure 13.  In this case, the projectile is launched in the wrong direction but still impacts the target. 

Figure 13. Trajectory of a cruise missile.

You can download and run this program (see Resources).

Multiplication game

I recently received an email message from a man who was thinking about teaching his twelve-year old son how to program using Alice.  As an example of the kinds of programs that he might teach his son to write, he asked if Alice would be suitable for writing a simple game that can be used to teach a younger child how to learn their multiplication tables.  I responded in the affirmative and decided to write such a program myself and present it to my young grandchildren who will be learning their "times tables" in preschool this year.  A complete listing of the program is provided in Listing 2.  A downloadable version of the world is provided in Resources.

In retrospect ...
Considering the age of the students who will be playing the game, it may have been better to simplify the text in Figure 1.

Posing the multiplication problem

The program begins by presenting a multiplication problem to the student, expecting the student to enter the product of the two numbers in the text field as shown in Figure 1.

Figure 1. Presentation of multiplication problem to student.

A correct answer

If the student enters the correct answer, the program plays an audible moo sound, the cow moves her head up and down in an affirmative gesture, and the word Correct appears on the screen as shown in Figure 2.

Figure 2. Multiplication program output for correct answer.

An incorrect answer

If the student enters an incorrect answer:

Figure 3. Multiplication program output for incorrect answer.

A new multiplication problem

After a short time period, the program presents a new multiplication problem to the student as shown in Figure 1.  The student should enter a value of 1000 to terminate the program.

Not a game of Doom ...

For teenagers accustomed to modern video games, the behavior of this game is clearly very simplistic.  However, the behavior of this game was not intended for teenagers, it was intended for preschoolers.

Illustrates fundamental programming concepts

An examination of the code in Listing 2 will show that this simple program illustrates many fundamental programming concepts including types, variables, loops, relational operators, and if-else selection statements.  Therefore, while the behavior of the game may be simplistic, the structure of the program should be useful in teaching students (even teenagers) how to write Alice programs.

Addition game

Listing 3 provides the source code for an addition game based on the concepts explained for the multiplication game above.

Subtraction game

Listing 4 provides the source code for a subtraction game based on the concepts explained for the multiplication game above.

Drag race game

Listing 5 shows the source code for a drag race game.  Note that the first two events in Listing 5 should read as follows:

Unfortunately, the word mouse is not preserved in this source code listing format.

Drag race game at startup

Figure 4 shows an image of the game at startup.  Two cars are at the starting line with instructions to the user to click on a car to start the race.

Figure 4. Drag race game at startup.

By clicking a particular car, the player not only starts the race, but also predicts which car will win the race.

Drag race game during running of Christmas tree lights

From what I read, drag races are started by running a drag strip "Christmas tree" through several colors of lights with the green light being the signal to start moving down the track.

When the user clicks on one of the cars, a simulated drag strip "Christmas Tree" cycles through red, yellow, and green as shown by the yellow circle in Figure 5.

Figure 5. Drag race game during running of Christmas tree lights.
Go on green

When the Christmas tree turns green, the two cars start moving down the track.

A while loop and a random number generator are used to control the motion of each car.  During each iteration of the while loop, each car moves forward by a random distance ranging from 0.5 to 1.5 meters.

Crossing the finish line

When one (or both) car crosses the finish line during an iteration of the while loop, the loop terminates and the motion of both cars stops.  The winner is determined to be the car that went the greatest distance beyond the finish line before stopping as shown in Figure 6.

Figure 6. Drag race game at end of game.
And the winner is ...

The text at the bottom of Figure 6 shows which car won, and also shows whether or not the player correctly predicted the winner by clicking on the car that won the race.

Processing parameters and list items of type Object

Method parameters of type Object

When you define a new method, you can declare the method parameters to be any of the following types:

A parameter of type Object

If you need to pass the light object, the ground object, or any object that was created from the gallery to a method, you need to define the parameter in your method as type Object.

You can only pass objects that appear in the object tree or <None> to the method.  You cannot pass the world object to the method.

What can the code in the method do with the parameter?

The issue under discussion in this section centers on what the code in the method can do with the incoming parameter of type Object when the method is called and begins execution.

One of the things that the code in the method can do is to directly call any one of sixteen primitive methods on the parameter.

Another thing that the code in the method can do is to use the parameter to set the values for the following five properties:

Another thing that the code in the method can do is to set the value of the parameter so that it actually represents a different object from the object that was passed as a parameter when the method was called.

There is at least one other thing that the code in the method can do with the parameter that I will explain shortly.

What the code in the method cannot do with the parameter

One of the things that the code in the method cannot do is to use the parameter to directly call any of the custom methods belonging to the object that was passed as a parameter.  This is a serious restriction.  As you will see later, however, there is a way to at least partially work around this restriction.

A similar situation in Java?

In an attempt to put this situation in perspective, I am going to discuss and explain a similar situation in Java, which is the underlying language for Alice.

Java also contains a class named Object.  This class is the root of the entire class inheritance hierarchy.  The Object class defines eleven methods and no variables.  It is perfectly legal to pass an object's reference to a method as a parameter of type Object.  However, I often tell my students that when that is done there are only twelve things that the code in the method can do with the incoming parameter:

What is not possible?

It is not possible to use the method parameter of type Object in Java to call any of the methods defined in the class from which the object was instantiated (other than the eleven methods inherited from Object) without first using a cast operator to change the type of the parameter.

The mechanics of the cast operation

If the actual type of the incoming object reference is known when the program is written, it is a simple matter to cast it to the actual type of the object.

If the actual type of the incoming object reference is not known when the program is written, but it is known that the actual type is one of a finite number of possible types, it is possible to use the instanceof operator to determine the actual type of the object reference and to apply an appropriate cast operator to change the type of the reference to the actual type of the object at runtime.

Getting back to Alice...

Earlier in this document, I explained some of the things  that the code in an Alice method can do with an incoming parameter of type Object, and I promised to explain one other option later.  The time has come to explain that other option.

While there is no cast operator and no instanceof operator in Alice, it is possible to use the Alice equality operator (==) to determine if an incoming method parameter of type Object refers to a specific object.  This is illustrated in Listing 8 where a test is made to determine if the parameter named obj refers to an object named cow.

Listing 8. Testing an Object parameter for equality to a specific object.
  if ( ( obj == cow ) ) {
       cow.dance ( );
  } else {

Calling custom methods

If the parameter does refer to a specific object, code can then be written to call custom methods on that object.  In Listing 8, the custom method named dance is called on the cow object after determining that the method parameter refers to the cow object.

Similar to the use of instanceof in Java

Note that this is similar to, but different from using the instanceof operator in Java to determine the actual type of an incoming parameter before applying a cast operator followed by a call to a custom method.  The Java instanceof operator is used to determine if the incoming parameter is of a particular type (not to determine if the parameter refers to a specific object).  The Alice code in Listing 8 determines if the incoming parameter refers to a specific object.

Java approach is somewhat more general

Because objects can be created and destroyed at runtime in Java on the basis of many different runtime conditions, the Java programmer doesn't know about specific objects when the program is written.  Therefore, the Java programmer must deal with objects at the more general class level when resolving parameters of type Object.

All Alice objects are known to the programmer

However, all objects in an Alice world must be created when the program is written and before the program is run.  Therefore, the Alice programmer knows about the existence of every object in the Alice world.

Although it may be somewhat cumbersome, the Alice programmer can use code similar to that shown in Listing 8 to determine which of the objects in the world was actually passed as a parameter to the method, and can then call custom methods on that specific object in the body of the if-else statement.

A program named ObjectParameters01

Figure 14 shows a screen shot of a program named ObjectParameters01.

Figure 14. Screen shot from the program named ObjectParameters01.
In this program, the world was populated with a cow and two penguins.  A custom method named dance was defined for each of those three objects.  The behavior of the dance method belonging to each object is different from the behavior of the dance method belonging to the other two objects.

Program behavior

The main method calls a world method named makeObjectsDance four times in succession.  The first three calls to the method pass the cow and each of the two penguins as parameters of type Object.  The fourth call passes the ground as a parameter of type Object.

The makeObjectsDance  method

The makeObjectsDance method begins by calling the primitive turn method directly on the incoming parameter each time it is called.  This code is shown in Listing 10, which contains the entire program listing.  Nothing special is required to use the incoming parameter of type Object to call any of the sixteen primitive methods mentioned earlier.

Identifying the objects and calling the custom methods

Then the makeObjectsDance method uses the incoming parameter to identify the object that is referenced by the incoming parameter.  It calls the custom dance method on the cow and each of the two penguin objects after determining that those are the objects referred to by the incoming parameter of type Object.  This is shown by the code fragment in Listing 9.

Listing 9. Calling custom methods on a parameter of type.
  if ( ( obj == cow ) ) {
       cow.dance ( );
  } else {
    if ( ( obj == penguin1 ) ) {
       penguin1.dance ( );
  } else {
    if ( ( obj == penguin2 ) ) {
       penguin2.dance ( );
  } else {
    // Cause the parameter to point to the camera
  // instead of the ground. Note that the ground
  // was caused to turn at the beginning of this method.
  ground .say( No match. Make the parameter point to camera instead of ground. ); duration = 3 seconds
  obj .set( value , camera );
  obj .turn( LEFT , 1 revolution ); asSeenBy = cow
  }
  }
  }

The dance method belonging to each object causes the object to step forward, do a little dance, and then return to its position in the line.  The program also causes some text bubbles to appear on the screen to explain what is happening as the program executes.

Changing the value of the parameter

The last call to the makeObjectsDance method in the main method passes the ground object as a parameter of type Object.  This results in the final else clause in Listing 9 being executed.  The code in the else clause calls the set method on the incoming parameter to change its value.  Following the call to the the set method, the parameter refers to the camera instead of the ground, which was actually passed as a parameter.

Then the primitive turn method is called on the modified parameter.  This causes the camera (not the ground) to fly around the cow, making one complete revolution around the cow and ending up where it started.

List items of type Object

When you store objects in a list as type Object and later extract items from the list, you encounter a situation very similar to that discussed above regarding a parameter of type Object.  You cannot directly call custom methods on the list items when you extract them from the list.  However, you can use the same technique shown above to identify the object referenced by a list item and then call custom methods on that object.  This is illustrated by the program named ObjectListItem01, which is presented in Listing 11.

This program is very similar to the program named ObjectParameters01 that I explained above.  Therefore, the program named ObjectListItem01 shouldn't require further explanation.

You can download a zip file containing both of these programs (see Resources).

Programming Alice using 3D coordinates

To progress beyond Alice in 3D programming, students will need to get beyond thinking in terms of moving forward, backward, left, right, up, and down.  They will need to start thinking in terms of the 3D coordinates x, y, and z.  However, the methodology for programming using coordinates in Alice is somewhat obscure.  Furthermore, there is an apparent bug in Alice that makes programming using 3D coordinates even more complicated than it would otherwise need to be.

In this section, I will show you how to move an object to a new location in 3D space using either absolute or relative coordinates.  Movement in absolute coordinates refers to movement relative to the origin of the world.  Movement in relative coordinates refers to movement relative to the object's current position along each of the three axes in 3D space.  Unlike the use of the primitive move method, neither absolute nor relative movements depend on the current orientation of the object.  Also, the orientation of the object is not changed when the object is moved.

The program named Vector01

Listing 12 contains a complete listing of a program named Vector01.  I won't provide a screen shot for this program because all it would show is a penguin and a magician's wand in 3D space.  You need to run the program and view the animation to appreciate it.  See Resources for a link to download a zip file containing this program.

The purpose of this program is to illustrate the use of the following methods to move an object on the basis of 3D coordinates:

Behavior of the program

This program places the ground, a penguin,  and a magician's wand at the origin of the world.  The wand is used solely to provide a visual marker for the origin of the world when the penguin moves away from the origin.

The main method

The main method is shown in Listing 13.

Listing 13. The main method for Vector01.
  public void main ( ) {
    
       // Illustrates how to program in Alice using vectors.
  // Moves a penguin in 3D space using both absolute
  // and relative vectors.
  // Initialize the penguin to the origin.
  world.setTheStage ( );
  // Move penguin away from origin with absolute move.
  world.vectorMoveAbs ( obj = penguin , x = 3 , y = 2 , z = -1 , duration = 1 , style = 1 );
  wait( 1 second );
  // Move back to origin with absolute move.
  world.vectorMoveAbs ( obj = penguin , x = 0 , y = 0 , z = 0 , duration = 0.25 , style = 3 );
  wait( 1 second );
  // Move away from origin again with absolute move.
  world.vectorMoveAbs ( obj = penguin , x = -1 , y = 2 , z = 3 , duration = 1 , style = 4 );
  wait( 1 second );
  // Move back to origin in two relative moves with a pause in between.
  world.vectorMoveRel ( obj = penguin , x = 0.75 , y = -1 , z = -1 , duration = 3 , style = 1 );
  wait( 1 second );
  world.vectorMoveRel ( obj = penguin , x = 0.25 , y = -1 , z = -2 , duration = 1 , style = 2 );
  }

Making an absolute move

The program begins by setting the stage to cause the camera and the other objects to assume their initial positions.  Then it calls the method named vectorMoveAbs to cause the penguin to move to a position specified by the following coordinates:

x = 3, y = 2, z = 1

The duration and style of the move are controlled by parameters passed to the method.

Pause the action

Then the program pauses for one second to allow the user to visually absorb what has just happened.  (Pauses are inserted at several points during the running of the program for that purpose.)

Move back to the origin

Following the pause, the main method calls the vectorMoveAbs method again to cause the penguin to move back to the origin specified by the following coordinates:

x = 0, y = 0, z = 0

Another absolute move

Following another pause, the vectorMoveAbs method is called to cause the penguin to move to:

x = -1, y = 2, z = 3

Move relative

Then the vectorMoveRel method is called to cause the penguin to move by the following incremental amounts relative to its current position:

dx = 0.75, dy = -1, dz = -1

Another pause

This is followed by another pause.  Then the vectorMoveRel method is called again to cause the penguin to move by the following incremental amounts relative to its current position:

dx = 0.25, dy = -1, dz = -2

That relative move causes the penguin to end up back at the origin..

The vectorMoveAbs method

The method named vectorMoveAbs is shown in Listing 14.  The purpose of this method is to move an object to a position in 3D space specified by x, y, and z coordinates without changing the orientation of the object.

Listing 14. The method named vectorMoveAbs
  public void vectorMoveAbs ( Object obj, Number x, Number y, Number z, Number duration, Number style) {
    Posistion theVector = Vector3( 0, 0, 0 ) ;
       theVector .set( value , ( getVector( right = x , up = y , forward = z ) ) ); duration = 0 seconds
  if ( ( style == 1 ) ) { . . }
       obj .moveTo( world ); position of = theVector duration = duration seconds style = BEGIN_AND_END_GENTLY
  } else {
    if ( ( style == 2 ) ) {
       obj .moveTo( world ); position of = theVector duration = duration seconds style = BEGIN_GENTLY_AND_END_ABRUPTLY
  } else {
    if ( ( style == 3 ) ) {
       obj .moveTo( world ); position of = theVector duration = duration seconds style = BEGIN_ABRUPTLY_AND_END_GENTLY
  } else {
    obj .moveTo( world ); position of = theVector duration = duration seconds style = BEGIN_AND_END_ABRUPTLY
  }
  }
  }
  }

Dealing with the style

The most complicated thing about this method is the code required to handle the style (treatment at the beginning and the end of the move).  Had I been satisfied to accept the default style value for the moveTo method, the entire vectorAbsMove method would have consisted of only about three statements.

Map style to numeric values

It is not possible to declare a parameter of type style so that the user can pass the desired style directly to the vectorAbsMove method.  Therefore, it was necessary to map the four different style types into the following numeric values:

The nested if-else statements in Listing 14 test the value of the incoming style parameter and use that value to call the moveTo method with the corresponding style.

Method parameters

The vectorAbsMove method requires the following six incoming parameters:

Construct a vector and make the move

The incoming x, y,and z values are used to construct a vector, which is used in a subsequent call to the moveTo method to establish the position, (relative to the origin of the world), that the object will be moved to by the moveTo method.

The vectorMoveRel method

The method named vectorMoveRel is shown in Listing 15.  The purpose of this method is to move an object by an incremental amount in 3D space relative to its current position.  Values are specified for x, y, and z, which will cause the object to be moved by those incremental distances along the corresponding axes.  The orientation of the object is not changed.

Listing 15. The method named vectorMoveRel
  public void vectorMoveRel ( Object obj, Number x, Number y, Number z, Number duration, Number style) {
    Posistion currentVector = Vector3( 0, 0, 0 ) ; Number newX = 0 ; Number newY = 0 ; Number newZ = 0 ;
       currentVector .set( value , ( obj .getPosition() asSeenBy = world ) ); duration = 0 seconds
  newX .set( value , ( ( ( currentVector .getDistanceRight() ) + x ) ) ); duration = 0 seconds
  newY .set( value , ( ( ( currentVector .getDistanceUp() ) + y ) ) ); duration = 0 seconds
  newZ .set( value , ( ( ( currentVector .getDistanceForward() ) + z ) ) ); duration = 0 seconds
  world.vectorMoveAbs ( obj = obj , x = newX , y = newY , z = newZ , duration = duration , style = style );
  }

Method parameters

This method requires the following six parameters:

The method in action

The method begins by calling the getPosition method on the object to get its current absolute coordinates.  Then it uses those coordinates along with the incoming parameter values to compute a new set of absolute coordinates for the object.  Finally, it calls the vectorMoveAbs method described above to move the object.  Therefore, the vectorMoveRel method must have access to the vectorMoveAbs method to function properly.

As mentioned earlier, you will find a link in Resources to download a zip file containing this program.

Creating a library of reusable methods, functions, and constants

I have seen several postings on the Alice Community Forum asking how to save a method or function and use it in future programs.  One solution is to create and save a library class containing methods, functions, and properties.  It is a simple matter to save the class in the local gallery.  Then you can add an object of that class to future programs that need access to the methods, functions, and constants stored there.

The procedure for creating a library class

The procedure for creating a library class is as follows.  Choose the smallest class that you can find in the gallery.  The smallest class that I have been able to find in the gallery is a MagicianWand, which has a size of 9 kb.

Create an object from that class and add it to an Alice world.  Make the object invisible by setting its isShowing property to false.  Rename the object to Library in the object tree.

Create a folder (thumbnail) in the local gallery

Create a new folder named A-Custom on your hard disk with the following path:

C:\...\Alice\Required\gallery\A-Custom

This will create a new folder (thumbnail) in your local gallery in which you can store your new Library class and other new classes that you may create as well.

Create new methods, functions, and properties and save the class

Create new methods, functions, and properties for the Library object.  Once you have created and tested your methods, functions, and properties, right click on Library in the object tree.  Select save object... from the popup menu.  Follow the instructions to save your new class in the folder named A-Custom as described above.

The next time you start Alice, your new library class should appear in your local gallery in a thumbnail named A-Custom.

Updating the library

As time goes on, you can add new methods, functions, and properties to the class by:

Over time, you should be able to create a very useful collection of custom methods, functions, and properties.

Using methods, functions, and properties from the library

To use these custom methods, functions, and properties in a future program, simply create a new object of the Library class and add it to the new world. 

I can envision at least three different kinds of methods and functions that would be appropriate for saving in the Library class.

Methods and functions that apply to all objects...

Methods and functions that require an object as a parameter and can be applied to any object created from the gallery would be appropriate for including in the Library class.  The sample program named Library01 (see Listing 16) contains two such methods named vectorMoveAbs and vectorMoveRel(I developed and explained these two methods earlier in this lesson.)

Functions that apply to no object in particular...

Functions that don't apply to any object in particular but are similar to the primitive functions belonging to the world would also be appropriate for inclusion in the Library class.  See the function named degreesToRev in Listing 16 for example.  This function accepts an incoming parameter in degrees and returns a value in revolutions corresponding to that number of degrees.  (Recall that one revolution equals 360 degrees.)

Methods and functions that apply to a specific object

The methods and functions described above can be called directly on the Library object and are very convenient to use.  It may also be useful to include methods and functions in the Library class that apply to a specific object .  They would be less convenient to use, but would still be more convenient than re-writing them every time they are needed.  In this case, it would be necessary to use the Alice clipboard and copy the method or function from the Library object to some other object.

In this case, the Library class would serve simply as a convenient repository for saving a method that will need to be copied to another object later.  The ability to create an object of the Library class in the new world would facilitate the ability to copy the method or function to another object.  Once the method or function has been successfully copied to another object in the new world, the object of the Library class could be deleted from the world to reduce its overall memory requirements.

Library properties

The Library class is also useful for storing frequently used constants, such as the mathematical constant PI.  Curiously, there is no world function named PI or anything similar, although the value of PI can be easily obtained by calling the Math.toRadians method on the world passing 180 degrees as a parameter.  (I wonder how many Alice students are aware of the relationship between degrees and radians.)

The program named Library01

The program named Library01 demonstrates the use of a Library class containing:

The program doesn't demonstrate the use of methods or functions that must be copied to some other object as described above.

Listing 17 shows the main method for the program named Library01.

Listing 17. The main method for the program named Library01.
  public void main ( ) {
    
       // Demonstrates use of Library methods, functions, and constants.
  // Chicken was manually placed at the origin of the world.
  // -----------------------------------------------------
  // Print a constant that is stored in the Library object.
  print( ( Library.pi .toString() ) );
  // Move chicken away from origin using absolute coordinates.
  Library.vectorMoveAbs ( obj = Chicken , x = -1 , y = 2 , z = 3 , duration = 1 , style = 4 );
  // Move chicken back to origin in two incremental relative
  // moves with a turn in between.
  Library.vectorMoveRel ( obj = Chicken , x = 0.75 , y = -1 , z = -1 , duration = 3 , style = 1 );
  // Call a Library function to execute the 90-degree turn.
  Chicken .turn( LEFT , ( Library.degreesToRev ( degrees = 90 ) ) );
  Library.vectorMoveRel ( obj = Chicken , x = 0.25 , y = -1 , z = -2 , duration = 1 , style = 2 );
  }

Description of the program

You can download a zip file containing this program (see Resources).

The world initially consists of a chicken object that has been aligned with the pointOfView of the world.  In addition to the chicken, an invisible object of the class named Library was added to the world.

Behavior of the program

The program begins by printing the value of the Library property named Library.pi.

Then the program calls the library method named Library.vectorMoveAbs to move the chicken to a new position on the basis of the absolute coordinate values (-1, 2, 3).  The duration for the move is one second, and the style is specified as 4 using the mapping shown earlier.

Then the program calls the method named Library.vectorMoveRel to move the chicken to a new position on the basis of relative coordinate values (0.75, -1, -1).

Turn the chicken

Following that relative move, the program calls the library function named Library.degreesToRev to convert 90 degrees to revolutions and to pass that value as a parameter to the primitive turn method belonging to the chicken object.

Return to the origin of the world

Finally, the program once again calls the method named Library.vectorMoveRel to move the chicken to a new position on the basis of relative coordinate values (0.25, -1, -2).  When this move is completed, the chicken is back at its original position at the origin of the world, but the chicken has a different orientation.  It is no longer facing in the direction of the world's blue axis, but is now facing in the opposite direction from the world's red axis.

Run the programs

I encourage you to either download the zip file containing the programs, or copy the code from the listings into your Alice development environment and play the programs.  Experiment with the code, making changes, and observing the results of your changes.

Resources

General resources

Resources from earlier lessons in the series titled "Learn to Program using Alice"

Downloads

Complete program listings

Complete listings of the programs discussed in this lesson are shown below.

Listing 1. Two-dimensional projectile trajectory program.

Trajectory01's Code

Created by: Dick Baldwin

world

Events

When the world starts
Do:
world.main ( );


 

Methods

  public void main ( ) {
    Number v0x = 0 ; Number v0y = 0 ; Number angleInDegrees = 0 ; Number angleInRadians = 0 ;
       world.setTheStage ( );
  // Get and process user input
  angleInDegrees .set( value , ( NumberDialog( question = Angle in degrees? ) ) ); duration = 0 seconds
  angleInRadians .set( value , ( Math.toRadians( angleInDegrees ) ) ); duration = 0 seconds
  v0x .set( value , ( ( 10 * ( Math.cos( angleInRadians ) ) ) ) );
  v0y .set( value , ( ( 10 * ( Math.sin( angleInRadians ) ) ) ) );
  // Fire the projectile
  world.fireTheProjectile ( vx = v0x , vy = v0y );
  }


 
  public void setTheStage ( ) {
    
       doInOrder {
       ground .setPointOfView( world ); duration = 0 seconds
  safe .setPointOfView( world ); duration = 0 seconds
  safe .turn( LEFT , 0.25 revolutions ); duration = 0 seconds
  camera .setPointOfView( ground ); duration = 0 seconds
  camera .turn( RIGHT , 0.5 revolutions ); duration = 0 seconds
  camera .moveAwayFrom( target = safe , amount = 10 meters ); duration = 0 seconds
  camera .move( UP , .0001 meters ); duration = 0 seconds
  camera .move( BACKWARD , 10 meters ); duration = 0 seconds
  camera .move( RIGHT , 5 meters ); duration = 0 seconds
  }
  }


 
  public void fireTheProjectile ( Number vx, Number vy) {
    Number t = 0 ; Number x = 0 ; Number y = 0.01 ; Number deltaT = 0.01 ; Number tSquared = 0 ; Number g = 32 ; Number oldX = 0 ; Number oldY = 0 ; Number deltaX = 0 ; Number deltaY = 0 ;
       // Equations of motion
  doInOrder {
       // See http://hyperphysics.phy-astr.gsu.edu/hbase/traj.html#tra12
  // ax = 0
  // vx = v0x
  // x = v0x * t
  // ay = -g
  // vy = v0y - g * t
  // y = vy * t - 0.5 * g * t * t
  // g = 32 feet per second per second
  }
  // Action
  doInOrder {
       while ( ( y > 0 ) ) {
       t .set( value , ( ( t + deltaT ) ) ); duration = 0 seconds
  tSquared .set( value , ( ( t * t ) ) ); duration = 0 seconds
  oldX .set( value , x ); duration = 0 seconds
  x .set( value , ( ( t * vx ) ) ); duration = 0 seconds
  deltaX .set( value , ( ( x - oldX ) ) ); duration = 0 seconds
  oldY .set( value , y ); duration = 0 seconds
  y .set( value , ( ( t * ( ( vy - ( ( tSquared * ( ( g * 0.5 ) ) ) ) ) ) ) ) ); duration = 0 seconds
  deltaY .set( value , ( ( y - oldY ) ) ); duration = 0 seconds
  doTogether {
       safe .move( FORWARD , deltaX meters ); style = BEGIN_AND_END_ABRUPTLY duration = .01 seconds
  safe .move( UP , deltaY meters ); style = BEGIN_AND_END_ABRUPTLY duration = .01 seconds
  }
  }
  }
  }
 

 

Listing 2. Multiplication game program.

MultTables01's Code

Created by: Dick Baldwin

world

Events

When the world starts
Do:
world.main ( );


 

Methods

  public void main ( ) {
    Number multiplier = 0 ; Number multiplicand = 0 ; Number product = 0 ; Number answer = 0 ; String Question = Wht is ;
       // Simple multiplication game designed to teach
  // students their time tables up to 10 x 10.
  // Continue looping until the user enters 1000
  while ( ( answer != 1000 ) ) {
       multiplier .set( value , ( Random.nextDouble() minimum = 0 maximum = 10 integerOnly = true ) );
  multiplicand .set( value , ( Random.nextDouble() minimum = 0 maximum = 10 integerOnly = true ) );
  product .set( value , ( ( multiplier * multiplicand ) ) );
  Question .set( value , ( ( ( ( multiplier .toString() ) + times ) + ( multiplicand .toString() ) ) + = ? Enter 1000 to quit. ) );
  answer .set( value , ( NumberDialog( question = Question ) ) );
  if ( ( answer == product ) ) {
       doTogether {
       cow .say( Correct ); duration = 3 seconds
  cow .playSound( cow.moo (0:01.567) );
  doInOrder {
       cow.neck.head .turn( FORWARD , 0.12 revolutions );
  cow.neck.head .turn( BACKWARD , 0.25 revolutions );
  cow.neck.head .turn( FORWARD , 0.12 revolutions );
  }
  }
  } else {
    doTogether {
       // Note the mechanism used to force an integer to be displayed.
  cow .say( ( Wrong, the answer is + ( ( Random.nextDouble() minimum = product maximum = product integerOnly = true ) .toString() ) ) ); duration = 3 seconds
  cow .playSound( world.chicken (0:08.542) );
  doInOrder {
       cow.neck.head .turn( RIGHT , 0.12 revolutions );
  cow.neck.head .turn( LEFT , 0.25 revolutions );
  cow.neck.head .turn( RIGHT , 0.12 revolutions );
  }
  }
  }
  }
  }

 

Listing 3. Addition game program.

Addition01's Code

Created by: Dick Baldwin

world

Events

When the world starts
Do:
world.main ( );


 

Methods

  public void main ( ) {
    Number firstAddend = 0 ; Number secondAddend = 0 ; Number sum = 0 ; Number answer = 0 ; String Question = Wht is ;
       // Simple addition game designed to teach
  // students how to add positive numbers up to 10+10
  // Continue looping until the user enters 1000
  while ( ( answer != 1000 ) ) {
       firstAddend .set( value , ( Random.nextDouble() minimum = 0 maximum = 10 integerOnly = true ) );
  secondAddend .set( value , ( Random.nextDouble() minimum = 0 maximum = 10 integerOnly = true ) );
  sum .set( value , ( ( firstAddend + secondAddend ) ) );
  Question .set( value , ( ( ( ( firstAddend .toString() ) + + ) + ( secondAddend .toString() ) ) + = ? Enter 1000 to quit. ) );
  answer .set( value , ( NumberDialog( question = Question ) ) );
  if ( ( answer == sum ) ) {
       doTogether {
       cow .say( Correct ); duration = 3 seconds
  cow .playSound( cow.moo (0:01.567) );
  doInOrder {
       cow.neck.head .turn( FORWARD , 0.12 revolutions );
  cow.neck.head .turn( BACKWARD , 0.25 revolutions );
  cow.neck.head .turn( FORWARD , 0.12 revolutions );
  }
  }
  } else {
    doTogether {
       cow .say( ( Wrong, the answer is + ( ( Random.nextDouble() minimum = sum maximum = sum integerOnly = true ) .toString() ) ) ); duration = 3 seconds
  cow .playSound( world.chicken (0:08.542) );
  doInOrder {
       cow.neck.head .turn( RIGHT , 0.12 revolutions );
  cow.neck.head .turn( LEFT , 0.25 revolutions );
  cow.neck.head .turn( RIGHT , 0.12 revolutions );
  }
  }
  }
  }
  }

 

Listing 4. Subtraction game program.

Subtraction01's Code

Created by: Dick Baldwin

world

Events

When the world starts
Do:
world.main ( );


 

Methods

  public void main ( ) {
    Number minuend = 0 ; Number subtrahend = 0 ; Number diference = 0 ; Number answer = 0 ; String Question = Wht is ;
       // Simple subtraction game designed to teach
  // students how to subtract positive numbers up to 10 - 10
  // for positive answers only (no signed numbers)
  // Continue looping until the user enters 1000
  while ( ( answer != 1000 ) ) {
       minuend .set( value , ( Random.nextDouble() minimum = 1 maximum = 10 integerOnly = true ) );
  subtrahend .set( value , ( ( minuend + 1 ) ) );
  while ( ( minuend < subtrahend ) ) {
       subtrahend .set( value , ( Random.nextDouble() minimum = 0 maximum = 10 integerOnly = true ) );
  }
  diference .set( value , ( ( minuend - subtrahend ) ) );
  Question .set( value , ( ( ( ( minuend .toString() ) + - ) + ( subtrahend .toString() ) ) + = ? Enter 1000 to quit. ) );
  answer .set( value , ( NumberDialog( question = Question ) ) );
  if ( ( answer == diference ) ) {
       doTogether {
       cow .say( Correct ); duration = 3 seconds
  cow .playSound( cow.moo (0:01.567) );
  doInOrder {
       cow.neck.head .turn( FORWARD , 0.12 revolutions );
  cow.neck.head .turn( BACKWARD , 0.25 revolutions );
  cow.neck.head .turn( FORWARD , 0.12 revolutions );
  }
  }
  } else {
    doTogether {
       // Note the mechanism for forcing the output to be an integer.
  cow .say( ( Wrong, the answer is + ( ( Random.nextDouble() minimum = diference maximum = diference integerOnly = true ) .toString() ) ) ); duration = 3 seconds
  cow .playSound( world.chicken (0:08.542) );
  doInOrder {
       cow.neck.head .turn( RIGHT , 0.12 revolutions );
  cow.neck.head .turn( LEFT , 0.25 revolutions );
  cow.neck.head .turn( RIGHT , 0.12 revolutions );
  }
  }
  }
  }
  }

 

Listing 5. Drag race game program.

DragRace01's Code

Created by: Dick Baldwin

world

Events

When is clicked on redCar
Do:
world.red ( );


 
When is clicked on yellowCar
Do:
world.yellow ( );


 
When the world starts
Do:
world.main ( );


 

Methods

  public void runTheRace ( ) {
    Number trackLength = 0 ; Number redDistance = 0 ; Number yellowDistance = 0 ; Number maxDistance = 0 ; Number redIncrement = 0 ; Number yellowIncrement = 0 ;
       trackLength .set( value , ( subject = road .getWidth() ) );
  world.runTheChristmasTree ( );
  while ( ( maxDistance < ( ( trackLength - ( subject = redCar .getDepth() ) ) ) ) ) {
       // Update the variables.
  doInOrder { . . . . . }
       redIncrement .set( value , ( Random.nextDouble() minimum = 0.5 maximum = 1.5 ) ); duration = 0 seconds
  yellowIncrement .set( value , ( Random.nextDouble() minimum = 0.5 maximum = 1.5 ) ); duration = 0 seconds
  redDistance .set( value , ( ( redDistance + redIncrement ) ) ); duration = 0 seconds
  yellowDistance .set( value , ( ( yellowDistance + yellowIncrement ) ) ); duration = 0 seconds
  maxDistance .set( value , ( Math.max( redDistance , yellowDistance ) ) ); duration = 0 seconds
  }
  // Move the cars.
  doTogether { . . }
       redCar .move( FORWARD , redIncrement meters ); duration = .025 seconds style = BEGIN_AND_END_ABRUPTLY
  yellowCar .move( FORWARD , yellowIncrement meters ); duration = .025 seconds style = BEGIN_AND_END_ABRUPTLY
  }
  }
  // Determine the winner.
  if ( ( redDistance > yellowDistance ) ) { . . . . }
       print( Red wins );
  if ( ( world.pickedCar == redCar ) ) { . . }
       print( You win the bet. );
  } else {
    print( You lose the bet. );
  }
  } else {
    print( Yellow wins. );
  if ( ( world.pickedCar == yellowCar ) ) {
       print( You win the bet. );
  } else {
    print( You lose the bet. );
  }
  }
  }


 
  public void red ( ) {
    
       world.pickedCar .set( value , redCar );
  print( ----------You picked red. );
  world.runTheRace ( );
  }


 
  public void yellow ( ) {
    
       world.pickedCar .set( value , yellowCar );
  print( ----------You picked yellow. );
  world.runTheRace ( );
  }


 
  public void main ( ) {
    
       print( );
  print( Click on a car to start the race. );
  }


 
  public void runTheChristmasTree ( ) {
    
       doInOrder {
       // Run the lights to start the race.
  circle .set( isShowing , true ); duration = 0 seconds
  wait( 1 second );
  circle .set( color , (1, 1, 0) );
  wait( 1 second );
  circle .set( color , (0, 1, 0) ); duration = 0 seconds
  }
  }

 

Listing 6. Approximate trajectory program.

JumpingFish01's Code

Created by: Dick Baldwin

world

Events

When the world starts
Do:
world.main ( );


 

Methods

  public void main ( ) {
    
       world.setTheStage ( );
  doTogether {
       bug2.fly ( );
  bug3.fly ( );
  bug4.fly ( );
  bug5.fly ( );
  mainBug.fly ( );
  }
  }


 
  public void setTheStage ( ) {
    
       // Set size and initial location of the fish and the camera.
  fish .resize( 4 ); duration = 0 seconds
  water .setPointOfView( world ); duration = 0 seconds
  fish .setPointOfView( water ); duration = 0 seconds
  camera .setPointOfView( water ); duration = 0 seconds
  camera .turn( RIGHT , 0.25 revolutions ); duration = 0 seconds
  camera .move( FORWARD , 20 meters ); duration = 0 seconds
  camera .move( UP , 1 meter ); duration = 0 seconds
  camera .pointAt( fish ); duration = 0 seconds
  camera .move( LEFT , 2 meters ); duration = 0 seconds
  water .set( isShowing , true );
  }


 

fish

Methods

  public void jump ( ) {
    Number azimuthInRadians = 0 ; Number length = 0 ;
       doInOrder {
       // Compute the horizontal azimuth to the bug.
  azimuthInRadians .set( value , ( Math.atan( ( ( world.zCoor / world.xCoor ) ) ) ) ); duration = 0 seconds
  if ( ( world.xCoor < 0 ) ) {
       azimuthInRadians .set( value , ( ( azimuthInRadians + 3.14 ) ) ); duration = 0 seconds
  } else {
  Do Nothing
  }
  length .set( value , ( ( ( ( world.xCoor / ( Math.cos( azimuthInRadians ) ) ) ) + ( subject = mainBug .getDepth() ) ) ) ); duration = 0 seconds
  fish .turn( LEFT , ( ( ( ( azimuthInRadians / 2 ) ) / 3.14 ) ) ); duration = 0 seconds
  }
  doInOrder {
       // Set vertical launch angle and make the fish visible.
  fish .turn( BACKWARD , .125 revolutions ); duration = 0 seconds
  fish .set( isShowing , true ); duration = 0 seconds style = BEGIN_AND_END_ABRUPTLY
  doTogether {
       doTogether {
       mainBug.leftWing .roll( LEFT , 0.25 revolutions ); duration = .25 seconds style = BEGIN_AND_END_ABRUPTLY
  mainBug.rightWing .roll( RIGHT , 0.25 revolutions ); duration = 0.25 seconds style = BEGIN_AND_END_ABRUPTLY
  }
  doTogether {
       mainBug.leftWing .roll( RIGHT , .375 revolutions ); duration = 0.25 seconds style = BEGIN_AND_END_ABRUPTLY
  mainBug.rightWing .roll( LEFT , 0.38 revolutions ); duration = 0.25 seconds style = BEGIN_AND_END_ABRUPTLY
  }
  // This code approximates the trajectory of a projectile.
  fish .move( FORWARD , length meters ); style = BEGIN_AND_END_ABRUPTLY duration = 2.5 seconds
  fish .turn( FORWARD , 0.25 revolutions ); style = BEGIN_AND_END_ABRUPTLY duration = 2.5 seconds
  }
  doTogether {
       // Make the bug and the fish disappear under the water.
  mainBug .set( isShowing , false ); duration = 0 seconds style = BEGIN_AND_END_ABRUPTLY
  fish .move( FORWARD , 4 meters ); duration = 0.25 seconds style = BEGIN_AND_END_ABRUPTLY
  }
  }
  }


 

mainBug

Methods

  public void fly ( ) {
    Number xInc = 0 ; Number yInc = 0 ; Number zInc = 0 ; Number height = 2 ; Number turnAngle = 0.25 ;
       doInOrder {
       // Initialize the bug's size and location
  mainBug .resize( 20 ); duration = 0 seconds
  mainBug .setPointOfView( water ); duration = 0 seconds
  mainBug .move( FORWARD , xCoor meters ); duration = 0 seconds
  mainBug .move( LEFT , zCoor meters ); duration = 0 seconds
  mainBug .move( UP , 2 meters ); duration = 0 seconds
  mainBug .set( isShowing , true ); duration = 0 seconds
  }
  while ( ( height > 0.1 ) ) {
       // Make bug move randomly and flap wings.
  // Bug ends up landing on the water
  doInOrder {
       xInc .set( value , ( Random.nextDouble() minimum = -0.5 maximum = 0.5 ) ); duration = 0 seconds
  zInc .set( value , ( Random.nextDouble() minimum = -0.5 maximum = 0.5 ) ); duration = 0 seconds
  yInc .set( value , ( Random.nextDouble() minimum = 0.05 maximum = 0.2 ) ); duration = 0 seconds
  turnAngle .set( value , ( Random.nextDouble() minimum = -0.25 maximum = 0.25 ) ); duration = 0 seconds
  world.xCoor .set( value , ( ( world.xCoor + xInc ) ) ); duration = 0 seconds
  world.zCoor .set( value , ( ( world.zCoor + zInc ) ) ); duration = 0 seconds
  height .set( value , ( ( height - yInc ) ) ); duration = 0 seconds
  }
  doTogether {
       doInOrder {
       doTogether {
       mainBug.leftWing .roll( LEFT , 0.25 revolutions ); ( Random.nextDouble() minimum = 0.5 maximum = 0.6 ) style = BEGIN_AND_END_ABRUPTLY
  mainBug.rightWing .roll( RIGHT , 0.25 revolutions ); ( Random.nextDouble() minimum = 0.5 maximum = 0.6 ) style = BEGIN_AND_END_ABRUPTLY
  }
  doTogether {
       mainBug.leftWing .roll( RIGHT , 0.25 revolutions ); ( Random.nextDouble() minimum = 0.5 maximum = 0.6 ) style = BEGIN_AND_END_ABRUPTLY
  mainBug.rightWing .roll( LEFT , 0.25 revolutions ); ( Random.nextDouble() minimum = 0.5 maximum = 0.6 ) style = BEGIN_AND_END_ABRUPTLY
  }
  }
  doTogether {
       mainBug .move( FORWARD , xInc meters ); style = BEGIN_AND_END_ABRUPTLY asSeenBy = water
  mainBug .move( LEFT , zInc meters ); asSeenBy = water style = BEGIN_AND_END_ABRUPTLY
  mainBug .move( DOWN , yInc meters ); asSeenBy = water style = BEGIN_AND_END_ABRUPTLY
  mainBug .turn( RIGHT , turnAngle revolutions ); duration = 1 second
  }
  }
  }
  fish.jump ( );
  }


 

bug2

Methods

  public void fly ( ) {
    Number xInc = 0 ; Number yInc = 0 ; Number zInc = 0 ; Number height = 2 ; Number turnAngle = 0.25 ;
       doInOrder {
       // Initialize the bug's size and location
  wait( ( Random.nextDouble() minimum = 0.1 maximum = 2 ) );
  bug2 .resize( 20 ); duration = 0 seconds
  bug2 .setPointOfView( water ); duration = 0 seconds
  bug2 .move( FORWARD , ( Random.nextDouble() minimum = -1 maximum = -3 ) ); duration = 0 seconds
  bug2 .move( LEFT , ( Random.nextDouble() minimum = -12 maximum = -14 ) ); duration = 0 seconds
  bug2 .move( UP , ( Random.nextDouble() minimum = 0.5 maximum = 2 ) ); duration = 0 seconds
  bug2 .set( isShowing , true ); duration = 0 seconds
  }
  while ( ( height > 0.1 ) ) {
       // Make bug move randomly and flap wings.
  // Bug ends up landing on the water
  doInOrder {
       xInc .set( value , ( Random.nextDouble() minimum = -0.5 maximum = 0.5 ) ); duration = 0 seconds
  zInc .set( value , ( Random.nextDouble() minimum = -0.5 maximum = 0.5 ) ); duration = 0 seconds
  yInc .set( value , ( Random.nextDouble() minimum = -0.2 maximum = 0.2 ) ); duration = 0 seconds
  turnAngle .set( value , ( Random.nextDouble() minimum = -0.25 maximum = 0.25 ) ); duration = 0 seconds
  world.xCoor .set( value , ( ( world.xCoor + xInc ) ) ); duration = 0 seconds
  world.zCoor .set( value , ( ( world.zCoor + zInc ) ) ); duration = 0 seconds
  height .set( value , ( ( height - yInc ) ) ); duration = 0 seconds
  }
  doTogether {
       doInOrder {
       doTogether {
       bug2.leftWing .roll( LEFT , 0.25 revolutions ); ( Random.nextDouble() minimum = 0.5 maximum = 0.6 ) style = BEGIN_AND_END_ABRUPTLY
  bug2.rightWing .roll( RIGHT , 0.25 revolutions ); ( Random.nextDouble() minimum = 0.5 maximum = 0.6 ) style = BEGIN_AND_END_ABRUPTLY
  }
  doTogether {
       bug2.leftWing .roll( RIGHT , 0.25 revolutions ); ( Random.nextDouble() minimum = 0.5 maximum = 0.6 ) style = BEGIN_AND_END_ABRUPTLY
  bug2.rightWing .roll( LEFT , 0.25 revolutions ); ( Random.nextDouble() minimum = 0.5 maximum = 0.6 ) style = BEGIN_AND_END_ABRUPTLY
  }
  }
  doTogether {
       bug2 .move( FORWARD , xInc meters ); style = BEGIN_AND_END_ABRUPTLY asSeenBy = water
  bug2 .move( LEFT , zInc meters ); asSeenBy = water style = BEGIN_AND_END_ABRUPTLY
  bug2 .move( DOWN , yInc meters ); asSeenBy = water style = BEGIN_AND_END_ABRUPTLY
  bug2 .turn( RIGHT , turnAngle revolutions ); duration = 1 second
  }
  }
  }
  }


 

bug3

Methods

  public void fly ( ) {
    Number xInc = 0 ; Number yInc = 0 ; Number zInc = 0 ; Number height = 2 ; Number turnAngle = 0.25 ;
       doInOrder {
       // Initialize the bug's size and location
  wait( ( Random.nextDouble() minimum = 0.1 maximum = 2 ) );
  bug3 .resize( 20 ); duration = 0 seconds
  bug3 .setPointOfView( water ); duration = 0 seconds
  bug3 .move( FORWARD , ( Random.nextDouble() minimum = -1 maximum = -3 ) ); duration = 0 seconds
  bug3 .move( LEFT , ( Random.nextDouble() minimum = -12 maximum = -14 ) ); duration = 0 seconds
  bug3 .move( UP , ( Random.nextDouble() minimum = 0.5 maximum = 2 ) ); duration = 0 seconds
  bug3 .set( isShowing , true ); duration = 0 seconds
  }
  while ( ( height > 0.1 ) ) {
       // Make bug move randomly and flap wings.
  // Bug ends up landing on the water
  doInOrder {
       xInc .set( value , ( Random.nextDouble() minimum = -0.5 maximum = 0.5 ) ); duration = 0 seconds
  zInc .set( value , ( Random.nextDouble() minimum = -0.5 maximum = 0.5 ) ); duration = 0 seconds
  yInc .set( value , ( Random.nextDouble() minimum = -0.2 maximum = 0.2 ) ); duration = 0 seconds
  turnAngle .set( value , ( Random.nextDouble() minimum = -0.25 maximum = 0.25 ) ); duration = 0 seconds
  world.xCoor .set( value , ( ( world.xCoor + xInc ) ) ); duration = 0 seconds
  world.zCoor .set( value , ( ( world.zCoor + zInc ) ) ); duration = 0 seconds
  height .set( value , ( ( height - yInc ) ) ); duration = 0 seconds
  }
  doTogether {
       doInOrder {
       doTogether {
       bug3.leftWing .roll( LEFT , 0.25 revolutions ); ( Random.nextDouble() minimum = 0.5 maximum = 0.6 ) style = BEGIN_AND_END_ABRUPTLY
  bug3.rightWing .roll( RIGHT , 0.25 revolutions ); ( Random.nextDouble() minimum = 0.5 maximum = 0.6 ) style = BEGIN_AND_END_ABRUPTLY
  }
  doTogether {
       bug3.leftWing .roll( RIGHT , 0.25 revolutions ); ( Random.nextDouble() minimum = 0.5 maximum = 0.6 ) style = BEGIN_AND_END_ABRUPTLY
  bug3.rightWing .roll( LEFT , 0.25 revolutions ); ( Random.nextDouble() minimum = 0.5 maximum = 0.6 ) style = BEGIN_AND_END_ABRUPTLY
  }
  }
  doTogether {
       bug3 .move( FORWARD , xInc meters ); style = BEGIN_AND_END_ABRUPTLY asSeenBy = water
  bug3 .move( LEFT , zInc meters ); asSeenBy = water style = BEGIN_AND_END_ABRUPTLY
  bug3 .move( DOWN , yInc meters ); asSeenBy = water style = BEGIN_AND_END_ABRUPTLY
  bug3 .turn( RIGHT , turnAngle revolutions ); duration = 1 second
  }
  }
  }
  }


 

bug4

Methods

  public void fly ( ) {
    Number xInc = 0 ; Number yInc = 0 ; Number zInc = 0 ; Number height = 2 ; Number turnAngle = 0.25 ;
       doInOrder {
       // Initialize the bug's size and location
  wait( ( Random.nextDouble() minimum = 0.1 maximum = 2 ) );
  bug4 .resize( 20 ); duration = 0 seconds
  bug4 .setPointOfView( water ); duration = 0 seconds
  bug4 .move( FORWARD , ( Random.nextDouble() minimum = -1 maximum = -3 ) ); duration = 0 seconds
  bug4 .move( LEFT , ( Random.nextDouble() minimum = -12 maximum = -14 ) ); duration = 0 seconds
  bug4 .move( UP , ( Random.nextDouble() minimum = 0.5 maximum = 2 ) ); duration = 0 seconds
  bug4 .set( isShowing , true ); duration = 0 seconds
  }
  while ( ( height > 0.1 ) ) {
       // Make bug move randomly and flap wings.
  // Bug ends up landing on the water
  doInOrder {
       xInc .set( value , ( Random.nextDouble() minimum = -0.5 maximum = 0.5 ) ); duration = 0 seconds
  zInc .set( value , ( Random.nextDouble() minimum = -0.5 maximum = 0.5 ) ); duration = 0 seconds
  yInc .set( value , ( Random.nextDouble() minimum = -0.2 maximum = 0.2 ) ); duration = 0 seconds
  turnAngle .set( value , ( Random.nextDouble() minimum = -0.25 maximum = 0.25 ) ); duration = 0 seconds
  world.xCoor .set( value , ( ( world.xCoor + xInc ) ) ); duration = 0 seconds
  world.zCoor .set( value , ( ( world.zCoor + zInc ) ) ); duration = 0 seconds
  height .set( value , ( ( height - yInc ) ) ); duration = 0 seconds
  }
  doTogether {
       doInOrder {
       doTogether {
       bug4.leftWing .roll( LEFT , 0.25 revolutions ); ( Random.nextDouble() minimum = 0.5 maximum = 0.6 ) style = BEGIN_AND_END_ABRUPTLY
  bug4.rightWing .roll( RIGHT , 0.25 revolutions ); ( Random.nextDouble() minimum = 0.5 maximum = 0.6 ) style = BEGIN_AND_END_ABRUPTLY
  }
  doTogether {
       bug4.leftWing .roll( RIGHT , 0.25 revolutions ); ( Random.nextDouble() minimum = 0.5 maximum = 0.6 ) style = BEGIN_AND_END_ABRUPTLY
  bug4.rightWing .roll( LEFT , 0.25 revolutions ); ( Random.nextDouble() minimum = 0.5 maximum = 0.6 ) style = BEGIN_AND_END_ABRUPTLY
  }
  }
  doTogether {
       bug4 .move( FORWARD , xInc meters ); style = BEGIN_AND_END_ABRUPTLY asSeenBy = water
  bug4 .move( LEFT , zInc meters ); asSeenBy = water style = BEGIN_AND_END_ABRUPTLY
  bug4 .move( DOWN , yInc meters ); asSeenBy = water style = BEGIN_AND_END_ABRUPTLY
  bug4 .turn( RIGHT , turnAngle revolutions ); duration = 1 second
  }
  }
  }
  }


 

bug5

Methods

  public void fly ( ) {
    Number xInc = 0 ; Number yInc = 0 ; Number zInc = 0 ; Number height = 2 ; Number turnAngle = 0.25 ;
       doInOrder {
       // Initialize the bug's size and location
  wait( ( Random.nextDouble() minimum = 0.1 maximum = 2 ) );
  bug5 .resize( 20 ); duration = 0 seconds
  bug5 .setPointOfView( water ); duration = 0 seconds
  bug5 .move( FORWARD , ( Random.nextDouble() minimum = -1 maximum = -3 ) ); duration = 0 seconds
  bug5 .move( LEFT , ( Random.nextDouble() minimum = -12 maximum = -14 ) ); duration = 0 seconds
  bug5 .move( UP , ( Random.nextDouble() minimum = 0.5 maximum = 2 ) ); duration = 0 seconds
  bug5 .set( isShowing , true ); duration = 0 seconds
  }
  while ( ( height > 0.1 ) ) {
       // Make bug move randomly and flap wings.
  // Bug ends up landing on the water
  doInOrder {
       xInc .set( value , ( Random.nextDouble() minimum = -0.5 maximum = 0.5 ) ); duration = 0 seconds
  zInc .set( value , ( Random.nextDouble() minimum = -0.5 maximum = 0.5 ) ); duration = 0 seconds
  yInc .set( value , ( Random.nextDouble() minimum = -0.2 maximum = 0.2 ) ); duration = 0 seconds
  turnAngle .set( value , ( Random.nextDouble() minimum = -0.25 maximum = 0.25 ) ); duration = 0 seconds
  world.xCoor .set( value , ( ( world.xCoor + xInc ) ) ); duration = 0 seconds
  world.zCoor .set( value , ( ( world.zCoor + zInc ) ) ); duration = 0 seconds
  height .set( value , ( ( height - yInc ) ) ); duration = 0 seconds
  }
  doTogether {
       doInOrder {
       doTogether {
       bug5.leftWing .roll( LEFT , 0.25 revolutions ); ( Random.nextDouble() minimum = 0.5 maximum = 0.6 ) style = BEGIN_AND_END_ABRUPTLY
  bug5.rightWing .roll( RIGHT , 0.25 revolutions ); ( Random.nextDouble() minimum = 0.5 maximum = 0.6 ) style = BEGIN_AND_END_ABRUPTLY
  }
  doTogether {
       bug5.leftWing .roll( RIGHT , 0.25 revolutions ); ( Random.nextDouble() minimum = 0.5 maximum = 0.6 ) style = BEGIN_AND_END_ABRUPTLY
  bug5.rightWing .roll( LEFT , 0.25 revolutions ); ( Random.nextDouble() minimum = 0.5 maximum = 0.6 ) style = BEGIN_AND_END_ABRUPTLY
  }
  }
  doTogether {
       bug5 .move( FORWARD , xInc meters ); style = BEGIN_AND_END_ABRUPTLY asSeenBy = water
  bug5 .move( LEFT , zInc meters ); asSeenBy = water style = BEGIN_AND_END_ABRUPTLY
  bug5 .move( DOWN , yInc meters ); asSeenBy = water style = BEGIN_AND_END_ABRUPTLY
  bug5 .turn( RIGHT , turnAngle revolutions ); duration = 1 second
  }
  }
  }
  }

 

Listing 7. An improved approximate trajectory program.

Trajectory02's Code

Created by: Dick Baldwin

world

Events

When the world starts
Do:
world.main ( );


 

Methods

  public void main ( ) {
    
       // Executes a circular arc trajectory given the launch angle
  // and the distance to the target as user input values.
  world.setTheStage ( );
  projectile.fly ( );
  }


 
  public void setTheStage ( ) {
    
       // Move all objects to the origin in 3D space.
  doInOrder { . . . . . }
       ground .setPointOfView( world ); duration = 0 seconds
  camera .setPointOfView( ground ); duration = 0 seconds
  projectile .setPointOfView( ground ); duration = 0 seconds
  target .setPointOfView( ground ); duration = 0 seconds
  startPointMarker .setPointOfView( ground ); duration = 0 seconds
  }
  // Position the camera.
  doInOrder { . . . }
       camera .turn( LEFT , 0.25 revolutions ); duration = 0 seconds
  camera .moveAwayFrom( target = ground , amount = 20 meters ); duration = 0 seconds
  camera .move( UP , .0001 meters ); duration = 0 seconds
  }
  // Make miscellaneous adjustments to objects.
  doInOrder {
       projectile .resize( 2 ); duration = 0 seconds
  target .resize( 2 ); duration = 0 seconds
  startPointMarker .resize( 3 ); duration = 0 seconds
  startPointMarker .move( DOWN , ( ( ( subject = startPointMarker .getHeight() ) / 2 ) ) ); duration = 0 seconds
  }
  }


 

projectile

Methods

  public void fly ( ) {
    Number pi = 0 ; Number chord = 0 ; Number angle = 0 ; Number arcLength = 0 ;
       // arcLength = (pi*chord*angle)/(180*sin(angle))
  // Note, the distance to the target is the chord.
  // The distance to move is the arcLength.
  // Get user input.
  doInOrder { . . }
       chord .set( value , ( NumberDialog( question = Distance to target: ) ) );
  angle .set( value , ( NumberDialog( question = Launch angle in degrees: ) ) );
  }
  // Put objects into position.
  doInOrder {
       // Stand target upright and move into position.
  target .turn( BACKWARD , 0.25 revolutions ); duration = 0 seconds
  target .move( FORWARD , ( ( chord / 2 ) ) ); duration = 0 seconds asSeenBy = ground
  target .set( isShowing , true ); duration = 0 seconds
  // Move projectile into position.
  projectile .move( BACKWARD , ( ( chord / 2 ) ) ); duration = 0 seconds asSeenBy = ground
  projectile .set( isShowing , true ); duration = 0 seconds
  // Move startPointMarker into position.
  startPointMarker .move( BACKWARD , ( ( chord / 2 ) ) ); duration = 0 seconds
  startPointMarker .set( isShowing , true );
  }
  // Aim projectile and compute fire control solution.
  doInOrder {
       projectile .turn( BACKWARD , ( ( angle / 360 ) ) ); duration = 2 seconds
  // Get the value of pi.
  pi .set( value , ( Math.toRadians( 180 ) ) ); duration = 0 seconds
  arcLength .set( value , ( ( pi * ( ( ( ( chord * angle ) ) / ( ( 180 * ( Math.sin( ( Math.toRadians( angle ) ) ) ) ) ) ) ) ) ) );
  }
  // Fire the projectile.
  doTogether {
       // The following two statements produce the projectile motion.
  projectile .move( FORWARD , arcLength meters ); duration = 2 seconds
  projectile .turn( FORWARD , ( ( 2 * ( ( angle / 360 ) ) ) ) ); duration = 2 seconds
  }
  }

 

Listing 10. The program named ObjectParameters01.

ObjectParameters01's Code

Created by: Dick Baldwin

world

Events

When the world starts
Do:
world.main ( );


 

Methods

  public void main ( ) {
    
       // The purpose of this program is to show how to
  // call custom methods on method parameters of
  // type Object. Also shows how to cause Object parameter
  // to point to a different object than the one passed
  // as a parameter by the calling method.
  world.setTheStage ( );
  // Call the same method once for each of four objects.
  // This method will call a primitive method and a custom method
  // on the first three objects passed as a parameter. It will cause the
  // received parameter to point to a different object in the last call.
  world.makeObjectsDance ( obj = cow );
  world.makeObjectsDance ( obj = penguin1 );
  world.makeObjectsDance ( obj = penguin2 );
  world.makeObjectsDance ( obj = ground );
  }


 
  public void setTheStage ( ) {
    
       ground .setPointOfView( world ); duration = 0 seconds
  cow .setPointOfView( ground ); duration = 0 seconds
  cow .move( RIGHT , 1 meter ); duration = 0 seconds
  penguin1 .setPointOfView( ground ); duration = 0 seconds
  penguin1 .move( LEFT , 1 meter ); duration = 0 seconds
  penguin2 .setPointOfView( ground ); duration = 0 seconds
  penguin2 .move( LEFT , 2 meters ); duration = 0 seconds
  camera .setPointOfView( ground ); duration = 0 seconds
  camera .turn( LEFT , 0.5 revolutions ); duration = 0 seconds
  camera .move( BACKWARD , 10 meters ); duration = 0 seconds
  camera .move( UP , 3 meters ); duration = 0 seconds
  camera .move( RIGHT , 3 meters ); duration = 0 seconds
  camera .pointAt( ground ); duration = 0 seconds
  }


 
  public void makeObjectsDance ( Object obj) {
    
       // Call a primitive method on the incoming object.
  ground .say( Call primitive turn method on incoming parameter. ); duration = 3 seconds
  obj .turn( RIGHT , 1 revolution );
  // Identify the specific object and call a custom
  // method on that object.
  ground .say( Identify the specific object and call a custom method on that object. ); duration = 3 seconds
  if ( ( obj == cow ) ) {
       cow.dance ( );
  } else {
    if ( ( obj == penguin1 ) ) {
       penguin1.dance ( );
  } else {
    if ( ( obj == penguin2 ) ) {
       penguin2.dance ( );
  } else {
    // Cause the parameter to point to the camera
  // instead of the ground. Note that the ground
  // was caused to turn at the beginning of this method.
  ground .say( No match. Make the parameter point to camera instead of ground. ); duration = 3 seconds
  obj .set( value , camera );
  obj .turn( LEFT , 1 revolution ); asSeenBy = cow
  }
  }
  }
  }


 

cow

Methods

  public void dance ( ) {
    
       cow.walk ( times = 3 , speed = 3 );
  cow .turn( RIGHT , 0.5 revolutions );
  cow.tailSwish ( times = 5 , speed = 3 );
  cow.walk ( times = 3 , speed = 3 );
  cow .turn( LEFT , 0.5 revolutions );
  }


 

penguin1

Methods

  public void dance ( ) {
    
       // Note that the behavior of this dance method
  // is a little different from the behavior of the
  // dance method belonging to penguin2.
  penguin1.walking ( x = 2 );
  penguin1.turn_head_left ( );
  penguin1.turn_head_right ( );
  penguin1.wing_flap ( times = 2 );
  penguin1 .turn( LEFT , 0.5 revolutions );
  penguin1.walking ( x = 2 );
  penguin1 .turn( LEFT , 0.5 revolutions );
  }


 

penguin2

Methods

  public void dance ( ) {
    
       // Note that the behavior of this dance method
  // is a little different from the dance method
  // belonging to the penguin1 object.
  penguin2.walking ( x = 2 );
  penguin2.wing_flap ( times = 2 );
  penguin2.jumping ( height = 1 );
  penguin2 .turn( LEFT , 0.5 revolutions );
  penguin2.walking ( x = 2 );
  penguin2 .turn( LEFT , 0.5 revolutions );
  }

 

Listing 11. The program named ObjectListItem01.

ObjectListItem01's Code

Created by: Dick Baldwin

world

Events

When the world starts
Do:
world.main ( );


 

Methods

  public void main ( ) {
    Object[] myList = ;
       // The purpose of this program is to show how to
  // call custom methods on objects stored in a list
  // as type Object.
  world.setTheStage ( );
  world.iterateTheList ( myList = myList );
  }


 
  public void setTheStage ( ) {
    
       ground .setPointOfView( world ); duration = 0 seconds
  cow .setPointOfView( ground ); duration = 0 seconds
  cow .move( RIGHT , 1 meter ); duration = 0 seconds
  penguin1 .setPointOfView( ground ); duration = 0 seconds
  penguin1 .move( LEFT , 1 meter ); duration = 0 seconds
  penguin2 .setPointOfView( ground ); duration = 0 seconds
  penguin2 .move( LEFT , 2 meters ); duration = 0 seconds
  camera .setPointOfView( ground ); duration = 0 seconds
  camera .turn( LEFT , 0.5 revolutions ); duration = 0 seconds
  camera .move( BACKWARD , 10 meters ); duration = 0 seconds
  camera .move( UP , 3 meters ); duration = 0 seconds
  camera .move( RIGHT , 3 meters ); duration = 0 seconds
  camera .pointAt( ground ); duration = 0 seconds
  }


 
  public void iterateTheList ( Object[] myList) {
    
       doInOrder {
       // Iterate the list, calling the same method during each
  // iteration, passing the next object in the list to the method
  // each time the method is called.
  // This method will call a primitive method and a custom method
  // on the first three objects in the list. It will cause the
  // fourth item in the list to point to a different object than the
  // object originally stored in the list.
  }
  For all myList , one item_from_myList at a time {
       // Call a primitive method on the incoming object.
  ground .say( Call primitive turn method on list item. ); duration = 3 seconds
  item_from_myList .turn( RIGHT , 1 revolution );
  // Identify the specific object and call a custom
  // method on that object.
  ground .say( Identify the specific object and call a custom method on that object. ); duration = 3 seconds
  if ( ( item_from_myList == cow ) ) {
       cow.dance ( );
  } else {
    if ( ( item_from_myList == penguin1 ) ) {
       penguin1.dance ( );
  } else {
    if ( ( item_from_myList == penguin2 ) ) {
       penguin2.dance ( );
  } else {
    // Cause the parameter to point to the camera
  // instead of the ground. Note that the ground
  // was caused to turn at the beginning of this method.
  ground .say( No match. Make the list item point to camera instead of ground. ); duration = 3 seconds
  item_from_myList .set( value , camera );
  item_from_myList .turn( LEFT , 1 revolution ); asSeenBy = cow
  }
  }
  }
  }
  }


 

cow

Methods

  public void dance ( ) {
    
       cow.walk ( times = 3 , speed = 3 );
  cow .turn( RIGHT , 0.5 revolutions );
  cow.tailSwish ( times = 5 , speed = 3 );
  cow.walk ( times = 3 , speed = 3 );
  cow .turn( LEFT , 0.5 revolutions );
  }


 

penguin1

Methods

  public void dance ( ) {
    
       // Note that the behavior of this dance method
  // is a little different from the behavior of the
  // dance method belonging to penguin2.
  penguin1.walking ( x = 2 );
  penguin1.turn_head_left ( );
  penguin1.turn_head_right ( );
  penguin1.wing_flap ( times = 2 );
  penguin1 .turn( LEFT , 0.5 revolutions );
  penguin1.walking ( x = 2 );
  penguin1 .turn( LEFT , 0.5 revolutions );
  }


 

penguin2

Methods

  public void dance ( ) {
    
       // Note that the behavior of this dance method
  // is a little different from the dance method
  // belonging to the penguin1 object.
  penguin2.walking ( x = 2 );
  penguin2.wing_flap ( times = 2 );
  penguin2.jumping ( height = 1 );
  penguin2 .turn( LEFT , 0.5 revolutions );
  penguin2.walking ( x = 2 );
  penguin2 .turn( LEFT , 0.5 revolutions );
  }
 

 

Listing 12. Program listing for Vector01.

Vector01's Code

Created by: Dick Baldwin

world

Events

When the world starts
Do:
world.main ( );


 

Methods

  public void main ( ) {
    
       // Illustrates how to program in Alice using vectors.
  // Moves a penguin in 3D space using both absolute
  // and relative vectors.
  // Initialize the penguin to the origin.
  world.setTheStage ( );
  // Move penguin away from origin with absolute move.
  world.vectorMoveAbs ( obj = penguin , x = 3 , y = 2 , z = -1 , duration = 1 , style = 1 );
  wait( 1 second );
  // Move back to origin with absolute move.
  world.vectorMoveAbs ( obj = penguin , x = 0 , y = 0 , z = 0 , duration = 0.25 , style = 3 );
  wait( 1 second );
  // Move away from origin again with absolute move.
  world.vectorMoveAbs ( obj = penguin , x = -1 , y = 2 , z = 3 , duration = 1 , style = 4 );
  wait( 1 second );
  // Move back to origin in two relative moves with a pause in between.
  world.vectorMoveRel ( obj = penguin , x = 0.75 , y = -1 , z = -1 , duration = 3 , style = 1 );
  wait( 1 second );
  world.vectorMoveRel ( obj = penguin , x = 0.25 , y = -1 , z = -2 , duration = 1 , style = 2 );
  }


 
  public void vectorMoveAbs ( Object obj, Number x, Number y, Number z, Number duration, Number style) {
    Posistion theVector = Vector3( 0, 0, 0 ) ;
       theVector .set( value , ( getVector( right = x , up = y , forward = z ) ) ); duration = 0 seconds
  if ( ( style == 1 ) ) { . . }
       obj .moveTo( world ); position of = theVector duration = duration seconds style = BEGIN_AND_END_GENTLY
  } else {
    if ( ( style == 2 ) ) {
       obj .moveTo( world ); position of = theVector duration = duration seconds style = BEGIN_GENTLY_AND_END_ABRUPTLY
  } else {
    if ( ( style == 3 ) ) {
       obj .moveTo( world ); position of = theVector duration = duration seconds style = BEGIN_ABRUPTLY_AND_END_GENTLY
  } else {
    obj .moveTo( world ); position of = theVector duration = duration seconds style = BEGIN_AND_END_ABRUPTLY
  }
  }
  }
  }


 
  public void setTheStage ( ) {
    
       penguin .setPointOfView( world ); duration = 0 seconds
  penguin .turn( LEFT , 0.5 revolutions ); duration = 0 seconds
  magicianWand .setPointOfView( world ); duration = 0 seconds
  magicianWand .resize( 2 ); duration = 0 seconds
  camera .setPointOfView( world ); duration = 0 seconds
  camera .move( BACKWARD , 15 meters ); duration = 0 seconds
  camera .move( UP , .0001 meters );
  }


 
  public void vectorMoveRel ( Object obj, Number x, Number y, Number z, Number duration, Number style) {
    Posistion currentVector = Vector3( 0, 0, 0 ) ; Number newX = 0 ; Number newY = 0 ; Number newZ = 0 ;
       currentVector .set( value , ( obj .getPosition() asSeenBy = world ) ); duration = 0 seconds
  newX .set( value , ( ( ( currentVector .getDistanceRight() ) + x ) ) ); duration = 0 seconds
  newY .set( value , ( ( ( currentVector .getDistanceUp() ) + y ) ) ); duration = 0 seconds
  newZ .set( value , ( ( ( currentVector .getDistanceForward() ) + z ) ) ); duration = 0 seconds
  world.vectorMoveAbs ( obj = obj , x = newX , y = newY , z = newZ , duration = duration , style = style );
  }

 

Listing 16. The program named Library01.

Library01's Code

Created by: Dick Baldwin

world

Events

When the world starts
Do:
world.main ( );


Methods

  public void main ( ) {
    
       // Demonstrates use of Library methods, functions, and constants.
  // Chicken was manually placed at the origin of the world.
  // -----------------------------------------------------
  // Print a constant that is stored in the Library object.
  print( ( Library.pi .toString() ) );
  // Move chicken away from origin using absolute coordinates.
  Library.vectorMoveAbs ( obj = Chicken , x = -1 , y = 2 , z = 3 , duration = 1 , style = 4 );
  // Move chicken back to origin in two incremental relative
  // moves with a turn in between.
  Library.vectorMoveRel ( obj = Chicken , x = 0.75 , y = -1 , z = -1 , duration = 3 , style = 1 );
  // Call a Library function to execute the 90-degree turn.
  Chicken .turn( LEFT , ( Library.degreesToRev ( degrees = 90 ) ) );
  Library.vectorMoveRel ( obj = Chicken , x = 0.25 , y = -1 , z = -2 , duration = 1 , style = 2 );
  }


Library

Methods

  public void vectorMoveAbs ( Object obj, Number x, Number y, Number z, Number duration, Number style) {
    Posistion theVector = Vector3( 0, 0, 0 ) ;
       theVector .set( value , ( getVector( right = x , up = y , forward = z ) ) ); duration = 0 seconds
  if ( ( style == 1 ) ) { . . }
       obj .moveTo( world ); position of = theVector duration = duration seconds style = BEGIN_AND_END_GENTLY
  } else {
    if ( ( style == 2 ) ) {
       obj .moveTo( world ); position of = theVector duration = duration seconds style = BEGIN_GENTLY_AND_END_ABRUPTLY
  } else {
    if ( ( style == 3 ) ) {
       obj .moveTo( world ); position of = theVector duration = duration seconds style = BEGIN_ABRUPTLY_AND_END_GENTLY
  } else {
    obj .moveTo( world ); position of = theVector duration = duration seconds style = BEGIN_AND_END_ABRUPTLY
  }
  }
  }
  }


  public void vectorMoveRel ( Object obj, Number x, Number y, Number z, Number duration, Number style) {
    Posistion currentVector = Vector3( 0, 0, 0 ) ; Number newX = 1 ; Number newY = 1 ; Number newZ = 1 ;
       currentVector .set( value , ( obj .getPosition() asSeenBy = world ) ); duration = 0 seconds
  newX .set( value , ( ( ( currentVector .getDistanceRight() ) + x ) ) ); duration = 0 seconds
  newY .set( value , ( ( ( currentVector .getDistanceUp() ) + y ) ) ); duration = 0 seconds
  newZ .set( value , ( ( ( currentVector .getDistanceForward() ) + z ) ) ); duration = 0 seconds
  Library.vectorMoveAbs ( obj = obj , x = newX , y = newY , z = newZ , duration = duration , style = style );
  }


Functions

  java.lang.Number public Number degreesToRev ( Number degrees) {
    
     Do Nothing
return ( ( degrees / 360 ) ) ;
  }
 

 


Copyright

Copyright 2007, Richard G. Baldwin.  Faculty and staff of public and private non-profit educational institutions are granted a license to reproduce and to use this material for purposes consistent with the teaching process.  This license does not extend to commercial ventures.  Otherwise, reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.

About the author

Richard Baldwin is a college professor (at Austin Community College in Austin, TX) and private consultant whose primary focus is a combination of Java, C#, and XML. In addition to the many platform and/or language independent benefits of Java and C# applications, he believes that a combination of Java, C#, and XML will become the primary driving force in the delivery of structured information on the Web.

Richard has participated in numerous consulting projects and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas.  He is the author of Baldwin's Programming Tutorials, which have gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.

In addition to his programming expertise, Richard has many years of practical experience in Digital Signal Processing (DSP).  His first job after he earned his Bachelor's degree was doing DSP in the Seismic Research Department of Texas Instruments.  (TI is still a world leader in DSP.)  In the following years, he applied his programming and DSP expertise to other interesting areas including sonar and underwater acoustics.

Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.

Baldwin@DickBaldwin.com

-end-