J*Man
Due to CMS by Friday, Feb 27.
In this assignment, you will create a simple video game called J*Man. In this
game, the player uses buttons to steer the star-like J*Man around a board,
capturing other pieces. The assignment will give you more experience with the
structure of object-oriented programs (e.g. subclasses, casting, and abstract
classes).
While the game appears simple, the methods in this assignment are quite
involved. It is important that you read and understand the directions before
you start with the assignment.
Table of Contents
Before You Get Started
Academic Integrity
We have given this assignment before. It is a good one, and students really
like it. Do not share your code with others. Do not obtain or look at a
copy of the earlier solution or a version being done by another student.
Such cheating helps no one, especially you, and it makes more unnecessary
work for us.
Unlike the Rhino assignment, it is highly unlikely that your code for
this assignment will look exactly like someone else's. This is the first
assignment that we will actively be using Moss to check for instances of
cheating and plagiarism.
Grading Policy
As with the previous assignment, you are to resubmit this assignment until you
pass. Once again,for this assignment, passing is considered 85%. You do not
have to get a perfect to pass.
We will not outline our grading scheme in this assignment. If you do not pass
you will be told what to revise. Hopefully, everything should be working
properly within one revision.
Collaboration Policy
You may do this assignment with one other person. If you are going to work
together, then form your group on CMS as soon as possible. If you do this
assignment with another person, you must work together. It is against the
rules for one person to do some programming on this assignment without the
other person sitting nearby and helping.
With the exception of your CMS-registered partner, you may not look at anyone
else's code or show your code to anyone else, in any form what-so-ever.
Getting Help
If you do not know where to start, if you do not understand the GUI framework,
or if you are completely lost, please see someone immediately. This can be the
course instructor, a TA, or a consultant. Do not wait until the last minute. See
the staff page to get
help.
Rules of the Game
To see the game J*Man in action, first download the following
jar file; this is our solution to the assignment. Put
the jar file onto your desktop and then double-click. On most systems, this
should launch the game and start it going. A window will open, with buttons, the
game board, and the game rules. It should look like the image to the right.
In the game there are four kinds of items.
- J*Man, a vaguely asterisk shaped character.
- Obstacles, white blocks which sit in place.
- Walkers, colored triangles that move about.
- Pillars, colored disks which do not move.
Both Walkers and Pillars may either be red, yellow, or green. As J*Man moves
about the board, the Walkers wander about slowly (in random directions), but
they do not change color. Conversely, Pillars do not move but they do change
color.
The goal of the game is to use the four navigation buttons to move J*Man about
the board until he has captured all the Walkers and Pillars. The pieces that
J*Man is allowed to capture is determined by its current color.
- A green J*Man can only capture red pieces
- A red J*Man can only capture yellow pieces
- A yellow J*Man can only capture green pieces
Whenever J*Man captures a piece, it takes on that piece's color. Hence the
challenge is to cycle the colors of J*Man appropriately to capture all the
pieces.
Both J*Man and the Walkers follow the following rule: if they try to move off
the board or try to move into a square that is occupied by something they cannot
capture (for a Walker, this means any occupied space), they do not move. After
each attempt by J*Man to move (regardless of whether it is successful), all the
Walkers and Pillars also get to perform one action. This action is determined
as follows:
-
Approximately 2/3 of the time (this is random), the action consists of
doing nothing.
-
If a Pillar gets to act (the other 1/3 of the time), then it randomly
chooses a color: red, green, or yellow.
-
If a Walker gets to act (the other 1/3 of the time), it randomly chooses a
direction - up, down, left, or right - and attempts a move in that
direction. If the move is illegal (e.g. there is something in the way), the
Walker does nothing.
Understanding the J*Man Application
The structure of this application is a bit more complicated than the previous
assignment. This assignment, like most real software applications, is not made
from a single class file. When you have a program that is made up of several
classes, it is important to organize the parts of a program in a logical and
coherent way, so that it is clear what each part is responsible for and so that
interactions between parts are kept reasonable. The larger and more complicated
the task of a program, the more important it is to have good organization.
In this section, we do three things.
- We introduce the model-view-controller (MVC) pattern.
- We introduce the source code for the assignment.
- We show how the source code conforms to the MVC pattern.
All of these are important for understanding the scope of this assignment.
Model-View-Controller Pattern
The classic way of organizing applications — particularly those that are
sit on a single computer and do not need to connect via the internet — is
using what is known as the model-view-controller paradigm. In this paradigm,
every single class is categorized as either a model, a view, or a controller.
The roles of each are detailed below.
Model
The model is a class that holds the application data. It provides getters and
setters to manipulate the data, plus some useful additional methods to perform
commonly used tasks on the data.
The Rhino class, which you worked on for the first assignment, is a
classic example of a model class. In this assignment, you will again work on
Model classes, though the will be more sophisticated than the Rhino
example.
View
A view is a class that displays a graphical user interface to the screen. It
also keeps track of when the user performs any input, such as typing or
moving/clicking a mouse. However, it does not tell the program what to do
when the user performs input. It only keeps track of the fact that it
happened.
A JFrame is a classic example of a view class. It displays
graphics, and notifies the program when the user clicks the "close box".
Controller
Controllers are the heavy lifters and they do everything else. They start up
the program and instantiate the other classes (e.g. the view and model) with
new-expressions. They also provide the methods that do something when the user
performs some input (e.g. presses a button). Finally, they also force the view
to refresh whenever it should be updated.
You have not written a controller class for this course yet. These types of
classes a bit beyond the scope of this course. However, you are welcome to look
at the source code to understand them better.
Assignment Source Code
Now that you roughly understand the model-view-controller-pattern, it is time to
look at the program source code. You should download the zip file
A3.zip. Unzip this file and put the contents in a new
directory. This zip file contains the following classes:
JManApp.java
-
This is the primary class for the application. It initializes all of the
objects in this application, and links them together (e.g. makes them fields of
each other so that they can "talk to each other"). It also has methods that
perform actions when you click on the buttons in the application.
In our application design, this is a
controller class.
JManFrame.java
-
This is a subclass of JFrame with buttons, panels, and other features.
It does not do anything with the buttons; it just arranges them on the
screen, while
JManApp has the methods that perform
actions when they are clicked.
In our application design, this is a
view class.
Piece.java
-
Instances of this class the game board, with all of the pieces described above.
It has methods for accessing the various pieces, as well as moving them about
the board.
In our application design, this is a
model class.
Piece.java
-
Instances of this class represent a element on the board in the game. It
includes information such as the type of piece, its color, and its
position.
In our application design, this is a
model class.
JMan.java
-
Instances of this class represent the player controlled JMan; it is a subclass
of class
Piece .
In our application design, this is a
model class.
All of these classes are explained in more
detail below. You will only need to modify (and extend) the Model classes.
The controller and GUI classes are already completed for you, as they are beyond
the scope of this course. At the end of these
instructions, we point you to some resources if you wish to learn more about
building a graphical application in Java. We urge you to study this material,
but you do not have to.
Running the Application
In order to run the application, the only file that you need to open in DrJava
is JManApp.java . This is the primary controller that starts
the application and initializes all of the other objects. If you compile and
use this in DrJava, DrJava will automatically use the other classes behind the
scenes.
To run the application — once you have opened and compiled
JManApp.java — type run JManApp in the
Interations pane. The window will pop up. It will look a lot like the image
above, except that the board is now completely black. That is because there are
no pieces in the game yet; it is your responsibility to add these.
J*Man Code Organization
Now that you are introduced to the concept of model-view-controller. We can
review how these classes all fit together.
Class JManApp
This is the primary class for running the application, and is the only one that
DrJava needs to open (though you will want to edit all of the Model classes).
When you run it, Java invokes the static method called main()
located in this class.
When run, JManApp creates instances of all of the other classes
with new-expressions. It also puts them in fields so they can "communicate"
with one another (e.g. call each other's methods). JManApp also
"listens" to button clicks; when a button click happens, it instructs the board
to rearrange its pieces and then requests the view to draw itself again. This
update-then-draw functionality is a classic example of what a controller does.
Class JManFrame
This class is a subclass of JFrame, which is associated with a window on your
monitor. It is a somewhat involved class because it lays out a lot of the visual
components. The primary thing to pay attention to is the fields. It has fields
for each of the buttons as well as a panel for displaying the board.
As a view class, this class does not tell the application what to do with these
buttons. Instead, you should look at the method addController .
This method is how we activate the buttons. Calling this method registers the
instance of JManApp as a listener for each of the buttons. Once an
object is registered as a listener, whenever you click on a button, the program
will call the method actionPerformed() in this object.
Inside this class file you will notice that there is an additional class called
JManPanel . Instances of this class as capable of drawing the board
on the screenn. A class that is defined inside of another class like this is
called an inner class. The reasons for using an inner class are a bit
complicated (it simplifies the code in very subtle ways); take CS 2110 if you
wish to learn more about this.
Class JManBoard
Instances of this class store a 2-dimensional array representing the state of
the board. While this array is a private field, this class has methods for
accessing the elements of the array. It also has methods for checking if a
space is occupied, and moving a piece from one location to another.
The most important method in this act() , which instructs the
board to update after user input. Most of the code that you will write in
this assignment will be part of this act() method. This method
also illustrates a bit of subtlety with our MVC pattern. This method is the
one "controlling" the game, moving the pieces about the board; why is it
not within a Controller class? That is because it is not an immediate
response to user input. A controller is generally limited to methods that
process user input, such as a button press. This method updates the state
of the board, making it more like a setter or getter function.
This class is almost completely finished for you, with the exception of the
method placePiece() , which you will complete on your own. However,
this is a very, very important class, and we advise you to study the class in
detail. In particular, you should look at the following methods:
- Function
isOnBoard() .
- Function
isEmpty() .
- Function
pieceAt() .
- Procedure
act() .
- Procedure
placePiece() .
For all of these methods you should read the specifications in detail. Then
you should look at their bodies (except for placePiece , which is
unfinished) to get a better understanding of how they work.
Classes Piece and JMan
The board needs to contain pieces and we need objects to represent those pieces.
All objects on the board are instance of the Piece class. This
is a model that contains the color of the piece, its position, and its type.
The type is encoded as an integer corresponding to one of the named constants
in the class Piece . As with Board , this class also
has an act() method to perform updates on the piece.
You will note that the act() in class Piece is
abstract. This is because each particular pieces (J*Man, obstacles, walkers,
pillars) all behave differently, and need their own walk method. Therefore, it
seems pointless to put an act() method in Piece .
However, we need some act() method in Piece for
the purpose of apparent (i.e. static) type. The JManBoard needs to
store all of the pieces in an array, and it needs to instruct them to act.
Because the array needs a type, JManBoard uses type
Piece , as every board piece will be an instance of a class that is
a subclass of Piece (for example, JMan ). As we saw in
class, the legality of method calls depends on the apparent type, not the real
(i.e. dynamic) type. Hence we put an act() method in
Piece to make the method calls legal, but we make it abstract with
the understanding that the subclasses are responsible for implementing it.
We have already start you off with one of these subclasses: JMan .
However, it is incomplete. A large part of this assignment will be finishing
JMan , as well as creating several other classes.
Assignment Instructions
Throughout this assignment, you should not need to modify either
JManApp or JManFrame . Instead, you will focus on the
other classes (JManBoard , Piece , and
JMan ), as well as writing a few new ones on your own.
We suggest that you complete the instructions below in the order provided. We
find that it is the simplest way to approach the assignment and allows for the
most testing. However, if you are comfortable with the assignment you are free
to pursue it in any order that you wish, such as completing the method
act() in JMan before creating the new classes.
Testing Guidlines
Before you get started, you should have an organized testing plan. If your
program does not work properly, we will send it back to you and you will be
forced to fix it. It is best that you get it right the first time.
You are welcome and encouraged to write JUnit tests — just as you did for
the class Rhino — for each of the classes that you work on.
Model classes are very natural classes to use for unit tests, as they do not
(directly) involve any user input that would be difficult to test. However,
this is not required, and we do not want you submitting any JUnit tests for
grading. We will simply grade your assignment based on how well it works, not
on how you tested it.
If you do not want to use JUnit tests, simply playing the game may suffice. But
keep in mind, the less testing you do, the more likely we are going to send it
back for revisions.
Finish Class Piece
The very first thing you should do is finish the class Piece . You
will notice that it has no fields and all of the constructors and methods are
all stubs. You need to add the appropriate fields, and fill out the bodies of
the constructors and methods. The only method that should not have a method is
act() , which is abstract.
Do not forget to use comments to specify the class invariants (e.g. the
properities of the fields). Class invariants for private fields are specified
with single-line comments, not JavaDoc comments.
Complete the Constructors to JMan
The constructors in the class JMan are also stubs. Complete them,
using a a call to the super-class constructor in each case. You should only
need one line to implement each constructor.
With that said, you might find it tricky to implement the first constructor
for JMan in one line. The constructor in Piece takes a color, not an int.
Therefore, it would appear that the right way to write the JMan constructor is
as follows:
if (c == 0) {
super(Piece.JMAN, x, y, Color.red);
} else if (c == 1) {
super(Piece.JMAN, x, y, Color.green);
} else {
super(Piece.JMAN, x, y, Color.yellow);
}
However, this does not work. The call to super must
be the very first line in the constructor. Therefore, you need to figure
out how write the code above as a single call to super . Perhaps using
conditional expressions (e.g. a ? b : c )?
You do not need to complete the act() method yet. We will come to
that later.
Fix placePiece()
If you run the game, you will see that you still have a black screen. That is
because, even though you have filled in (most of) the methods of
Piece and JMan , the game still does not add any of the
pieces to the board.
Fix placePiece so that it handles (only) the case of parameter
t being Piece.JMAN . You should read the specification
of placePiece carefully to figure out how to do this. Now, when
you evaluate run JManApp in the interactions pane, you should see a
board with a J*Man in its upper left corner (position [0, 0]).
Add New Pieces
According to the rules of the game, you will need three more types of pieces:
walkers, pillars,and obstacles. You need to make a class for each one of these.
They each should be a subclass of Piece and should return the
appropriate value for getType() . Look at your implmentation (so
far) of JMan to see what we are looking for.
At this stage of the assignment, you should just focus on the constructors and
toString() . The act() method can and should remain as
a stub, just as it still is in the class JMan . In writing the
constructors, make sure to specify them properly; look at the specifications of
the constructors in JMan as examples.
For the method toString , you should look at the one we have written
for you in class JMan . This method can be invaluable in debugging.
For example, you can find information about a piece p simply by
executing System.out.println(p).
When you are done with these new classes, it is time to test them. You can test
them either by a JUnit test, or proceeding on to the next step.
Complete placePiece()
Fix placePiece in JManBoard so that it handles
parameter t being any one of the new types of piece (e.g. walker,
pillar, obstacle). Now when you evaluate run JManApp , you should
see that kind of pieces appearing on the board. While you will not be able to do
anything with them, you should be able to get some feel as to whether or not
they are being placed correctly. Do you have the right number of pieces (10
walkers, 10 pillars, 20 obstacles)? Do you have a reasonable ratio of colors?
Complete act()
The final step is to complete the method act() for all four of the
Piece subclasses: JMan , Obstacle ,
Walker , and Pillar . You might wish to do
JMan first, but that is the hardest act() method to
write and is best left to the end. In fact, you might notice that we have
stubbed in a few extra method in JMan to help you write the method
act() .
For the other classes, you should pur in a good specification for the procedure
act() ; look at the one we give you for JMan as an
example. Then write the method body. Look again at the
rules above to see what each piece should be doing in its
act() method.
The classes JMan and Walker require special attention.
You have to account for moving in one of four directions: up, down, left, and
right. You should not have essentially duplicate code four times, once
for each direction. That leads to a long, unwieldy, difficult-to-debug and
maintain method. Instead, your code should do the following:
-
Calculate the coordinates of the proposed position (px, py) to
move towards.
-
Process the proposed move to (px, py).
If you do not write your code this way, you will be required by the grader to
change it later.
Finishing the Assignment
You have now completed the assignment. In order to test that everything is
working properly, you should play the game. Start the game and see what happens
to the pieces when you click an up, down, left, or right button. For walkers and
J*Man, be sure you try all possibilities. Try to move off the board in any
direction; try to move to an empty square; try to move to an occupied square.
If you are happy with the game, go back and look at the source code in all of
the .java files. Make sure that you have satisfied our
style guide. This
includes the following:
-
All lines should be short enough that horizontal scrolling is not necessary
(~80 characters).
-
There should be a blank line before the specification of each method and
none after the specification.
-
The class invariants should be there (e.g. you have listed constraints for
all the fields).
- The specifications for all of the methods should be complete.
- The files all should be properly indented.
To ensure the last one, select an entire .java file and hit tab;
DrJava will then auto-indent for you.
Turning it In
To make grading simpler, we want you to submit all of the files, including those
that you did not modify (e.g. JManApp.java and
JManFrame.java ) Put all of the .java files in a
folder and produce a ZIP file called a3jman.zip . Upload this ZIP
file onto CMS by the due date: Friday, March 1st at 11:59PM
As before, check the CMS daily until you get feedback from a grader. Make sure
your CMS notifications for CS 1130 are set so that you are sent an email when
one of your grades is changed.
Addendum: Building Graphical Applications in Java
The best place to learn about building GUIs in Java is to read/listen to lessons
17-1 to 17-4 of the CD ProgramLive. You already know that a JFrame is a
window on your monitor. Lesson 17-1 tells you how you can add components to the
JFrame, like buttons and text fields. Lesson 17-2 then shows you the basic
components that one can add to a JFrame, and for each one, you can download the
code for the demo. Lesson 17-3 then tells you about layout managers, which are
used to put components in various positions of a JFrame. Finally, lesson 17-4
shows you the basics of "listening" to actions, like a click of a
button.
With these lessons, in less than 1.5 hours, you can have a good idea about how
GUIs are used. It is then fairly simple to look at a view class like
JManFrame and see how the GUI is constructed. Note that GUI is
laid out in the constructor, as we want the GUI to be complete as soon as
the view class is allocated. We use Box objects as our layout manager to make
everything line up. The view class also packs the frame, so that everything
is the right size, and puts it in the right position.
Note, however, that the view is not immediately visible. That is because
we have not yet registered listeners with the buttons; the view would
not work properly if made visible too soon. To implement the listeners, we rely
on the controller class (e.g. JManApp ). In the MVC pattern, the
controller class creates the instance of the view class, and not vice versa. So
the controller class has to pass itself to the view class in order to register
listeners. This is done in the method addController . We
could have done this in the constructor (by adding a parameter for
JManApp in the constructor). However, since we need to add and
remove listeners every time we create a new game, we decided to make it a
separate method. Only after this method is called are we ready to make
the window visible.
If you are interested in learning more about creating graphical applications
in Java, you should take CS 2110.
About the MVC Pattern
We should mention that our approach to the MVC pattern is not the only one. In
particular, we used an MVC pattern with lightweight controllers. Our
controller is only used for initializing the application, and receiving
user-input events (e.g. button presses). However, there is the alternative
approach of using heavywight controllers. In this approach, the models
would never have anything other than getter and setter methods, while the
act() methods would be part of the controller.
Why would we ever do this? In a game, the actions of a piece or a character
can get quite complex. A character might lack certain abilities — such
as swimming or a double-jump — until getting a power-up. Instead of
trying to code every single possible ability in the class to begin with, it
is easier to put these abilities each in separate controller classes and apply
them to the player as necessary. This is a style of programming known as
Aspect-Oriented Programming, which is covered some in CS 3110.
Additionally, many of these topics are covered in CS 3152, the game design
course.
|