CompSci 307
Spring 2019
Software Design and Implementation

Thinking in Objects: Methods and Encapsulation

The goal of this lab is to work together to refactor the given code to make better use of the existing classes by giving them more methods that use instance variables that are hidden from the main class. Additionally, you will make a simple "test case" to practice working with Timelines.

Getting Started

For this lab exercise, you must work together with someone else in the class (for example your partner for the Game project):

Discussion

Use Gitlab's markdown format to record the group's answers in the file called DISCUSSION.md that is included with the example code. IntelliJ includes a markdown editor that provides a preview or here is a web-based editor that provides similar functionality and can be shared like Google Docs.

Start by reading over the code to see if you have any questions about how it works. Currently, one rectangle moves back and forth across the screen to block the player's "frog" from moving from the bottom of the screen to the top. Your ultimate goal is to make any number of blocks moving back and forth across the screen at random speeds.

To begin discussing the code's design, spend some time evaluating the code using the following questions as a guide:

Refactor the Code

As a reminder, try to practice using the suggested workflow to integrate new versions of the code with the other person's copy of the code regularly — start with each person making their own separate branch.

Each person should choose a class (either Mover or Block) in which to create the new methods you discussed (without changing the signature of the existing methods except perhaps the constructor), then merge the code (this should produce no conflicts since the Game class should not be refactored yet), then work together to refactor the Game class.

You should be able to do most of this simply by moving the existing code to the new classes and then calling the new methods in place of the old code with the appropriate parameters. In the current design, the method getShape() is a necessary evil because it needs to be passed to OpenJFX methods that require it, but the Game class is accessing it far too often and thus doing too much work that an active object could be doing to share the "code intelligence". In fact, the ultimate goal is that, when completely refactored, the Game class would not call any methods directly on the Rectangle class (e.g., getX(), setX(), setFill(), etc.). Instead those calls should be done in either the Mover or Block classes (so, for example, we could change the Rectangle to an ImageView without changing the Game class code). Thus you will know you are "done" when the only calls to getShape() within the Game class are in the add() calls within the setupGame() method and all the work previously done is encapsulated in well named methods that are called on the appropriate object.

Revisit the discussion quesitons above to see if refactoring the code has changed what you think about the answers you gave, especially the methods you thought each class should have and what methods should be public or private. Add your new thoughts to the discussion file.

Adding a Feature

Update the code to add two new features:

Each person should choose a feature to work on in their branch, then merge the code.You may make any changes to the code you think are warranted (functional, organizational, or creating new classes) and feel free to discuss the changes with each other (either for better understanding OpenJFX or to avoid conflicts), and it should be possible to make these changes without creating a merge conflict.

Testing

To prepare for testing your game project, write the framework for testing your code in this lab together.

The actual "test" will simply be to change the color of all the blocks a given number of times in an animation that lasts one second when a numeric key is pressed. To do this, you will pause() the current Timeline (stored as myAnimation), then create a new Timeline object that will last a fixed number of steps instead of an INDEFINITE number. The KeyFrame object for this new Timeline will will call the flash() method instead of the step() method. After the new Timeline's animation ends, you can either restart the original Timeline by pressing the SPACE key or look up how to do it automatically using the method setOnFinished().

To think more about the role of testing in games, answer these discussion questions:

Submission

At the end of class, use Gitlab's Merge Request to submit your group's answers to the discussion questions above and refactored code to the original organization repository. Make sure the NetIDs of everyone in the group are in the title of your Merge Request and in the markdown file.