![]() |
Problem Set 9 Due on Tuesday, April 29 |
The purpose of this problem set is to give you experience with declaring Java classes, drawing object diagrams, using Java graphics, and playing with AnimationWorld. In Task 1, you will draw object diagrams showing the state of several objects. In Task 2, you will create a class the models simple cartoon faces, and draw these faces. In Task 3, you will create sprite classes for some simple animations.
There are also two optional extra credit problems. Extra Credit Challenge 1 is an open-ended opportunity to draw any picture(s) of your own design. In Extra Credit Challenge 2 is a chance for you to create your own animation.
All code for this assignment is available in the ps9_programs folder in the cs111 download directory on the CS fileserver.
Faces.java
from
Task 2. If you are unable to complete all the
subtasks, turn in the version of your code that
solves those subtasks you have completed.
Spinner.java
from Task 3.
MyPicture.java
from
(optional) Extra Credit Challenge 1.
ps9_programs
folder. In particular,
Faces
subfolder should
contain your final version of Faces.java
.
Spinners
subfolder should
contain your final version of Spinner.java
.
MyPicture
subfolder should
contain your final version of MyPicture.java
(if you did the first extra credit challenge).
MyAnimation
subfolder should
contain your final version of any sprite and animation
classes you created (if you did the second extra credit challenge).
The purpose of this problem is to give you some practice drawing object diagrams. Recall that an object diagram shows a collection of interconnected class instances and arrays:
Consider the following Java class declaration:
public class Node { public int value; public Node [] subnodes; public Node (int value, Node [] subnodes) { this.value = value; this.subnodes = subnodes; } public Node (int value) { this.value = value; } }
The Node
class describes instances that have
two instance variables: a value
variable that holds an integer, and
a subnodes
variable that holds an array of
other Node
instances.
Here is a sequence of statements that creates and manipulates Node
instances:
Node [] nodes = new Node [5]; nodes[4] = new Node(4); nodes[3] = new Node(3, new Node [] {nodes[4]}); nodes[2] = new Node(2, new Node [] {nodes[4], nodes[3]}); nodes[1] = new Node(1, new Node [] {nodes[2], nodes[3]}); nodes[4].subnodes = new Node [] {nodes[1]}; nodes[1].subnodes[1].subnodes[0] = nodes[1].subnodes[0]; nodes[1].value = nodes[2].subnodes[1].subnodes[0].value + nodes[1].subnodes[0].subnodes[0].value;
In this problem, you are to draw a single object diagram that
depicts the state of all objects (and their component variables)
in ObjectLand after the above eight statements are executed.
Your diagram should also include the local variable nodes
.
Follow these conventions:
Node
class should be draw as a large box
labeled Node
that contains two instance variables.
null
pointer should have a slash
drawn through it.
In this problem, we will model simple cartoon faces like those shown below:
Each face is characterized by the following state:
For example, the following table shows the values for the color (r = red, g = green, and b = blue), happiness (h) and sleepiness (s) of each face in the corresponding position in the figure above:
r=255,
g=0,
b=0, h=0.0, s=0.0 |
r=255,
g=63,
b=0, h=0.25, s=0.0 |
r=255,
g=127,
b=0, h=0.50, s=0.0 |
r=255,
g=191,
b=0, h=0.75, s=0.0 |
r=255,
g=255,
b=0, h=1.0, s=0.0 |
r=255,
g=0,
b=63, h=0.0, s=0.25, |
r=255,
g=63,
b=63, h=0.25, s=0.25 |
r=255,
g=127,
b=63, h=0.50, s=0.25 |
r=255,
g=191,
b=63, h=0.75, s=0.25 |
r=255,
g=255,
b=63, h=1.0, s=0.25 |
r=255,
g=0,
b=127, h=0.0, s=0.50 |
r=255,
g=63,
b=127, h=0.25, s=0.50 |
r=255,
g=127,
b=127, h=0.50, s=0.50 |
r=255,
g=191,
b=127, h=0.75, s=0.50 |
r=255,
g=255,
b=127, h=1.0, s=0.50 |
r=255,
g=0,
b=191, h=0.0, s=0.75 |
r=255,
g=63,
b=191, h=0.25, s=0.75 |
r=255,
g=127,
b=191, h=0.50, s=0.75 |
r=255,
g=191,
b=191, h=0.75, s=0.75 |
r=255,
g=255,
b=191, h=1.0, s=0.75 |
r=255,
g=0,
b=255, h=0.0, s=1.0, |
r=255,
g=63,
b=255, h=0.25, s=1.0 |
r=255,
g=127,
b=255, h=0.50, s=1.0 |
r=255,
g=191,
b=255, h=0.75, s=1.0 |
r=255,
g=255,
b=255, h=1.0, s=1.0 |
We will represent a face by an instance of the Face
class,
which is described by the following contract:
Face Contract
Constructor Methods:
public Face (Color c, double h, double s)
Constructs and returns aFace
instance whose color isc
, whose happiness ish
, and whose sleepiness iss
.
public Face ()
Constructs and returns aFace
instance whose color is yellow, whose happiness is 1.0, and whose sleepiness is 0.0.Instance Methods:
public Color getColor()
Returns the color of this face.
public double getHappiness()
Returns the happiness of this face.
public double getSleepiness()
Returns the sleepiness of this face.
public void setColor (Color c)
Changes the color of this face toc
.
public void setHappiness (double h)
Ifh
is in the the range [0.0, 1.0], changes the happiness of this face toh
. Otherwise, leavesh
unchanged and displays an error message indicatingh
is out of range.
public void setSleepiness (double s)
Ifs
is in the the range [0.0, 1.0], changes the sleepiness of this face tos
. Otherwise, leavess
unchanged, and displays an error message indicatings
is out of range.
public void draw (Graphics g, Rectangle r)
Draw a picture of this face inscribed in rectangler
within graphics contextg
. Note thatRectangle
is Java's standard rectangle class in thejava.awt
package. See the Rectangle contract page for theRectangle
contract, and the the CS111 Contracts page for other contracts.
public String toString ()
Return a string representation of this face. A face with red/green/blue color values r, g, and b and with happiness h and sleepiness s should have the following string representation:
"Face[color=java.awt.Color[r=r,g=g,b=b]; happiness=h; sleepiness=s]"
Note that you can use the
toString()
method for colors to get the string representation of a color.
In this subtask, you will define a preliminary version of the Face
class. A skeleton of this class can be found in the file Face.java
within the Faces
subfolder of the ps9
folder.
You are flesh out the skelelton with instance variable declarations,
constructor method declarations, and instance method declarations so that
it implements the Face
contract given above except
for the draw()
method. Rather than actually drawing the face
in the given rectangle, your initial draw()
method should
simply display a string representation of the face in the Java Console
window (via System.out.println
).
For example, when you test the default applet ManyFaces.html
,
you should get the following output:
Face[color=java.awt.Color[r=255,g=0,b=0]; happiness=0.0; sleepiness=0.0] Face[color=java.awt.Color[r=255,g=0,b=63]; happiness=0.0; sleepiness=0.25] Face[color=java.awt.Color[r=255,g=0,b=127]; happiness=0.0; sleepiness=0.5] Face[color=java.awt.Color[r=255,g=0,b=191]; happiness=0.0; sleepiness=0.75] Face[color=java.awt.Color[r=255,g=0,b=255]; happiness=0.0; sleepiness=1.0] Face[color=java.awt.Color[r=255,g=63,b=0]; happiness=0.25; sleepiness=0.0] Face[color=java.awt.Color[r=255,g=63,b=63]; happiness=0.25; sleepiness=0.25] Face[color=java.awt.Color[r=255,g=63,b=127]; happiness=0.25; sleepiness=0.5] Face[color=java.awt.Color[r=255,g=63,b=191]; happiness=0.25; sleepiness=0.75] Face[color=java.awt.Color[r=255,g=63,b=255]; happiness=0.25; sleepiness=1.0] Face[color=java.awt.Color[r=255,g=127,b=0]; happiness=0.5; sleepiness=0.0] Face[color=java.awt.Color[r=255,g=127,b=63]; happiness=0.5; sleepiness=0.25] Face[color=java.awt.Color[r=255,g=127,b=127]; happiness=0.5; sleepiness=0.5] Face[color=java.awt.Color[r=255,g=127,b=191]; happiness=0.5; sleepiness=0.75] Face[color=java.awt.Color[r=255,g=127,b=255]; happiness=0.5; sleepiness=1.0] Face[color=java.awt.Color[r=255,g=191,b=0]; happiness=0.75; sleepiness=0.0] Face[color=java.awt.Color[r=255,g=191,b=63]; happiness=0.75; sleepiness=0.25] Face[color=java.awt.Color[r=255,g=191,b=127]; happiness=0.75; sleepiness=0.5] Face[color=java.awt.Color[r=255,g=191,b=191]; happiness=0.75; sleepiness=0.75] Face[color=java.awt.Color[r=255,g=191,b=255]; happiness=0.75; sleepiness=1.0] Face[color=java.awt.Color[r=255,g=255,b=0]; happiness=1.0; sleepiness=0.0] Face[color=java.awt.Color[r=255,g=255,b=63]; happiness=1.0; sleepiness=0.25] Face[color=java.awt.Color[r=255,g=255,b=127]; happiness=1.0; sleepiness=0.5] Face[color=java.awt.Color[r=255,g=255,b=191]; happiness=1.0; sleepiness=0.75] Face[color=java.awt.Color[r=255,g=255,b=255]; happiness=1.0; sleepiness=1.0]
draw()
method so that it draws an alert,
happy face with the face's color in the specified
rectangle. Your method should ignore the actual
happiness of the face and simply assume that it is 1.0.
Similarly, your method should ignore the actual
sleepiness of the face, and just assume that it is 0.0.
However, your method should draw the face
using the actual color of the face.
So when you run the ManyFaces.html
applet,
the goal is to get the following picture:
Below is a diagram of a happy face inscribed in the unit square indicating the placement of the eyes, nose, and mouth. You should draw the happy face exactly as depicted in this diagram.
Notes:
Graphics
class presented
in lecture and lab. As part of doing this problem, you should
consult the contract for the Graphics class.
You will also need to use the contracts for the
Rectangle
and
Polygon
classes.
Graphics
class expect
integers as arguments. The java compiler will complain if you
pass a floating point number rather than an integer as an argument
to one of these methods. For instance, if
g
denotes a Graphics
instance and
r
denotes a Rectangle
instance,
then the following is incorrect:
g.drawLine(r.x + (0.1 * r.width), r.y + (0.3 * r.height), r.x + (0.7 * r.width), r.y + (0.6 * r.height));
This problem can be fixed by using an integer cast expression
(int) E
to convert the result of a floating point
expression E
to an integer. A corrected
version of the above example is:
g.drawLine(r.x + (int) (0.1 * r.width), r.y + (int) (0.3 * r.height), r.x + (int) (0.7 * r.width), r.y + (int) (0.6 * r.height));
OneFace.html
applet. You can do this
by moving OneFace.html
before
ManyFaces.html
in the Face.mcp
project file.
Here is the window produce by this applet:
draw()
method so that it correctly shows
droopy eyelids for sleepy faces, as shown below:
A face with sleepiness factor s (between 0.0 and 1.0) should have "eyelids" covering a fraction s of the height of the eyes from the top to the bottom. This effect can be achieved as follows:
Note that, according to its contract,
the drawOval()
method
covers an area that is width + 1 pixels wide and
height + 1 pixels tall. In contrast, the
the fillOval()
method
covers an area that is width pixels wide and
height pixels tall.
Because of this discrepency, to get your picture to
"look right" you may need to subtract 1 from the
width and height arguments of drawOval()
.
drawMethod()
so that it takes
into account the happiness of the face. A face with
happiness 0.0 should have a line as a mouth, while
larger happiness values (up to 1.0) should be drawn
as filled half-ovals whose height is proportional
to the happiness value.
For example, here are faces whose happiness value changes from left to right:
Here is the specification for the mouth that you should implement:
Math.max()
method, which returns the maximum of two integers.
The above specification can be implemented via a single
invocation of the fillArc()
method that
handles all happiness values between 0.0 and 1.0.
The key to getting this to work is to determine
the coordinates of the rectangle in which the arc is
inscribed as a function of the happiness value.
Do not attempt to do this by trial and error!
Instead, determine the correct formula on a sheet
of paper before you attempt to implement this
part!
This problem description contains an embedded AnimationWorld applet.
Experience shows that this applet may run fine in some browsers
but not in others. If you cannot get the applet
to work in one browser, try another one instead.
If you can't find any browser that works, you can run the applet
in CodeWarrior from the Test
subfolder of ps9_programs/Spinners
.
The following Spinners
animation shows "spinning"
disks of various sizes and colors:
In this problem, your goal is to flesh out the declaration
of the Spinner
class
(a subclass of Sprite
)
within the Spinners
folder
so that it describes the behavior of spinning two-colored disks.
Instances of Spinner
should be created via the following
constructor method:
public Spinner(int x, int y, int radius, int dRadius, Color color1, Color color2);
Creates a spinning disk with radiusradius
whose center is at the position (x
,y
) in the Java coordinate system. The disk appears to be "hanging" by a black string from the top of the window and appears to have two "sides", one of which is coloredcolor1
, and the other of which is coloredcolor2
. Initially a circle ofcolor1
should be displayed. The "spinning" motion is simulated by changing the horizontal radius of the oval by the amountdRadius
at every invocation ofupdateState()
. The height of the oval should not change.
For example, the animation shown above is specified as follows:
import java.awt.*; class SpinnerAnimation extends Animation { public SpinnerAnimation() { addSprite(new Spinner(200,100,50,3,Color.red,Color.blue)); addSprite(new Spinner(250,150,125,1,Color.yellow,Color.green)); addSprite(new Spinner(300,200,50,5,Color.pink,Color.gray)); addSprite(new Spinner(400,200,100,2,Color.cyan,Color.magenta)); setNumberFrames(Animation.NO_MAX_FRAMES); } }
To complete this problem, you will have to
Spinner
class.
These should all be private
.
Spinner()
constructor method specified above.
resetState()
,
updateState()
, and drawState()
described in the
Sprite contract.
Spinner
implementation, run
the animation in the SpinnerShowcase
applet. A correct definition of Spinner
will give rise to the same behavior shown in the test applet
(a copy of which can be found in the Test
subdirectory).
This is a completely optional problem. You should only attempt it after completing the rest of the assignment.
You can use Java graphics as a tool to create fascinating pictures. Here is a chance to be artistically creative and earn some extra credit points at the same time.
For this challenge, flesh out the paint()
method in the MyPicture
class within
the MyPicture
folder to draw whatever
picture you imagine. If you like, you can draw more
than one by making copies of MyPicture.java
where the files (and the contained class) have different
names.
Notes:
You can use AnimationWorld to create dazzling animations that show off your artistry and your programming talents. Here is a chance to be creative and earn some extra credit points at the same time.
For this challenge, build an animation of your own design. You may use existing sprites that we have studied, but you should create and use at least one new kind of sprite from scratch.
The MyAnimation
subfolder of the
ps9_programs
folder contains
a copy of the sprites and animations shown
in Lecture 21. This is a good starting point
for your own animations. You may edit the
existing files or create ones of your own.
Add any animations you create to
MyShowcase.java
.
Notes: