DISCLAIMER: Due to the shortened time period of the semester from closures, the point value of this problem set is reduced to 30 points rather than the typical 100. This means across all problem sets this semester there are 630 possible points. This problem set is due on LDOC, but late submissions will be accepted through Friday 12/7 at 11:59pm. Office hours will not be open after LDOC so please plan accordingly.
In this problem set, you'll create an emoji using code. We encourage you to have fun with it and go beyond the minimum requirements! PS6 is all about getting your hands dirty with object-oriented programming while being creative. This is also the first problem set where you will rely on external documentation as part of a class library.
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 being impressed with technical artistry!
Tip #1: Before writing any code, sketch your emoji on graph paper. Aim to work in a coordinate system with x and y axes ranging from -100 to +100. Know that one requirement is to use at least one rectangle, one circle, and one path (series of lines) in your final emoji.
You will build a class for each part of your emoji's face and then assemble these parts together in your final Emoji class, kind of like piecing together parts into a Mr. Potato head "FaceShape". You will make an Eye class (and then construct two Eye objects from the same single class), a Mouth class, and so on.
Tip #2: When working on individual parts, try to center each part around the coordinate 0, 0. In the last step, you will place these parts at their correct coordinates, relative to one another.
Tip #3: Your Eye class should only contain the shapes for a single eye. At the final step you will construct two Eye objects from your single Eye class. You will be able to position each eye independently of the other.
We are providing stencil code to help get you started with this assignment. You'll use the IntroCS Graphics library's built-in classes while writing your own classes with properties, a constructor, and methods.
Tip #4: Explore the library's documentation to familiarize yourself with what shape classes and capabilities are available for you to work with. In particular, look at:
Tip #5: Can't decide what red, green, and blue values to fill your color with? Go to this site that helps you pick a color, and use the RGB Normalized Decimal values as the arguments for your Color object. For example, let lilac: Color = new Color(0.874, 0.207, 0.913).
To ensure you have the latest material, be sure your development environment is shut down, then pull the latest code and start it back up. Run the following commands in the VSCode Integrated Terminal:
The starting files you'll need for this app are automatically added to the folder ps06-emoji upon running "npm run pull"
You'll be doing most of your work in the Emoji.ts file, as well as some work in emoji-script.ts.
Emoji.ts - The classes for each piece of your Emoji (FaceShape, Mouth, Eye) as well as the composed Emoji class itself, will be defined within this file.
emoji-script.ts - This is the "runner" for the application. From this file, you will import each piece from Emoji.ts and render them to the SVG artboard to display your whole emoji.
CoordinateGrid.ts - You will not need to modify this file, but you may find using it helping when designing your Emoji. Its shapes method will generate a coordinate grid with labels. It is enabled by default.
Honor Code Header
All problem sets begin with an Honor Code pledge. Notice this header is contained within the block comment tags discussed in Lecture 1. You can copy/paste the pledge below and fill in your name and ONYEN. Be sure that this pledge is in the file Emoji.ts for PS06.
/** * Author: * ONYEN: * UNC Honor Pledge: I certify that no unauthorized assistance has been received * or given in the completion of this work. I certify that I understand and * could now rewrite on my own, without assistance from course staff, * the problem set code I am submitting. */
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. 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.
Your FaceShape class will generate the background that gets layered behind your other pieces (eyes, mouth, etc). Be as creative as you'd like with 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 property tone.
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 Eye class.
Return type: Group Name: shapes Parameters: none
The method definition of the shapes method has a few requirements:
Your Eye class should represent a single eye *NOT* both eyes. When you get to the final step of piecing together your complete Emoji class, you will create two instances of the Eye class and position them individually. You should try to center your Eye's shapes around the coordinate 0, 0 to make the final step more straightforward.
Begin by defining and exporting a class named Eye in Emoji.ts.
Eye requires an irisColor property, just like FaceShape's tone property. Refer back to your FaceShape for help here. By making the irisColor a property, we can easily generate eyes of different colors.
Once your Eye class is defined and its shapes method is setup, you should update your emoji-script.ts to no longer show FaceShape and instead show your Eye as you're working on its graphics. To do this, be sure to import the Eye class from "./Emoji" and update your code. For example:
// TODO: Change the following code when you work on other pieces let piece: Eye = new Eye(new Color(0.3, 0.3, 1.0)); shapes.add(piece.shapes());
Property: Type: Color Name: irisColor Constructor: Parameter: Type: Color Name: irisColor Requirement: The constructor must assign the irisColor parameter to the irisColor property.
The shapes for your emoji's mouth will be setup in this class.
You will need to first declare and export a Mouth class to the Emoji.ts file.
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.
To visualize your Mouth piece as you are working on it, instead of your Eye piece, update the code in emoji-script.ts like you did above in the Eye class.
Now that you have all your Emoji's components built... it's time to compose them in the Emoji class!
Go ahead and declare and export a class named Emoji to the Emoji.ts file.
Requirement B.0 - Your Emoji class must have at least 4 properties: faceShape, mouth, 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.) Their types should be FaceShape, Mouth, and Eye respectively.
Requirement B.1 - Your Emoji class should have a zero-parameter constructor. In the constructor, you should initialize each of your properties 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 properties. Consider declaring local variables to hold each of the returned Groups from your components. A Group does not have an x, y position, however, a group does have a "transform" property. Once you have a component's Group of shapes, you can "translate" (move), "scale", and "rotate" a piece by assigning to its transform property. An example is given below:
let leftEyeShapes: Group = this.leftEye.shapes(); leftEyeShapes.transform = leftEyeShapes.transform.translate(10, -20); // The above line of code causes the group to be shifted // to the right by 10 units on the X axis and up by 20 units on the Y.
To visualize your emoji as you are adding its piece's shapes, update your code in emoji-script.ts to work with the Emoji class's shapes method rather than Mouth's.
Learning objective: experience building up a set of reusable classes that can be composed together. In this case, notice that the Emoji class' properties are made up of other classes that you've defined. This is an example of dividing up a problem into subcomponents. We could easily extend and swap out individual pieces of the Emoji to create additional variations. The idea of subdividing a problem into many different classes and functions that can then be brought together to solve the complete problem is called decomposition and composition. It is a valuable practice in computer science that leads to simplifying problems while at the same time producing small, reusable components.
Be sure to make use of the graphics library's documentation for additional information on properties available to you as you craft your Emoji.
These challenges are not for credit but are fun if you're looking for an extra challenge.
0. Add additional component classes to your emoji beyond the required FaceShape, Eye, and Mouth. For example: Nose, Hair, Hat, etc.
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.
3. Draw some of your piece's shapes using loop or using recursion. This could allow you to make parametric Emoji.