Comp 110 Emoji

Points: 500

Full Extra Credit Due Date: Wednesday 3/22 at 11:59PM

Normal Due Date: Friday, 3/24 at 11:59PM

In this problem set, you'll create your own emoji using only Java code. This is the first open ended problem set in COMP110, so we encourage you to have fun with it! PS4 is all about getting your hands dirty with code while being creative. 

A few of last semester's best submissions are pictured above. Yours does not need to be this fancy, this is a high bar. However, if you're feeling ambitious, the UTAs and I love having our socks knocked off by COMP110 student code!

Tip #0: Start early!

Tip #1: Before writing any code, sketch your emoji on graph paper. Aim to work in a coordinate system of about 100 x 100. Know that one requirement is to use at least one rectangle, one circle, and one path (series of lines) in your final emoji.

When you begin coding, you will break your emoji down into simpler component classes (e.g., nose, mouth, eye, etc.) whose only concern is creating the shapes for that individual part. Finally, you will assemble your emoji out of these parts, kind of like assembling a Mr. Potato head.

We are providing stencil code to help get you started with this assignment. You'll use real JavaFX classes while writing your own methods, constructors, and field. This is challenging material and all of the concepts we've covered in lecture are coming together in this assignment! When you've completed it, no matter what your Emoji ultimately looks like, you can be really proud of the work you have put in to get to this point in COMP110!

Getting Started: Import the PS4 Project

To get started, follow these steps to install the Support Code for PS4.

  1. Start Eclipse
  2. Select and copy the following link to your clipboard: https://github.com/comp110/17S-PS4-Emoji.git
  3. Click the File menu
  4. Select "Import"
  5. Double click "Git" to expand the folder
  6. Double click "Projects from Git"
  7. Double click "Clone URI".
  8. The "URI" field should already have the URI you copied in Step 2 in it. If it does not, paste the URI from step 2 in it. Click next.
  9. Ensure there's a check beside of "master". Click next.
  10. In the "Directory" field, click "Browse". Navigate to your documents folder and select the COMP110 folder. Click next.
  11. Ensure "Import existing Eclipse projects" is selected. Click next.
  12. Ensure the correct Problem Set folder is checked. Click finish. Run the runner. You should see a blank canvas.

Part A. Emoji's Components

There are a few requirements you must fulfill in order to receive full credit. Outside of these requirements you have complete creative control over your drawings and your program's design.

Requirement A.0 - You must use at least one Rectangle, one Circle, and one Path in your emoji. Reference documentation for these classes is included after Part B in the "Library Class Reference" section. Where and how you choose to use these shapes in your emoji is up to you. For example, if your FaceShape uses a Rectangle and your Eye uses both a Path and a Circle, you have satisfied requirement A.0. 

Tip #4: When you are working on individual components in Part A, try to "anchor" them around the coordinate 0, 0. Do not move them to their eventual coordinates yet, just get their look right. When you reach the point of bringing together your emoji in Part B, you can precisely position each piece on it then.

FaceShape

Your FaceShape is the background that gets layered behind your other pieces (mouth, nose, eyes). Be as creative as you'd like for your FaceShape.

We are providing stencil code for this class to help get you started. It has a constructor with a Color parameter for the FaceShape's "tone". This parameter is assigned to the field _tone. We are also providing getter and setter methods for this property, as well.

You should start the code for this problem set by first understanding how our stencil code fulfills requirements A.1 and A.3.0 for you. Then you should complete requirements A.2 and A.3.1 on your own. After that, proceed on to the Mouth class.

FaceShape Requirements:

  • Requirement A.1 - FaceShape must have a single parameter constructor which takes a Color parameter to initialize the FaceShape's tone. It must also have a getter and setter for this property named getTone and setTone, respectively. This requirement is already completed for you in the stencil code as long as you do not remove or modify it.
  • Requirement A.2 - At least one Shape in the Group returned by the shapes method (described below in A.3) must be filled with Color _tone field.
  • Requirement A.3.0 - Complete the implementation of the shapes method. It should have the following characteristics:
Visibility:   public
Return type:  javafx.scene.Group
Name:         shapes
Parameters:  
     none

The method definition of the shapes method has a few requirements:

  • Requirement A.3.1: The Group returned must have at least one shape or path added to it.

Mouth

The shapes for your emoji's mouth will be constructed in this class.

You will need to first add a Mouth class to the project. You should add this class to the comp110 package. To do so, right click on the comp110 package in Eclipse and select new Class. You will need to name the class Mouth with exact capitalization and spelling matching.

