CS111 Lab: Java graphics and animation CS111, Wellesley College, Spring 2004 Lab 12 Wednesday, May 7, 2004 In the final lab of the term, you will: practice using Java graphics object practice reading Java contracts (APIs) (very useful for us Java programmers!) use randomness to make your pictures more interesting use animation (time permitting) And, most importantly, you will draw cool pictures on Java applets!! Exercise 1: Making a Rainy Day picture. Start off by downloading the folder lab12_programs. In the RainyDay folder, open the file RainyDay.java in DrJava. Your task is to create an applet that looks roughly like this: Note that precise details are not provided, e.g. exact positions and the size of the text and the umbrellas. The goal is to let you experiment with Java graphics and to figure things out on your own. Task 1. Writing the text. Goal: write the text "Rain, rain, go away!" as it appears on the applet in the method writeText. Note that you can use instance variable g to access the graphics of the applet. Hint: the method drawString of the Graphics package writes text. Click here for more about drawString. Changing your font To liven up your font a bit (otherwise it will appear in the default font), you can set the font for the graphics object just as you set color for drawing, only instead of setColor() you use setFont() (see the Graphics contract). Changing your font requires creating a new Font object. The Font constructor takes 3 parameters: A font name, which is a string. It must be one of the predefined font names. Examples are: "Serif" (which is the font used in this applet), "Sans-serif", "Sand" or "Monospaced". The font style, which is a predefined instance variable. There are three options: Font.BOLD (which we use in this lab), Font.ITALIC, and Font.PLAIN (default). The font size, an integer. In this lab the font in the Applet was created like this:
Font rainfont = new Font("Serif", Font.BOLD, 20);
Want to know more? You can read about the Font class in the Font contract. Experiment with different font names, styles, and sizes! You can change the text color by setting the color of the Graphics object. Invoke your method in paint() to draw the text on the applet screen. Task 2: Drawing the umbrellas Goal: Add umbrellas to your applet so that it roughly looks like this: Write your code for the method
public void drawUmbrella(Point p, int length, Color c1, Color c2) {
}
The Point p contains the coordinates of the left upper corner of the rectangle containing the umbrella, the length refers to the length of the base of the umbrella top, and c1 and c2 are the colors of the top of the umbrella. Invoke the method drawUmbrella() three times to draw the three umbrellas, as in the picture. Test your method frequently as you are writing it. A couple of hints for writing this umbrella method: Use drawArc() and fillArc() from the Java Graphics class. You'll need multiple fillArc() invocations to make one umbrella. Click here for some fillArc() examples. See the Graphics contract. Draw the umbrella handle last. Task 3: Adding random raindrops Goal: Add some random raindrops so that the picture looks something like this: Fill in the method drawRainDrop(Point p, int height). Here the Point p stores the coordinates of the left upper corner of the enclosing rectangle of the raindrop, and height is the height of the entire raindrop. There are different ways of drawing a raindrop. Here's one way that uses a triangle and an arc (in the applet, the raindrops are grey): You can draw a raindrop any way you like. Drawing lots of rain When you get the correct picture of the raindrop, make it rain on your applet screen (for instance, there are 150 raindrops in the picture above). Hint: use a loop and a random number generator to position the raindrops on the screen. Randomizer: a random number generator The class RainyDay has an instance variable ran which is a Randomizer:
Randomizer ran = new Randomizer(); // for random raindrops
A randomizer has many methods for generating various kinds of random numbers. Here are some of them: public boolean flip () returns "true" and "false" with equal probabilities. public int intBetween (int lo, int hi) returns an integer at random between the two given integers: lo and hi (including the bounds). The parameters must be such that lo is less than hi. Example:
int n = ran.intBetween(1,20); // n is randomly chosen between 1 and 20
assigns to n an integer randomly chosen between 1 and 20 (including 1 and 20). All of the numbers have the same probability. public int evenBetween (int lo, int hi) returns a randomly chosen even number between lo and hi. public int oddBetween (int lo, int hi) returns a randomly chosen odd number between lo and hi. You can use the randomizer ran anywhere within the class RainyDay. Adding many raindrops You need to write a loop in which you draw raindrops with random positions on the applet screen. Hint: use the variables height and width which specify the size of the applet (they are defined in the method paint()). You may also randomly choose the size of raindrops, if you'd like. Where do you add the loop in the method paint() so that the picture looks like the one above? If you have time left, add other features to your applet! Exercise 2: Animation. The animation code is in the LabAnimation folder. You can experiment with the code in the Test folder, or you can run a demonstration from here. There are two animations in this lab. Task 1: Balloons Part 1. Balloons In this animation balloons go up to the ceiling, hang there for a while, and then go down. The position, the size, the speed of balloons, and the amount of time they are stuck to the ceiling varies. The file BalloonAnimation.java is the code for the animation class for the balloons. In the file creation of all balloons except for one is commented out. Uncomment it after you get the first balloon to behave correctly. Your code for balloons goes into the file Balloon.java. The constructor and some instance variables are already defined, do not change the constructor! You need to write the code for the following methods (I recommend you to do it in this order): resetState() -- sets the balloon to the initial state, i.e. on the floor. You can use variables height and width, which Balloon inherits from Sprite. They refer to the height and the width of the screen. drawState(Graphics g) -- draws the balloon at the given position. updateState() -- controls the movements of the balloon. The balloon should go up (incrementing its height by d on every frame) until it reaches the ceiling, then it hangs at the ceiling for the number of frames given in timeStuck (how do you count the time?), and then goes down, decrementing the height by d, until it reaches the floor. Make sure to test the reset button: reset the animation, and then play it again. It should work exactly as it did the first time. Task 2: Starry night The applet starts off as a blue sky: The sky slowly gets darker and a few stars appear: In the end (frame 100) the sky is dark, filled with stars, and the moon appears in the left upper corner: Now that we have enjoyed the view, let's look at the programming details. There are three kinds of Sprites in this animation: NightBackground, SmallStar, and Moon. Your task is to fill in missing parts of the code for these three classes and add them to the animation in the file StarryNightAnimation using the addSprite() method. NightBackground is a sprite that inherits from ColorBackground. The constructor for NightBackground sets the initial color of the background to blue. You need to make the color darker (by invoking the method darker() ). Making the background darker on every frame would turn it black very soon, so we introduce a delay: the color stays the same for the number of frames specified by the the parameter delay. Your task is to fill in the resetState() and the updateState() methods of NightBackground. Stars are sprites of the class SmallStar. The resetState() method generates random x and y coordinates within the applet's screen, the radius (a number between 1 and 5), and the time the star will appear on the sky (a number between 1 and 100). Your task is finish the method resetState() and write the methods drawState() and updateState(). Hint: the star should be drawn only after it has become visible. The moon is a sprite of the class Moon. Its coordinates, radius, and the time of appearance are set by the constructor. It's drawn as a yellow vertical half-circle. Use the same trick as you used for stars to make the moon appear at the given time. Extra effort problem (there is no credit for labs, so I can't call it extra credit : -) ) you probably noticed that the picture is not astronomically correct: stars show through the dark half of the moon. Fix this problem by adding the other half of the moon drawn in the background color. You need to pass the delay as a parameter to the moon constructor, since you need to figure out the background color at the time when the moon appears. Now that you are done with the lab exercises, you can create your own animations!