Description
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 (Ctrl). 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 ORGANIED
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 while(true 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.
MOING FROM TET 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(“nnn”) 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. ero 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 HOO.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 HOO.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.
HANDING SER INPT
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 mouse 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 1st 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.