PI: Laboratory 5: Graphics, Painting, and Containment | |
OverviewIn this lab, you will get to know some key parts of the java AWT, namely painting and containment. Polymorphism also plays a small role, but you may choose to deal with it in more detail if you have time.As usual, you should read the general information handout for the collaboration policy. For this assignment, you may discuss the project in as much detail as you like with your classmates, but you should do the writeup on your own. You may also get comments from other students on all portions of your writeup before turning it in, if you wish. Please include the names of anyone with whom you collaborate, in any way, on this assignment, and indicte the nature of the collaboration. If you do not collaborate with anyone on any part of this assignment, please state so explicitly. [Failure to include this information is a violation of the collaboration policy.] You will be turning in the code you write for this
lab. This code must be your own. We do encourage you, however, to ask your
classmates for help debugging. Helping someone else debug their code is
a great way to improve your own programming skills.
Contents
IntroConceptWe're going to be writing part of the code for a Breakout game. Specifically, the code that defines how a particular brick behaves.If you're not familiar with the game Breakout, the basic idea is this: You're in a box that contains a paddle, a ball, and rows of bricks. You can move the paddle from side to side, but not up or down, and it is your only method of controlling the movement of the ball. The object of the game is to use the ball to destroy all of the bricks, without letting the ball hit the ground. Basic Gameboard PiecesIn our version of Breakout, we have defined several different sets of behavior for you. Every game object(balls, bricks, etc) implements the BreakoutComponent interface. Most objects do this via a sub-interface that more specifically classifies what kind of object it is. For example, the Brick interface is a subclass of BreakoutComponent that exists so that the Board can tell whether you've won the game(cleared all the Brick objects) or not.Here is a brief summary of the Breakout interfaces you might find it useful to know about:
How Breakout Works (and paint too)You have a Board. A Board keeps track of all the game objects(the Bricks, Balls, etc) but the Board doesn't really know the difference between a brick, a ball, a wall, or a paddle -- it just has a list of generic BreakoutComponent objects. The BreakoutComponent interface guarantees that everything on the Board will be able to answer some basic queries about what size it is, where it is on the board, whether it's an ellipse or a rectangle or whatever, and some other things that you can look at on the BreakoutComponent javadoc if you wish. One of the more important methods it defines in the context of this lab, though, ispaint . paint is a funky sort of method. Unlike most of the methods you've seen so far, you the programmer are not the one who decides when and where this method is called. In fact, you'd probably find it pretty difficult to call this method explicitly on any BreakoutComponent, even if you tried, because you're missing the key ingredient: a Graphics . A Graphics object is what does most of the work in a paint method -- it knows how to draw ovals, rectangles, lines, text, and even images. But unfortunately, you can't create a Graphics out of thin air like you might do new String() or new Frame() . Go ahead, check the javadoc. The constructor for Graphics is protected: you're not allowed to create one directly, which means you can't call paint . Who, then, does call paint ?! This is what makes paint so neat. Java itself decides when paint gets called. paint happens any time a window, or part of a window, needs to be painted -- like when it first appears, or when you momentarily drag something over top of it, and drag it away again. So... what happens if you want something to be animated? If you can't tell your component to paint , how do you change what shows up on the screen after it paints it the first time?It would be really aggravating if the answer to this question was, "You don't. Tough." But then, people probably wouldn't use Java for as many entertaining things as they do. Luckily, all components have a nifty "hidden" method called repaint() that Java handles all by itself -- you don't have to write a word of code for it. When you call repaint on a Component (a java.awt.Component , not a BreakoutComponent -- sadly, BreakoutComponent is only a shadowy simulation of what a Component ought to be) Java knows to go and find the Graphics it used to paint this Component last time, and uses the Component's paint method to see how it ought to be painted. repaint() is like the Component saying, "Hey! I changed! I need to be painted again!" just like what happens when you cover up the Component for a bit and then uncover it again. In Breakout, we don't really need to worry about repaint() (though certainly don't forget what you just learned!). In Breakout, the Board is getting automatically repainted every few milliseconds. World , the object that controls the "clock" for Breakout, knows that things are moving all the time, and is constantly running a loop telling everything on the board to update themselves, and telling the GUI components to repaint(which, in turn, tell all the BreakoutComponents they know about to repaint as well). Part of the target exercise of this lab is to understand the basics of writing the paint(Graphics g) method of a Brick object. Take a moment to browse the javadoc for Graphics in the Java API.
Other important Breakout classesHow to control the painting of the gameboard objects is what we're most concerned about with this lab. However, in order to get Breakout to run, we need to briefly look at some of the beefier classes that help control how the whole game works(rather than just how one particular gameboard looks over its lifetime). These classes are BreakoutUI, Board, BoardPanel, and World.We already talked about World somewhat, but you might want to look at its introduction in the javadoc to get a better idea of the activity that happens during each "tick" of the game. (Remember the loop we put in the run() methods in NodeNet? each "tick" is one iteration of World's run() loop.) You won't have to worry about most of it -- all we're really interested in for now is the very last step where World redraws the board. Note that we don't have to create a World: that's BreakoutUI's job. BreakoutUI and BoardPanel are a pair of classes that form the user interface for Breakout. BreakoutUI houses the actual JFrame that is the window you see on the screen, and BoardPanel is a section of the frame that houses the gameboard. Creation of the BoardPanel is also BreakoutUI's job, so we don't have to worry about that either. Jot down the constructor and methods available in BreakoutUI. We'll come back to them shortly. The Board class is getting much closer to the stuff we're actually going to be working with during this lab. We already know that a Board object is the thing that actually keeps track of each individual brick, ball, paddle, or wall. Look in the javadoc for Board's constructor.
add , since those methods will be very important during this lab.
The LabOneGetting started with MainThe first thing you need to do is set up a file called Main.java, which will define a class with a special method that starts the whole thing running.
TwoSet up aBreakoutUI
ThreeBuilding aBrick
Everything that you see on the breakout Board implements the BreakoutComponent interface. BreakoutComponent defines some basic functionality such as location getters/setters, painting behavior, and ingame activity.
Take a look at the javadoc for BasicBrick . First check out the interface it implements -- Brick . Brick is an interface that extends BreakoutComponent without adding any functionality, and basically just lets the Board know that this particular BreakoutComponent is a Brick . Why this is useful: when all the Brick objects in the Board are gone, you've won the game.
FourAdding ourBrick to a Board
Remember that Breakout uses a class called Board to keep track of all the game pieces -- bricks, balls, paddles, and walls. When we clicked "Load" before, Breakout looked in a configuration file to get the information it needed to build and load a new Board object. We're going to use a simpler process to build our first board.
FiveBecause breakout is less fun without a paddle & a ballLet's make our new Board actually playable.
SixBecause a flat black rectangle is boringRevisit the prelab activity where you listed the methods in Graphics that allow you to draw things on the screen, and look for ways to spiff up our brick. How would you draw a solid brick? A solid brick with a different colored outline from its insides? A brick with... polka dots? Stripes? The Olin "O"? Play around, create a couple different Brick classes that look neat. Add multiple instances of different bricks to the Board , and use them all together in a single Board.Once you have completed a few brick classes that draw themselves different ways, you have completed the target exercise for this lab. If you have extra time, though, there's always... Gravy!There is lots of room for expansion in this lab if you have time... We'd suggest reading through this section for ideas, and picking a couple to work on that interest you.Other Brick functionalityThere are several methods inBasicBrick other than paint that beg to be overridden. Most notably, the behavior that happens when a brick is hit by a ball:
This method tells the Brick which BreakoutComponent just hit it. It should return true if the Brick died and needs to be removed from the Board , and false if it should stay put. You can experiment with bricks that don't die unless you hit them several times, or maybe even bricks that spawn new bricks -- after a game has started, you can use Board.add(BreakoutComponent, java.awt.Point) to add components to the Board . (auto-layout-add is disabled while in-game)
PolymorphismThe polymorphism features in breakout are terribly entertaining, so you can definitely take a look at that. Remember that since all the members of the board have to implementBreakoutComponent , they all have a set of common methods that you can use regardless of what class they might be from -- that's what polymorphism means, really: using interfaces to give several different types of objects a guaranteed similar behavior, so you can treat them all as a single group. This could definitely be useful, for example, in doing neat things with the hit(BreakoutComponent bc) method.
If you get bored with playing with bricks, or if you're getting annoyed with having to maintain 20 add() statements, you'll probably be interested in how to write a Board file -- like the one we loaded in part Two of the Lab.
BoardfilesCheck out the format of theexampleboard.brd file in the Board directory. It's massively documented, but should you need a hand figuring something out, don't hesitate to ask someone. Try duplicating whatever Board you've got set up in your main method using a boardfile, run it, and load it.
Okay, so you just managed to achieve something you'd already had five minutes ago... great. But now, it's really easy to change up the ball and paddle, and keep track of large numbers of bricks in the Board with fewer keystrokes.
The Rebounding InterfaceThe tricky thing about moving objects like balls is that they have to figure out what to do when they hit something. This behavior is defined in theRebounding interface. Luckily, the functionality you need for things that bounce is already covered for you in BasicBall , so you're probably alright just extending that class. If you want to make something that moves, but doesn't need to rebound off of anything, you probably don't need to implement Rebounding -- just put the movement in the update() method.
More Ideas
Post-Lab, AKA What To Turn InYour completed assignment should include:
| |
Questions, comments, gripes and other communication to pi-staff@lists.cognition.olin.edu | |
This course is a part of Lynn Andrea Stein's Rethinking CS101 project at the Computers and Cognition Laboratory and the Electrical and Computer Engineering area at Franklin W. Olin College of Engineering. |