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:
A scene consists of up to three shapes, all at different positions.
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.
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.
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.
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.
Declare an interface for shapes, with the methods
VisibleAtPoint (accepting a
position and returning a
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:
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
MoveTo methods, so that it is a valid shape.
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
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
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.
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).
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.
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.)
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:
Based on whether
from < to or vice versa, determine whether this animation is running forward or backward.
Calculate how long each frame will take, if the entire animation is supposed to last for the given
In a loop, run the animation. At the top of each loop, clear the screen using
clear.WipeScreen(), then call the animation function with the current frame number to see what scene you should be drawing. Call the scene’s
Draw method to draw it. Then
time.Sleep(•) for the proper duration before the next iteration of the loop starts.
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.