If you have studied the earlier lessons in this series (see Resources), you have learned all about the Turtle class, its superclass named SimpleTurtle, and the classes from which a turtle's contained objects are instantiated (Pen and PathSegment). You have learned how to instantiate new Turtle objects, placing them in either a World object or a Picture object. You have learned how to manipulate the Turtle objects once you place them in their environment. The time has come for you to learn about the environment in which a turtle lives. You will learn about the World class in this lesson. You will learn about the Picture class in a future lesson.

In this series of lessons, I will present and explain many of the classes in a multimedia class library that was developed and released under a Creative Commons Attribution 3.0 United States License(see Resources) by Mark Guzdial and Barbara Ericson at Georgia Institute of Technology. In doing this, I will also present some interesting sample programs that use the library.

I will explain Ericson's World class in this lesson. I will also present and explain a sample animation program in which seven Turtle objects chase another Turtle object around in an aquarium. A screen shot from the sample program, showing seven turtles in hot pursuit of a red and green turtle, is shown in Figure 1.

Discussion and sample code

A complete listing of the World class is shown in Listing 23 near the end of the lesson. The only changes that were made to this listing were minor formatting changes that were required to make the source code fit into this narrow publication format.

Let's try something new

I'm going to try something in this lesson that I have never tried before. I'm going to explain the World class in the context of a sample program named TurtleWorld01 that animates a group of turtles in a World object.

As usual, I will explain the code in fragments. However, to help you know whether a particular code fragment came from the World class or came from the sample program, I will use two different background colors for the listings of the code fragments. The two colors are shown in Listing 1 and Listing 2.

This is an animated program that is designed to illustrate various features of the World class and the Turtle class. (See resources for earlier lessons on the Turtle class.) A complete listing of the program is provided in Listing 24 near the end of the lesson.

The program places eight Turtle objects in a World object referred to by a variable named aquarium. One turtle is designated as the leader and is given a red shell to make it highly visible. (A screen shot from the running program is shown in Figure 1.)

An Image from an aquarium containing a starfish and some other fish is used as a background picture for the aquarium. The lead turtle has a red shell and a green body. The body color and the shell color of two of the turtles are set to yellow and orange to make them stand out from the background. The remaining four turtles are presented in their default colors of green, cyan, and purple.

Follow the leader

All eight turtles are initially placed in random locations in the aquarium. The lead turtle swims around randomly. The other seven turtles converge rapidly on the leader and swim in formation following the leader while attempting to avoid collisions with one another.

Much of the time, the formation looks roughly like a hexagon with six turtles forming the perimeter and one turtle in the center. (See Figure 1.)

Once started, the program will run until it is manually terminated.

Beginning of the program named TurtleWorld01

The program begins in Listing 3 by instantiating an object of the Runner class and calling the run method on that object.

public World(int w, int h){
width = w;
height = h;
// set up the world and make it visible
initWorld(true);
}//end constructor