You will need to declare a shapes method in the Mouth class. The method declaration has the exact same specifications as Requirement A.3's above.

Once you have Mouth's shapes method declared, you can begin working with it visually by modifying the Runner to draw a Mouth instance's shapes rather than a FaceShape instance's. To do so, in the main method, instantiate a Mouth, assign it to a local variable, and pass the return value of calling its shapes method to a new AutoGUI. Here is the code to achieve this:

public class Runner {
  public static void main(String[] args) {
        Canvas canvas = new Canvas();
        
        // FaceShape aFaceShape = new FaceShape(Color.LIGHTBLUE);
        // canvas.draw(aFaceShape.shapes());
        Mouth aMouth = new Mouth();
        canvas.draw(aMouth.shapes());
  }
}

Mouth Requirements

  • Requirement A.3 (same as above) - Mouth's shapes method must also satisfy requirement A.3 as described above.
  • Requirement A.4 - This class does not require a constructor. However, if you are going above and beyond and give your Mouth class some fields that need to be initialized in a constructor, we do require Mouth to have a 0-parameter constructor.

Nose

Add a Nose class to the comp110 package, as well. Follow the same steps as Mouth.

The shapes for your emoji's nose will be constructed here. The process for beginning work on your Nose class and seeing your visual progress on it are the exact same as the process for Mouth (see above).

Nose Requirements

  • Requirement A.3 (same as above) - Nose's shapes method must also satisfy requirement A.3 as described above.
  • Requirement A.4 - Same as above for Mouth.

Eye

Your Eye class should represent a single eye *NOT* both eyes. When you get to putting together your Emoji class, you will create two instances of the Eye class and position them individually.

Begin by adding an Eye class to the comp110 package.

Eye requires an irisColor property, just like FaceShape's tone property. Refer back to your FaceShape for help here. Its requirements are described in A4.

Eye Requirements

  • Requirement A.3 (same as above) - Eye's shapes method must also satisfy this requirement.
  • Requirement A.5 - Eye must have an irisColor Color property. Eye's shapes method (A.3) must fill one of the shapes returned with the iris Color. Below are the specific requirements you'll need to satisfy.
Field:
  Visibility:  private
  Type:        javafx.scene.paint.Color
  Name:        _irisColor
Constructor:
  Visibility:  public
  Parameter:
      Type:    javafx.scene.paint.Color
      Name:    irisColor
  Requirement: The constructor must assign the irisColor parameter
               to the _irisColor field.
Getter Method:
  Visibility:  public
  Return Type: javafx.scene.paint.Color
  Name:        getIrisColor
  Parameters:  none
  Requirement: Return the _irisColor field.
Setter Method:
  Visibility:  public
  Return Type: void
  Name:        setIrisColor
  Parameter:
      Type:    javafx.scene.paint.Color
      Name:    irisColor
  Requirement: Assign the irisColor parameter to the _irisColor
               field.

Part B. Implement your Emoji

Now that you have all your Emoji's components built... it's time to compose them in the Emoji class!

Go ahead and add a class named Emoji to the comp110 package.

Requirement B.0 - Your Emoji class must have at least 5 fields: faceShape, mouth, nose, leftEye, rightEye. (If you are building a one-eyed emoji, it still needs both leftEye and rightEye properties, however, you are free to position one eye directly over the other.) See the list of B.0 requirements just below for the specific names you must use for the field, setter, and getter for each property.

Each of these properties should have its own field declared. Only the faceShape, leftEye, and rightEye properties need to have getter and setter methods. Their types should correspond to the respective classes you implemented in Part A.

  • B.0.0 - _faceShape
    • Private field named _faceShape of type FaceShape declared
    • Implement a getter named "getFaceShape" for this field
    • Implement a setter named "setFaceShape" for this field
  • B.0.1 - _mouth
    • Private field named _mouth of type Mouth declared
  • B.0.2 - _nose
    • Private field named _nose of type Nose declared
  • B.0.3 - _leftEye
    • Private field named _leftEye of type Eye declared
    • Implement a getter named "getLeftEye" for this field
    • Implement a setter named "setLeftEye" for this field
  • B.0.4 - _rightEye
    • Private field named _rightEye of type Eye declared
    • Implement a getter named "getRightEye" for this field
    • Implement a setter named "setRightEye" for this field

Requirement B.1 - Your Emoji class should have a zero-parameter constructor. In the constructor, you should initialize each of your fields to a new instance of its respective class. (i.e. assign _faceShape a new FaceShape object).

Requirement B.2 - Your Emoji class must have a shapes method, with the same requirements as in requirement A.3. Emoji's shapes method should return a Group containing all of the shapes of its components added to it.

