$29
CS300: PROGRAMMING II
Pair Programming is allowed but not required for this assignment.
This assignment involves reorganizing some of the data from your P1 Swim Sim program, replacing
the old text based display with graphics, and adding user interaction. The code that is developed for
this assignment will also be used as the basis for future programming assignments, so be sure to
keep your code clean, clear, and well commented. Here’s what one frame of this animation might
look like when you are done.
P2: SWIM SIM (GRAPHIC)
LECTURE NOTES
Objectives and Grading Criteria
The goals of this assignment include reorganizing a real-time simulation into a more general form,
and making use of instantiable objects of predefined types. In addition to the provided Data object
type, you will make use of PApplet and PImage objects defined in the processing library. You will
also make use of a callback method to facilitate human interactions with your simulation.
Grade Breakdown:
25
points
5 zyBooks Tests: automated grading test results are visible upon submission, and allow
multiple opportunities to correct the organization and functionality of your code. Your
highest scoring submission prior to the deadline will be recorded.
25
points
5 Hidden Tests: automated grading tests are run after the assignment’s deadline. They
check for similar functionality and organizational correctness as the zyBooks Tests. But
you will NOT be able to resubmit corrections for extra points, and should therefore
consider and test your own code even more thoroughly.
GETTING STARTED
0. If it’s not already there, open the project containing your P1 code in Eclipse. Select your project
folder in the “Package Explorer” view, then copy its contents (Ctrl-C) and then paste them (CtrlV). This will prompt you to name the new copy whatever you’d like, although P2SwimSim would
be a descriptive choice. Navigate to the Main.java file within the src folder of this new project,
and open it before clicking Run. Eclipse usually does a good job of running the code associated
with whatever file you have open in the editor. However I still personally prefer to close other
projects with similarly named files to prevent myself from possibly confusing them. You can
remove your old project from Eclipse by selecting it in the “Package Explorer” and then pressing
“Delete” (or choosing this from the right-click menu). A dialog will confirm your intentions with
this action and it’s very IMPORTANT to leave the check box labelled “Delete project contents on
disk (cannot be undone)” unchecked. By leaving this unchecked, your files will remain intact so
that you can re-open this project later using the “Import” option from the “File” menu, and then
selecting “Existing Projects into Workspace” from the “General” folder.
GETTING ORGANIZED
1. Review your code from P1 and notice the growing complexity of your main method. There is a
natural and common way for us to decompose this method into more focused and less complex
pieces: we break out the simulation setup code and the code that repeatedly updates our
simulation. Here’s the new form for the body of our main method, which introduces the two new
methods (setup and update) that we will be implementing through this step:
Both of these methods need access to your array of characters, and to all of your objects’ positions
for them to work. But instead of passing all of these array references separately into each
method, we’re going to group all of them together into a single object of type Data (this new type
is already defined in the SwimSim.jar file that you setup during P1). Instantiate a new object of
type Data using its no-arg constructor at the beginning of your main method. Notice that this
object contains fields of the appropriate types for: char[][] tank, int[][] fishPositions, int[][]
foodPositions, and int[][] hookPositions. You can access these field names through a reference
(named data) to a Data object as: data.fieldName. Refactor your main method into separate
setup() and update() methods that each make use of the references in this new Data object.
1
2
3
setup(data);
while(true)
update(data);
2. Ensure that your simulation still works as well as it did before the refactoring performed in that
last step. Your main method is now structured in the way that the processing graphics library
(and many other real-time graphics and user interface frameworks) expects. You should next be
able to replace (start by commenting out) the contents of your main method with a single call to
the provided method: Utility.startSimulation(). This will 1) instantiate a new Data object, 2) pass
that object to your setup() method, and then 3) repeatedly pass the same object to your update()
method until the program is terminated. But in addition to all of this work that your old main
method was already doing, Utility.startSimulation() will also create a graphical window using the
processing library! Notice that closing this gray window will now also terminate your program.
MOVING FROM TEXT TO GRAPHICS
3. Getting rid of the old text graphics should be pretty straight forward: just remove the call of
renderTank() from our update() method’s definition. Let’s also remove the calls to
Utility.pause(200) and System.out.println(“\n\n\n”); from this method, since neither of them
will be of any use in the graphical version of this program.
4. We no longer have any need for the char[][] that we were using in the past. Instead of drawing
into that array, we’ll start drawing into our new graphical window using the processing field
within our Data object. To demonstrate this, let’s replace the call to our own fillTank() method
with a call to processing’s background() method that performs a similar computation.
Notice that this method takes three arguments between 0 and 255 that correspond to the
amounts of red, green, and blue light (in that order) that contribute to the color drawn across the
entire background of our window. Zero corresponds to no light of a particular color, and 255
refers to the maximum amount of that light, so passing (0,0,0) would result in black and
(255,255,255) would result in white.
5. Next we’ll revisit our placeObjectInTank() method, and change it to draw characters
into the window instead of the old char[][]. Let’s change the second parameter of this
method from char[][] tank to PApplet processing (the type of the processing field
within our Data object). Now we can use the processing.text(string,x,y) method to
draw the string s to the position x,y on the screen. It’s still the case that y increases while moving
from the top to bottom of the screen, and x increases from left to right. Don’t worry about what
part of the fish is aligned with the pixel position (x,y) yet… we’ll be making some other changes
before this becomes important. After the placeObjectInTank() method is drawing to the window,
executing your program should result in bunch of moving white text crammed in the upper left
corner of the screen. We’ll get to fixing this in the next step, but first let’s change the color that
text is being drawn in to black by calling processing’s fill(color) method:
1 data.processing.background(0,255,255); // colors entire window cyan/aqua
This method is overloaded (like background) to take three numbers as separate red, green, and
blue intensities, or to take a single grayscale number from 0 (black) to 255 (white). Which of
your methods do you think that processing’s fill method should be called from? See whether you
can think of multiple good arguments for putting this method call in different places.
6. Our old 32×8 character simulation has expanded to an 800×600 pixels window. And these new
dimensions are stored in fields named width and height within the processing object. Revise your
setup() and update() methods to make use of this new width and height. Be sure to reference
these values through the processing object, rather than hard-coding any 800s or 600s yourself.
After fixing these references, your four fish, six food, and one hook should be much more spread
out and easier to see.
7. Let’s go back to the placeObjectInTank() method again, and change it to draw images instead of
text. Download and extract the contents of this zip file to your computer. You should find a
folder named images that contains three image files: FISH.png, FOOD.png, and HOOK.png. You
need to move (or copy) this images folder directly into your project folder. After this folder is in
the correct location, we can load images from our placeObjectInTank() method by calling
processing’s loadImage(filename) method:
Notice that this method returns a new type of object: a PImage. After loading this image, we can
draw it using processing’s image(fishImage,x,y) method. The only problem is that this makes
everything looks like a fish! Try running it. Finish implementing this method so that it loads all
three images: FISH.png, FOOD.png, and HOOK.png, and then only draws the correct one
depending on whether the string argument passed in was “<(('”, “*”, or “J” respectively. To
make your hook to look even cooler, draw a line connecting it to the top of the screen using
processing’s line(x1,y1,x2,y2) method, which draws a line from position (x1,y1) to position
(x2,y2). Play around with moving this line a few pixels to the right of the hook’s center to align it
with the hook’s eye.
Note: Reloading each image every time any object is drawn may seem wasteful (because it is).
But don’t worry about fixing this yet, we’ll have some better tools at our disposal to improve
this part of our design in the next assignment.
HANDLING USER INPUT
8. The final step of this assignment is to add controls for a human to interact with our simulation.
When the user clicks the mouse on your simulation window, the hook should be moved to the
bottom of the screen directly below their mouse where it was clicked. We’ll accomplish this by
1 processing.fill(0);
1 PImage fishImage = processing.loadImage("images" + java.io.File.separator + "FISH.png");
defining a callback method which is automatically called by the Utility class whenever the mouse
is clicked. Here’s the callback method’s signature:
This method is called each time the mouse button changes from being released to pressed by the
user. The data object holds reference to all of your objects’ positions and the processing object.
And the screen position of the mouse (in pixels) is passed through the mouseX and mouseY
parameters.
9. The user will ultimately be trying to catch fish on this hook, which will be more interesting if we
vary the hook’s speed as it ascends. Instead of always moving up one unit per update, let’s have
the hook move faster as it gets closer to the top of the screen. Implement this feature by
modifying your calls to the moveAllObjects() method. Do NOT change the definition of this
method to implement this feature. Here’s a formula for the amount and direction that your hook
should move in any one update, which is based on the only hook’s current y position and the
height of the entire screen:
10. Congratulations on finishing this second CS300 assignment! After verifying that your work is
correct, and written clearly in a style that is consistent with the course style guide, you should
submit your work through zybooks. If the automated tests detect defects in your code, you may
fix those and re-submit for full credit, although you will need to wait an hour between
submissions. The most recent of your highest scoring submissions prior to the deadline of 17:00
on Thursday, September 21st will be used as part of your score for this assignment.
Additional grading tests will then be run against your highest scoring submission, to determine
the rest of your assignment grade.
1
2
3
4
public static void onClick(Data data, int mouseX, int mouseY)
{
}
1 // -(height + 50 - y)/50;