Interfaces for animation

Assignment overview

In this assginment, you’ll create a more sophisticated animation system than in your previous assignment. You will use interfaces to allow the system to handle a variety of shapes and drawing mechanisms.

Here is a general overview of how your system will work:

  1. A scene consists of up to three shapes, all at different positions.

  2. shape is an interface, with a number of different concrete types representing different shapes. Each shape type has a method called VisibleAtPoint that given an x, y coordinate, returns a Boolean, indicating whether the shape must be drawn that point. It also contains a MoveTo method, which returns an updated version of the shape moved to a certain (x, y) position, and a GetPosition method, which returns its current position.

  3. Each scene knows how to Draw itself. This involves looping through every coordinate, checking if any of its three shapes are visible at that point, and if so, printing a # symbol; if no shape is visible, a blank space is printed.

  4. An animation is a type that has, as its underlying type, func (int) scene–a function that takes in a frame number and outputs a scene. It has a method to Run an animation from a certain frame to another frame, in a certain amount of time. This involves drawing a frame, sleeping for a bit, then clearing the screen and drawing another frame.

Install the clear package

In Terminal, type go get github.com/alex-lew/clear-screen-cs2. This will allow you to import clear "github.com/alex-lew/clear-screen-cs2", then call clear.WipeScreen() to clear the Terminal window between frames of animation.

Step-by-step instructions

1Implement four shapes

Declare an interface for shapes, with the methods VisibleAtPoint (accepting a position and returning a bool), GetPosition (returning a position, from your previous animation homework), and MoveTo, which takes a position as input and returns a new shape moved to that position.

Then design the following shape types, as structs:

  1. rectangle, which represents a rectangle. Its position represents its top left corner; it also has a width and height. The rectangle struct should also have a boolean field, filled, which determines whether it is a filled rectangle, or just the outline of a rectangle. Its VisibleAtPoint method returns true if the given point lies on the border of the rectangle, or, if the rectangle is filled, inside the rectangle. The rectangle also has GetPosition and MoveTo methods, so that it is a valid shape.

  2. circle, which represents a circle. Its position represents its center. It also stores its radius. All circles are filled; no need to store a boolean for this. To implement the VisibleAtPoint method for a circle, just check the distance between the given point and the circle’s center; if this distance is less than or equal to the circle’s radius, return true. As above, the circle also must implement GetPosition and MoveTo.

  3. groupedShape, which represents two shapes grouped together into one, which move together. Use a struct with two fields holding “sub-shapes”. The groupedShape keeps track of a “core position,” and each sub-shape’s position is interpreted as being relative to the core position. If, for example, the groupedShape is located at (10, 4), and it contains sub-shapes located at (-7, -2) and (5, 6), the sub-shapes should actually be considered to be located at (3, 2) and (15, 10) respectively. The MoveTo and GetPosition methods of the groupedShape apply to the core position; by changing it, you automatically move both the sub-shapes together. To say whether the groupedShape is visible at a certain position, check whether either of its sub-shapes is visible at that position.

  4. At least one shape of your own choosing / design. This can be something like the rectangle or circle (for instance, you could add a triangle shape), or it could be a “composite shape” type, like the groupedShape (you might add an intersectionShape, for instance, that is just like the groupedShape but instead of showing both subshapes, you show only their intersection; the shape is visible only at points where both subshapes overlap, i.e., where both are visible).

Extra Challenge: Outlined circle

The rectangle type supports both filled and outlined variants, but the circle type described above is always filled. Modify it to support an “outline” option, by adding a filled boolean to your struct, and changing the VisibleAtPoint function accordingly.

2The scene type

Create a scene struct that stores up to three shapes. (If a shape is nil, that shape slot is unused.) It should have a Draw method, which assumes that the Terminal screen is an empty 80x24 grid (80 wide, 24 tall), and draws the scene. To do this, loop through each row and column, choosing whether to draw a space or a # character, based on whether any of your three shapes are visible. (At the end of each row, make sure to use fmt.Println() to move to the next row.)

3The animation type

Declare an animation type with underlying type func (int) scene. Give it a method, (a animation) Run(from int, to int, duration time.Duration), which does the following:

4Your own animation

Create an animation with at least three shapes (not every shape needs to move). Your main function should run this animation from start to finish, and then from finish to start.