Listing 5, which is a code fragment from the World class, begins by saving the incoming width and height values in a pair of private instance variables. (You can view all of the World's instance variables in Listing 23.) Then it calls the initWorld method, (shown in Listing 6), passing true as a parameter to complete the construction of the new World object.

The initWorld method

The incoming boolean parameter to the initWorld method is used to determine if the world will be visible when it is instantiated.

The preferred sizeI have discussed the preferred size in many earlier lessons.

Listing 6 begins by calling the setPreferredSize method inherited from the JComponent class to set the preferred size of the World object.

Create an all-white background picture

Then Listing 6 instantiates a new default all-white Picture object and assigns the picture's reference to a private instance variable named picture.

Add the world to a JFrame object

One of the world's private instance variables (see Listing 23) is a reference variable named frame containing a reference to an empty JFrame object. Listing 6 adds the new World object to the JFrame object. Therefore, the JFrame object becomes the visual container for the world.

Then Listing 6 calls the pack method on the JFrame object. This causes the size of the JFrame object to be set to the preferred size of the world that it contains.

Finally, Listing 6 causes the JFrame object to be visible or not visible, depending on the boolean value received as an incoming parameter by the initWorld method.

If you examine the instance variables in Listing 23, you will see that the World object creates and maintains an ArrayList object containing references to all of the turtle objects that are added to the world. Listing 7, which is a fragment from the TurtleWorld01 program, gets and saves a reference to that list. The reference will be used for manipulating the turtles later. The reference is saved as the interface type List.

The size of the World
Note that the size of the picture of the aquarium was determined in advance and the dimensions of the world were set to the size of the picture Listing 4. Otherwise, either a portion of the world would be white, or some of the picture would not be visible.

Listing 9 calls the setPicture method on the World object to replace the all-white picture with the background image shown in Figure 1.

The setPicture method of the World class

As you can see in Listing 10, the setPicture method simply assigns the incoming Picture object's reference to the instance variable named picture. (See Listing 23.)

A ModelDisplay object
The World class implements the ModelDisplay interface. Therefore, a World object is also a ModelDisplay object.

Turtle constructors

You learned in an earlier lesson (see Resources) that whenever you instantiate a new Turtle object, you can specify the container in which it will live: Picture object or ModelDisplay object. You also learned that you can optionally specify the coordinates at which the turtle will be placed in that container.

When the container is a ModelDisplay object...

You learned that when the specified container is a ModelDisplay(World) object, the constructor for the Turtle class:

Sets the initial position coordinates for the new turtle.

Sets the initial body color of the new turtle to one of four default colors.

Sets the initial pen color to match the body color.

Increments a static turtle counter in the Turtle class.

Calls the addModel method on the specified ModelDisplay(World) object.

The method begins by adding the new turtle's reference to the world's ArrayList object that is used to maintain a list of all the turtles that belong to the world.

To paint or not to paint...

Then the addModel method checks the value of a boolean instance variable named autoRepaint(which is true by default) to determine whether or not to repaint the world containing the new turtle. The call to the repaint method causes the world's paintComponent method to be called. I will have more to say about this later.

Perform some housekeeping chores

Listing 13 performs some housekeeping chores in preparation for running the animation loop in the program named TurtleWorld01.

Most of the actions in Listing 13 involve extracting references to Turtle objects from the world's list of turtles and calling various methods of the Turtle and SimpleTurtle classes on those references. You learned about these methods in earlier lessons (see Resources).

The animation loop will continue to run until the program is manually terminated.

Once during each animation cycle, the turtle with the red shell (see Figure 1) turns by a random amount and moves forward by a random distance. The variables named leaderMove and angle in Listing 14 are assigned random values that will be used later to control those actions.

Process each turtle during each animation cycle

Each turtle in the list is processed once during each animation cycle. Listing 15 shows the beginning of a for loop that iterates on the list of turtles to accomplish that.

Left strictly to their own devices, all seven of the turtles that are chasing the leader would attempt to occupy exactly the same space. Listing 16 contains a for loop that attempts to force those seven turtles to maintain some distance between them.

The code in Listing 16 computes the distance between each of those seven turtles and six other turtles, (excluding itself and the leader).

If the distance between the current turtle and a test turtle is below a specified threshold, the current turtle turns and moves away from the test turtle by a specified amount. While this algorithm is not perfect, it does a pretty good job of keeping the turtles separated as you will see if you run the program.

A model-view-control paradigm
I explained in an earlier lesson (see Resources) that the call to the modelChanged method constitutes part of the use of a model-view-control (MVC) paradigm by the World class.

Call the world's modelChanged method

You learned in an earlier lesson that if the heading, the visibility, or the position of a turtle is changed, the turtle object calls the world's modelChanged method, which is shown in Listing 17. The World object may, or may not cause itself to be repainted in response to that call.

The modelChanged method of the World class

The world's modelChanged method checks the value of the boolean variable named autoRepaint. If the value is true, the repaint method is called, which in turn causes the world's paintComponent method to be called. (I'll have more to say about the paintComponent method later.) Otherwise, it does nothing in response to the call.

Continuing with the for loop that began in Listing 15, if the current turtle being processed is the first turtle in the list, it is the leader. Its behavior is different from the behavior of the other seven turtles.

Listing 18 shows the behavior of the leader during one iteration of the animation loop.

Tests are performed in Listing 18 to determine if the leader has collided with one of the four walls of the world. If so, the leader's heading is set to the direction of the opposite wall.

Turn and move randomly

Regardless of whether or not a collision with a wall has occurred, the leader's heading is modified by a random amount ranging from -22.5 degrees to +22.5 degrees (see Listing 14) and the leader moves forward by a random distance ranging from half its length to three-fourths of its length (see Listing 14).

The other seven turtles make their move

If the current turtle is not the leader but instead is one of the seven turtles that follow the leader, the code in Listing 19 is executed.

Each of the seven turtles in the herd turn to face the new position of the leader and move toward the leader by one-tenth the distance to the leader. In theory, the members of the herd would never catch the leader. However, because the leader must turn back toward the herd when it collides with a wall, there are frequent collisions between the leader and the members of the herd. The leader simply blasts through the formation, colliding with other turtles along the way, and goes out the other side of the formation. This causes the other turtles to turn and give chase in the new direction.

Once again, every time any of the turtles moves or changes its heading, the World object is given an opportunity to repaint itself.

Listing 19 signals the end of the for loop that causes the processing of every turtle during each animation cycle.

Control the animation speed

At the end of each animation cycle, the program goes to sleep for 100 milliseconds to control the overall speed of the animation. This is shown in Listing 20.

Although that is the end of the program named TurtleWorld01, it is not the end of the explanation of the class named World. There are several other methods in the World class that need to be explained.

Two more overloaded constructors

There are two more overloaded constructors for the World class. One receives no arguments and constructs a world that is visible by default and has a default size. The other receives a boolean value and constructs a world that may or may not be visible, depending on the value of the incoming parameter and has a default size.

Both of these constructors are straightforward. You can view the code for these two constructors in Listing 23.

"First and foremost, you should know that in Java graphics programming, one of the most important instantiated objects is the graphics context. This object is an instance of the java.awt.Graphics class, and it refers to an area of the screen such as an applet. A graphics context provides methods for all of the drawing operations on its area. It also holds "contextual" information about such things as the drawing area's clipping region, painting color, transfer mode, and text font."

Stated differently, if you want to draw on an object using methods of the Graphics class or the Graphics2D class, you must first get a graphics context on the object on which you want to draw.

A rectangular area...

I often tell my students that such an object of the Graphics class represents a rectangular area of the screen or an off-screen buffer in memory. Whatever you draw on the Graphics object will be drawn on the screen or in the off-screen buffer memory. (As I recall, it is also possible to get a Graphics object that represents a rectangular area on a sheet of paper in a printer, but I haven't had a reason to think about that in a long time.)

The graphics context for a World object

You can get a graphics context on a World object by calling the getGraphics method shown in Listing 21.

Painting in AWT and Swing
For more information on the paint mechanisms utilized by AWT and Swing, including information on how to write the most efficient painting code, see Painting in AWT and Swing.

Update the world's visual representation

When an object of the World class decides, for whatever reason, that its visual representation on the screen needs to be updated (see Listing 12 and Listing 17 for example), it makes a call to the repaint method inherited from the Component class. This ultimately results in a call to the world's paintComponent method.

Can be triggered by the operating system

Similarly, when the operating system decides for whatever reason that the world's screen representation needs to be updated, (such as when it is minimized and then restored), the operating system causes the world's paintComponent method to be called.

A reference to a graphics context

When the paintComponent method is called, it receives a reference to a graphics context that represents an area of the screen that is to be repainted.

Casting the graphics context
Casting the graphics context reference to type Graphics2D makes it possible to use the methods of the Graphics2D class to draw on the graphics context.

Actually an object of the Graphics2D class

The graphics context is received as type Graphics, but it is actually a reference to an object of the Graphics2D subclass of Graphics.

Draw the current picture on the graphics context

Listing 22 begins by calling the drawImage method to draw the image contained in the world's current Picture object on the graphics context. This produced the aquarium background shown in Figure 1.

Call paintComponent on each of the turtles

Then Listing 22 uses an iterator to loop and call the paintComponent method on each Turtle object whose reference is stored in the list of turtles, passing the same graphics context received by the world's paintComponent method.

Draw each turtle and its track

We learned in an earlier lesson (see Resources) that a turtle's paintComponent method begins by casting the incoming reference of type Graphics to type Graphics2D. Then it draws the body parts of the turtle at the correct location, in the correct color with the correct heading. Then it calls the paintComponent method on the Pen object that belongs to the turtle, passing the same graphics context that it received.

Drawing the historical turtle track

As a turtle moves with the pen down, the turtle's Pen object maintains a list of historical turtle movements as type PathSegment. When the paintComponent method is called on the Pen object, it uses the contents of that list to reconstruct and draw line segments with the correct width and the correct color representing the turtle's historical path. Note, however, that the pen was never down in the sample program named TurtleWorld01 so no turtle tracks are produced. (For an interesting effect, disable the call to the penUp method in Listing 15.)

The remaining methods of the World class

The world class defines several additional methods that I haven't discussed in this lesson:

getLastTurtle - a method to get a reference to the last turtle in the list of turtles.

containsTurtle - a method to determine if the list contains a reference to a specific turtle object.

remove - a method to remove a specific turtle from the list.

getWidth - a method to get the width of the World object.

getHeight - a method to get the height of the World object.

setAutoPaint - a method to set the value of the autoPaint variable to true or false.

setVisible - a method to make the World object visible or invisible.

getTurtleIterator - a method to get an Iterator object on the list of turtles.

toString - a method to return a string that describes a World object.

The code for all of the methods in the above list is straightforward. You can view that code in Listing 23.

That wraps it up

That brings us to the end of the explanation of the class named World and the end of the explanation of the program named TurtleWorld01.

Run the programs

I encourage you to copy the code from Listing 24, compile the code, and execute it. Experiment with the code, making changes, and observing the results of your changes. Make certain that you can explain why your changes behave as they do.

In this lesson, I have explained an animation program named TurtleWorld01 along with an explanation of the class named World. The program named TurtleWorld01 illustrates a form of flocking behavior (see Wikipedia: Flocking behavior in Resources) where a herd of turtles follow a lead turtle as it moves randomly in a World object while attempting to avoid collisions with one another.

/*Program TurtleWorld01
Copyright R.G.Baldwin 2009
This is an animated program that is designed to illustrate
various features of the Turtle and World classes.
The program places eight Turtle objects in a World object
known as the aquarium. One turtle is designated as the
leader and is given a red shell to make it highly visible.
An Image from an aquarium containing a starfish and some
other fish is used as a background picture for the
aquarium.
The body color and shell color of two other turtles are
set to yellow and orange to make them stand out from the
background.
The leader swims around randomly in the aquarium.
All eight turtles are initially placed in random locations
in the aquarium. However, the other seven turtles rapidly
converge on the leader and swim in formation following the
leader while attempting to avoid collisions with one
another.
Much of the time, the formation looks roughly like a
hexagon with six turtles forming the perimeter and one
turtle in the center.
Once started, the program will run until it is manually
terminated.
Tested using Windows Vista Premium Home edition and
Ericson's multimedia library.
*********************************************************/
import java.util.Random;
import java.util.Date;
import java.util.List;
import java.awt.Color;
public class Main{
public static void main(String[] args){
new Runner().run();
}//end main method
}//end class Main
//------------------------------------------------------//
class Runner{
//Instantiate a random number generator.
Random randGen = new Random(new Date().getTime());
//Set the dimensions and instantiate a new world.
int aquariumWidth = 450;
int aquariumHeight = 338;
World aquarium = new World(
aquariumWidth,aquariumHeight);
//Get a reference to the list of turtles maintained by
// the World object.
List turtleList = aquarium.getTurtleList();
//----------------------------------------------------//
void run(){
aquarium.setPicture(new Picture("aquarium.gif"));
int numberTurtles = 8;
//Place each turtle in a random location in the
// aquarium.
for(int cnt=0;cnt < numberTurtles;cnt++){
int xCoor =
Math.abs(randGen.nextInt() % aquariumWidth);
int yCoor =
Math.abs(randGen.nextInt() % aquariumHeight);
new Turtle(xCoor,yCoor,aquarium);
}//end for loop
int angle = 0;//leader turning angle
int leaderMove = 0;//leader move distance
Turtle turtle = null;
Turtle testTurtle = null;
//First turtle in the list is the leader. Color it red
// and get its length.
Turtle leader = (Turtle)turtleList.get(0);
leader.setShellColor(Color.RED);
int turtleLength = leader.getHeight();
//Change the shell and body colors of two of the other
// turtles.
turtle = (Turtle)turtleList.get(3);
turtle.setBodyColor(Color.YELLOW);
turtle.setShellColor(Color.ORANGE);
turtle = (Turtle)turtleList.get(7);
turtle.setBodyColor(Color.ORANGE);
turtle.setShellColor(Color.YELLOW);
while(true){//animation loop will run forever
//Leader will move a random distance ranging from
// half its length to 3/4 its length during each
// animation cycle.
leaderMove = (int)(turtleLength/2
+ turtleLength*randGen.nextDouble()/4);
//Leader will turn a random amount ranging from
// -22.5 degrees to +22.5 degrees during each
// animation cycle.
angle = (int)(45*(randGen.nextDouble() - 0.5));
//Process each turtle in the list during each
// animation cycle.
for(int cnt = 0;cnt < turtleList.size();cnt++){
turtle = (Turtle)turtleList.get(cnt);
turtle.penUp();//no turtle tracks allowed
//Force the turtles to maintain some distanced
// between them by comparing the distance from the
// current turtle to every other turtle (other
// than the leader) and making a correction when
// too close.
for(int cntr = 1;cntr < turtleList.size();cntr++){
testTurtle = (Turtle)turtleList.get(cntr);
//Don't process leader or self.
if((testTurtle != turtle) && (cnt != 0)){
int separation = (int)(turtle.getDistance(
testTurtle.getXPos(),testTurtle.getYPos()));
//Try to keep them separated by at least
// twice the turtleLength center to center
if(separation < 2*turtleLength){
//Turn and move away from test turtle.
turtle.turnToFace(testTurtle);
turtle.turn(180);
turtle.forward(turtleLength/3);
}//end if
}//end if
}//end for loop on turtle separation
if(cnt == 0){
//This is the leader
//Force the leader to bounce off the walls.
int xPos = leader.getXPos();
int yPos = leader.getYPos();
if(xPos < turtleLength){
leader.setHeading(90);
}else if(xPos > aquariumWidth -turtleLength -2){
leader.setHeading(-90);
}//end else
if(yPos < turtleLength){
leader.setHeading(180);
}else if(
yPos > aquariumHeight -turtleLength - 2){
leader.setHeading(0);
}//end else
//Leader turns a random amount and moves a
// random distance during each animation cycle.
leader.turn(angle);
leader.forward(leaderMove);
}else{
//This is not the leader. Turn to face the
// leader and move toward the leader.
turtle.turnToFace(leader);
int distanceToLeader = (int)(turtle.getDistance(
leader.getXPos(),leader.getYPos()));
turtle.forward(distanceToLeader/10);
}//end else
}//end for loop processing all turtles
//Control the animation speed.
try{
Thread.currentThread().sleep(100);
}catch(InterruptedException ex){
}//end catch
}//end while loop
}//end run
}//end class runner

Richard Baldwin is a college professor (at Austin Community College in Austin, TX) and private consultant whose primary focus is object-oriented programming using Java and other OOP languages.

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.