To achieve this, you will need to call the shapes method of each of the Emoji's fields. Consider declaring local variables to hold each of the returned Groups from your components. Once you have a component's Group of shapes, you can call setTranslateX and setTranslateY on each component Group to place it in the correct position on the Emoji.

To see your Emoji class and tweak its component's placements, modify your Runner to draw an instance of your Emoji class' shapes.

Library Class Reference

Here are the Shapes of JavaFX you must use in this problem set and some of their most useful methods. Remember: you must import a class from another package before you can use it in your own classes.

For additional challenge and creative flexibility, you are free to use any Shape in the JavaFX library's javafx.scene.shape package. More information on this is provided in the "Hacker Edition" section of this problem set, written at the bottom.

javafx.scene.shape.Group

  • Group() - Default constructor.
  • void setTranslateX(double x) - Move the Group along the x-axis.
  • void setTranslateY(double y) - Move the Group along the y-axis.
  • void setRotate(double degrees) - Rotate an entire group of shapes.
  • void setScale(double factor) - Scale a group of shapes. 1.0 is "same size", 0.5 is shrunken by 50%, 1.5 is enlarged by 50%, and so on.
  • Add shapes to a Group with the following method calls. The way Java evaluates this code involves advanced concepts we'll learn in coming weeks. For now, read this as "hey group, give me the list of your shapes ('children'), so I can add this shape to it":
    <group instance>.getChildren().add(<shape>);

Circle, Rectangle, and Path all have these methods:

  • void setFill(Color fillColor) - Change the "background" or fill of a Shape.
  • void setStroke(Color strokeColor) - Change the border color of a Shape.
  • void setStrokeWidth(double width) - Change the width of the stroke. Defaults to 0.0, which means no border (even if you set a color!).

javafx.scene.shape.Circle

  • Circle() - Default constructor.
  • void setCenterX(double x) - Sets a Circle's center X property.
  • void setCenterY(double y) - Sets a Circle's center Y property.
  • void setRadius(double radius) - Sets a Circle's radius property.

javafx.scene.shape.Rectangle

  • Rectangle() - Default constructor.
  • void setX(double x) - Sets the Rectangle's top-left corner's X coordinate.
  • void setY(double y) - Sets the Rectangle's top-left corner's Y coordinate.
  • void setWidth(double width) - Sets a Rectangle's width property.
  • void setHeight(double height) - Sets a Rectangle's height property.
  • void setArcWidth(double width) - want rounded corners? Try experimenting with this method and setArcHeight.
  • void setArcHeight(double height) - want rounded corners? Try experimenting with this method and setArcWidth.

javafx.scene.shape.Path

A Path is a series of PathElements, or points connected by lines. Warning: you must set a stroke color and stroke width before your path will be visible. You can give a Path a fill color, as well.

Think of a Path like thumbtacks on a cork board connected with yarn. To build a Path, you'll add a starting point to it (a MoveTo instance) followed by a series of lines (LineTo instances). For an example use of a Path, refer to Lecture 5's House.java and Window.java. If you would like to use curved lines along your path, please see the Hacker Edition section at the bottom.

  • Path() - Default constructor.
  • Add PathElements to a Path with the following method calls. This is the same concept as adding a Shape to a Group. For now, read this as "hey path, give me your list of path elements, so I can add this element to it":
    <path instance>.getElements().add(<element>);

javafx.scene.shape.MoveTo

This is the first element of a Path and can be thought of as the "starting point".

  • MoveTo() - Default constructor.
  • void setX(double x) - Set the X coordinate of the starting point.
  • void setY(double y) - Set the Y coordinate of the starting point.

javafx.scene.shape.LineTo

Subsequent elements added to the Path will draw a line from the previous element to the next LineTo element.

  • LineTo() - Default constructor.
  • void setX(double x) - Set the X coordinate.
  • void setY(double y) - Set the Y coordinate.

Submission Instructions

To submit, follow the usual submission instructions.

Hacker Edition

These challenges are not for credit but are fun if you're looking for an extra challenge.

Challenges

0. Use other JavaFX Shape classes. To learn more about these classes, refer to the official documentation for classes in the javafx.scene.shapes package.

1. Declare your own helper methods in classes to clean up your code. Rather than do all the work of generating a component's shapes in a single method, break it down into multiple methods. For an example of this, consider looking at Flower.java from Lecture 12.

2. Add additional component classes to your emoji beyond the required Eye, FaceShape, Mouth, Nose.

3. Draw some component's shapes using a loop or using recursion. This could allow you to make parametric Emoji.