12: Graphics and Animation

What We Will Cover


Continuations

Questions from last class?

Project Questions?

12.1: Graphical Programming

Learner Outcomes

At the end of the lesson the student will be able to:

  • Write simple graphics programs containing points, lines, circles and text
  • Select appropriate coordinate systems for graphics
  • Process user input and mouse clicks in graphic programs

12.1.1: Introduction to Graphics

  • So far our programs have all worked from the console using cin and cout
  • In this section we will look at how to add graphics to a C++ program
  • To create a graphical program, you must use a graphics library
  • C++ does not have a standard graphics library
  • Thus you must alway use a third-party graphics library

    Third-party library: a code library from someone other than the C++ provider (first party) and the user of C++ (second party)

  • The graphics library we will use was written by the author of the textbook, Cay Horstmann
  • Horstamnn's libraries have a small set of shape classes you can use to draw in a graphics window
  • A graphics window is a small portion of the screen you can use to display graphical shapes
  • In addition to displaying graphics, we can get user input from the keyboard and a mouse
  • The following is a simple graphics program that creates a graphics window and draws a message

Program to Display a Message: hellowin.cpp

1
2
3
4
5
6
7
8
9
#include "ccc_win.h"

int ccc_win_main() {
    Point p = Point(1, 3);
    Message greeting = Message(p, "Hello, Window!");
    cwin << greeting;

    return 0;
}

Constructing Objects with Parameters

  • Note that the above example constructs objects with parameters:
    Point p = Point(1, 3);
  • We can initialize an object by passing it construction arguments
  • For instance, in the above example we construct a Point object by passing it coordinates
  • We can construct the Point using shortcut construction as well:
    Point p(1, 3);
  • What is the code to construct the greeting object using shortcut construction?

Displaying Graphics

  • To display graphical shapes, we use a window object called cwin
  • You must use cwin rather than cout to display graphics as shown below:
    Point p(1, 3);
    Message greeting(p, "Hello, Window!");
    ...
    cout << greeting; // No! Will not compile or display
    cwin << greeting; // Displays a message in a window
    

Including the Graphics Classes

  • To use the graphics classes we must include the files that contain their definitions
  • However, different computer systems have different graphics systems installed
  • The library provides several files to work with various graphics systems
  • Which one to use can get tricky so the library provides a single header file that in turn includes the correct files automatically:
    #include "ccc_win.h"
    
  • We will discuss how to compile graphics applications in the next section

12.1.2: Compiling Code That Includes Graphics

  • Since graphics libraries are not part of standard C++, we have to tell the compiler where to find any graphics library files we use
  • The classroom and lab computers are set up so that TextPad knows where the graphics classes are located
  • To compile, you simply select the menu item for compiling C++ graphics
  • You can set up TextPad at home to work the same way by following my instructions: How To Setup TextPad for Writing C++ Programs
  • However, if you prefer to work at the command line, or are using a Mac OSX or Linux computer, you will need a different technique

Working at the Command Line

  • One technique is to work at the command line
  • The easiest way to make use of the graphics files is to copy them to the same directory as you are working within
  • That way the #include directive will find the files when it compiles your code
  • The graphics files are all located in: cccfiles.zip
  • The following instructions explain how to download and install on Windows and Linux/Unix/Mac OS X
  • To run graphics files on Linux/Unix/Mac OS X, you will need to open an X11 terminal

Working at the Command Line on Windows

Note : these instructions assume you installed Cygwin following my instructions.

  1. Save cccfiles.zip to a convenient location on your computer like the Desktop or your Cygwin home directory
  2. Open the ZIP file by double clicking on the file, which will open a new window.
  3. Select all the files in the window and copy them into the directory in which you are working.
  4. Copy the following command string to the Cygwin command prompt and change the file names to match your source and executable file names:

    g++ -D CCC_MSW -I c:\cygwin\usr\include\w32api -o executableName sourceFile.cpp ccc_msw.cpp ccc_shap.cpp -luser32 -lgdi32

    Where:
    • executableName: the name of the executable file you want to create
    • sourceFile.cpp: the name of your source code file.
  5. Run your program in the usual way:

    ./executableName

Working at the Command Line on Linux/Unix/Mac OS X

Note: the following instructions assume you have installed g++ and X11.

  1. Save cccfiles.zip to a convenient location on your computer like the Desktop or your home directory
  2. Open the ZIP file by double clicking on the file, which will open a new window.
  3. Select all the files in the window and copy them into the directory in which you are working.
  4. Open a terminal window.
  5. Copy the following command string to the command prompt and change the file names to match your source and executable file names:

    g++ -o executableName sourceFile.cpp ccc_x11.cpp ccc_shap.cpp -L/usr/X11R6/lib -lX11

    Where:
    • executableName: the name of the executable file you want to create
    • sourceFile.cpp: the name of your source code file.
  6. Run your program in the usual way:

    ./executableName

More Information

12.1.3: Displaying Graphical Shapes

  • In this section we discuss how to make objects display graphical shapes
  • Our graphics library can draw four different shapes as shown below
  • To create more complex shapes, we use combinations of the simple shapes
  • For example, we could draw a square using four lines
  • You position the shape objects within a coordinate system

    XY Coordinates

  • By default, the center of the window is the coordinates (0, 0)
  • The x-coordinates range from (-10, y) on the left side to (10, y) on the right
  • The y-coordinates range from (x, -10) at the bottom to (x, 10) at the top

Drawing Points

  • The most basic graphical shape is the point
  • A point has an x- and y-coordinate
  • The coordinate system for our graphics library is centered in the middle of the window
  • You can see the center of the coordinate system in the following example which draws a point at the coordinates (0, 0):
    #include "ccc_win.h"
    
    int ccc_win_main() {
        Point p(0, 0);
        cwin << p;
    
        return 0;
    }
    
  • Note that, just like with numbers, we can construct constant objects
  • Thus, we could construct a constant Point object using code like:
    const Point P_MSG(-10, 9);

Drawing Circles

  • A circle is defined by a center point and a radius
  • We first construct a Point object:
    Point p(-1, 0);
  • Then we use the Point object as the center of the circle:
    Circle c1(p, 1.5);
  • We can construct both objects in one statement as well:
    Circle c2(Point(1, 0), 1.5);
  • You can see both construction techniques in the following example:
    #include "ccc_win.h"
    
    int ccc_win_main() {
        Point p(-1, 0);
        Circle c1(p, 1.5);
        Circle c2(Point(1, 0), 1.5);
        cwin << c1 << c2;
    
        return 0;
    }
    

Drawing Lines

  • We construct a line by specifying two end-points:
    Point p1(-2, 0);
    Point p2(2, 0);
    cwin << Line(p1, p2);
    
  • We can construct both end-points in the same statement we construct the line too:
    cwin << Line(Point(0, 2), Point(0, -2));
  • You can see both construction techniques in the following example:
    #include "ccc_win.h"
    
    int ccc_win_main() {
        Point p1(-2, 0);
        Point p2(2, 0);
        cwin << Line(p1, p2);
        cwin << Line(Point(0, 2), Point(0, -2));
    
        return 0;
    }
    

Drawing Text Messages

  • We can display text anywhere we like using Message objects
  • The Point argument specifies the upper left corner of the message
  • We saw how to display a message in our first example:
    #include "ccc_win.h"
    
    int ccc_win_main() {
        Point p = Point(1, 3);
        Message greeting = Message(p, "Hello, Window!");
        cwin << greeting;
    
        return 0;
    }
    
  • Note the message displayed can be either a string or a number

12.1.4: Moving Objects

  • Sometimes it is convenient to redraw the same shape object in a different location
  • To change locations, all the graphical classes implement a member function named move()
  • Syntax:
    objectName.move(dx, dy)
  • Where:
    • objectName: the variable of the graphical shape object
    • dx: the amount to move in the x-direction
    • dy: the amount to move in the y-direction
  • The following example draws a square by drawing two lines and then redrawing the lines in a different location

Program square.cpp: Draws a Square by Moving Points and Lines

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include "ccc_win.h"

int ccc_win_main() {
    Point p1(1, 3);
    Point p2 = p1;
    Point p3 = p1;

    // Move points to create right-angle lines
    p2.move(0, 1);
    p3.move(1, 0);
    Line line1(p1, p2);
    Line line2(p1, p3);
    cwin << line1 << line2;

    // Move the lines and redraw them
    line1.move(1, 0);
    line2.move(0, 1);
    cwin << line1 << line2;

    return 0;
}

12.1.5: Graphic Classes Summary

  • You can see all the constructors and functions of the four basic shape classes below

Class Point

Constructor/Function Description
Point(x, y) Constructs a point at location (x, y)
p.get_x() Returns the x-coordinate of the point p
p.get_y() Returns the y-coordinate of the point p
p.move(dx, dy) Moves point p by (dx, dy)

Class Circle

Constructor/Function Description
Circle(p, r) Constructs a circle with center p and radius r
c.get_center() Returns the center point of a circle c
c.get_radius() Returns the radius of a circle c
c.move(dx, dy) Moves circle c by (dx, dy)

Class Line

Constructor/Function Description
Line(p, q) Constructs a line joining points p and q
l.get_start() Returns the starting point of line l
l.get_end() Returns the end point of line l
l.move(dx, dy) Moves line l by (dx, dy)

Class Message

Constructor/Function Description
Message(p, s) Constructs a message with starting point p and text string s
Message(p, x) Constructs a message with starting point p and label equal to the number x
m.get_start() Returns the starting point of message m
m.get_text() Gets the text string message m
m.move(dx, dy) Moves message m by (dx, dy)

12.1.6: Getting Input from the Graphics Window

  • You cannot use cin to get input from a graphics window
  • cin gets input from the console and not the graphics window
  • To read text from a graphics window, you use the get_string() member function of cwin
  • Syntax:
    string response = cwin.get_string(prompt);
  • Where:
    • response: the string variable in which to store the input
    • prompt: the message to give the user
  • For example, to ask the user for their name:
    string name = cwin.get_string("Enter your name:");
    
  • The prompt and input occurs in an input area at either the top or bottom of the graphics window, depending on your system
  • To read numerical data input from a graphics window, use the get_int() or get_double() function
  • For example, to ask the user for their age:
    int age = cwin.get_int("Enter your age:");
    

Mouse Input

  • Sometimes you want to have the user input a mouse position
  • Rather than typing information, you can get the position using a mouse click
  • To get the coordinates of the mouse, use the get_mouse() member function
  • Syntax:
    Point mouse = cwin.get_mouse(prompt);
  • Where:
    • mouse: the Point variable in which to store the mouse coordinates
    • prompt: the message to give the user
  • For example, to ask the user for a mouse click:
    Point p = cwin.get_mouse("Click in the circle");
    
  • The following program demonstrates how to get user input from a graphics window

Program click.cpp: Gets User Input from the Graphics Window

1
2
3
4
5
6
7
8
9
10
11
#include "ccc_win.h"

int ccc_win_main() {
    string name = cwin.get_string("Enter your name:");
    Circle c(Point(0, 0), 5);
    cwin << c;
    Point p = cwin.get_mouse("Click in the circle");
    cwin << p << Message(p, name + " clicked here");

    return 0;
}

Exercise 12.1: Drawing on Our Programming Knowledge!

In this exercise we look at how to draw simple graphic shapes. Specifically, you will write a program to display a drawing like the following:

Face picture

Specifications

  1. Copy the following program into a text editor, save it as face.cpp, and then compile and run the starter program to make sure you copied it correctly.
    #include "ccc_win.h"
    
    int ccc_win_main() {
        // Enter code here
    
        return 0;
    }
    
  2. In ccc_win_main(), declare and draw a circle for the outline of the "face", using code like:
    Point center(0, 0);
    Circle face = Circle(center, 6);
    cwin << face;
    

    A Circle object requires a center point and a radius. For more information, see section: 12.1.3: Displaying Simple Graphical Shapes.

  3. Next, add code to draw a line for the mouth using code like the following:
    Point lp1(-2.5, -2);
    Point lp2(2.5, -2);
    Line mouth = Line(lp1, lp2);
    cwin << mouth;
    

    To construct a Line object, you need two end-points. For more information, see section: 12.1.3: Displaying Simple Graphical Shapes.

  4. Add a smaller circle for the left "eye" using code like the following:
    Circle eye(Point(-2, 2), .5);
    cwin << eye;
    

    Note how we are constructing the Point object inside the parenthesis of the eye object. When you construct an object nested in the parenthesis, you do not define an object name.

  5. Rather than creating a new object for the right "eye", we will reuse the eye object with the following code:
    eye.move(4, 0);
    cwin << eye;
    

    The move() function moves the object by a (dx, dy) amount. For more information, see section: 12.1.4: Moving Objects.

  6. Compile and execute your code to verify you see something like the image above.
  7. Now let us explore how to get input from a user in the graphics window. Enter the following code to get input from the user:
    string input = cwin.get_string("Enter a message");
    

    You can get input for types string, int or double. For more information, see section: 12.1.6: Getting Input from the Graphics Window.

  8. To display the input we draw a text message using a Message object. Add code like the following to display the message the user enters:
    Point p = cwin.get_mouse("Click next to the mouth");
    cwin << Message(p, input);
    

    A Message object needs both a Point and a message to display. To get the Point object, we use another type of user input -- the mouse click. For more information, see section: 12.1.6: Getting Input from the Graphics Window.

  9. Compile and execute your code to see how the user input works in the graphics window.
  10. Submit your program source code to show you completed this exercise.
  11. In addition, work through the example in section: 12.1.7: Choosing a Coordinate System and be prepared to answer the Check Yourself questions in the section: 12.1.8: Summary.
  12. Submit the phoenix.cpp source code to Blackboard as part of your project.

12.1.7: Choosing a Coordinate System

  • Consider the following data from page 99 of our textbook
  • It lists the average temperatures in Phoenix, Arizona by month
Month Average
Temperature
Month Average
Temperature
January 11 July 33
February 13 August 32
March 16 September 33
April 20 October 23
May 25 November 16
June 31 December 12
  • How would we construct a graph of this data on paper?
  • After determining the algorithm for constructing the graph on paper, we can translate our algorithm to display it as a graphical program
  • However, we run into some problems displaying the graph using points
  • For instance, if we try to plot the data point (1, 11) as a Point, it will not even show up on the graph
  • To make the data fit our graph, we need to change our coordinate system

Changing the Coordinate System

  • The default coordinate system for the graphics classes:
    • The origin (0, 0) is at the center
    • x- and y- axis range from -10.0 to 10.0
  • The user can reset the coordinate system using the syntax:
    cwin.coord(xLeft, yTop, xRight, yBottom)
  • Where:
    • xLeft: the left-most x-position
    • yTop: the top-most y-position
    • xRight: the right-most x-position
    • yBottom: the bottom-most y-position
  • For example, we might chose the following coordinate system for our Phoenix data:
    cwin.coord(1, 33, 12, 11);
  • The following program plots the data

Program phoenix.cpp: Plots Temperatures in Phoenix, Arizona

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "ccc_win.h"

int ccc_win_main() {
    cwin.coord(1, 33, 12, 11);
    cwin << Point(1, 11);
    cwin << Point(2, 13);
    cwin << Point(3, 16);
    cwin << Point(4, 20);
    cwin << Point(5, 25);
    cwin << Point(6, 31);
    cwin << Point(7, 33);
    cwin << Point(8, 32);
    cwin << Point(9, 29);
    cwin << Point(10, 23);
    cwin << Point(11, 16);
    cwin << Point(12, 12);

    return 0;
}

12.1.8: Summary

  • In this section we looked at how to use objects to draw shapes
  • C++ does not have a standard graphics library, so you always have to include one
  • We are using a graphics library developed by Cay Horstmann, the author of the textbook
  • To use the graphics classes we must include the files that contain their definitions
    #include "ccc_win.h"
    
  • The classroom and lab computers are set up so that TextPad knows where the graphics classes are located
  • We discussed how to draw four basic shapes using objects of:
    • Point
    • Circle
    • Line
    • Message
  • To create more complex shapes, we use combinations of the simple shapes
  • For example, we could draw a square using four lines
  • Sometimes it is convenient to redraw the same shape object in a different location
  • To change locations, all the graphical classes implement a member function named move()
  • We looked at an example of using move() to draw a square
  • You cannot use cin to get input from a graphics window
  • Instead you need to use the "get" functions of cwin:
    • cwin.get_string(prompt)
    • cwin.get_int(prompt)
    • cwin.get_double(prompt)
  • Also, you can get a mouse-click location using the get_mouse() function of cwin
  • For example:
    Point p = cwin.get_mouse("Click in the circle");
  • When displaying graphics, you often need to specify a coordinate system that matches your data
  • Once you have chosen the coordinate system, you set the coordinates using the coord() function of cwin
  • For example:
    cwin.coord(1, 33, 12, 11);

Check Yourself

As time permits, be prepared to answer these questions. You can find additional information in the sections that follow.

  1. Does C++ have a standard library for graphics?
  2. What file must you include to compile graphics programs?
  3. What five classes are used in the graphics library to draw shapes?
  4. What code do you write to construct each of the following four shapes?
    • Points
    • Circles
    • Lines
    • Text messages
  5. Once you have constructed a shape object, how do you display it in a window?
  6. Why might you need to change coordinate systems?
  7. What is the purpose of the move() function?
  8. What code do you use to read string input from the user in a graphics window?
  9. What is a convenient way to get mouse coordinates from a user?

12.2: Computer Animation

Objectives

At the end of the lesson the student will be able to:

  • Explain the principles of animation
  • Create code for simple animation
  • Write code for animation objects

12.2.1: Introduction to Computer Animation

  • Animation is the illusion of motion created by displaying a series of images or shapes
  • For example, the following animation displays at 10 frames per second (FPS):

    example animation

  • The speed of the display is fast enough that you cannot easily see the individual frames
  • Contrast this with the following image that displays at 2 frames per second:

    example animation at slower frame rate

  • At 2 FPS, the animation is slow enough that you can see the individual frames
  • Both of these animations were produced by displaying these images, known as frames:

    animation frames

  • Note that these images are in the public domain and were obtained from Wikipedia

12.2.2: Moving Shapes

  • We can create a simple animation with our graphics system by drawing shapes
  • For instance, we can draw a circle and move it around the graphics window
  • Recall that we construct a Circle with a Point and a radius
  • We first construct a Point object:
    Point p(0, 0);
  • Then we use the Point object as the center of the circle:
    Circle circ(p, 1.0);
  • We can construct both objects in one statement as well:
    Circle circ2(Point(0, 0), 2.0);
  • To create movement we need to change the location of the circle over time
  • We control how much to change the location using two variables:
    double dx = .125; // movement in x direction
    double dy = .125; // movement in y direction
    
  • To change the location, we use the move() function of Circle:
    circ.move(dx, dy);
    
  • This function adds dx and dy to the current x and y location values

12.2.3: Moving the Shape with a Loop

  • To create movement over time, we use an animation loop
  • There are three steps to an animation loop as shown in the following diagram:

    update,render,sleep

  • During the update portion of the loop, you calculate the position of your shape
  • During the render portion, you draw the shape
  • Then you wait a short while before repeating the process
  • To pause, we use the function: usleep(microseconds)
  • Function usleep() stops the program for some specified number of microseconds
    • A microsecond is one millionth of a second
  • There are two reasons for pausing:
    1. To slow down the animation's frame rate
    2. To allow other programs on the computer to run
  • The second reason is important but not always obvious
  • A modern operating system runs several programs at the same time
  • At some point, other programs need a chance to run
  • A good time for other programs to run is when our program does not need to run
  • The following example uses an animation loop to move a circle across the screen

Example Animation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <cmath>
using namespace std;
#include "ccc_win.h"

int ccc_win_main() {
    const int DELAY = 33333; // 30 FPS
    const int FRAMES = 100;
    double dx = .125;
    double dy = 0;

    Circle circ = Circle(Point(0, 0), 1);

    for (int frame = 0; frame < FRAMES; frame++) {
        // Update
        circ.move(dx, dy);
        // Render
        cwin.clear();
        cwin << circ;
        // Pause
        usleep(DELAY);
    }
    Point p = cwin.get_mouse("Click to exit");
    exit(0);

    return 0;
}

12.2.4: Bouncing off the Walls

  • To make our animation more interesting, we can add a bounce to the circle
  • Imagine the circle is a ball and that we want the ball to bounce off the walls
  • Imitating a real thing or process is known as a simulation
  • One use of computers is simulating, or modeling, key characteristic of systems
  • For our simulation, we use the sides, top and bottom of the window as the walls
  • Remember that our coordinate system is centered in the window at (0, 0)

    XY Coordinates

  • The x-coordinates range from (-10, y) on the left side to (10, y) on the right
  • The y-coordinates range from (x, -10) at the bottom to (x, 10) at the top
  • We can define constants for the walls:
    const double TOP = 10.0;
    const double RIGHT = 10.0;
    const double BOTTOM = -10.0;
    const double LEFT = -10.0;
    
  • To test if the ball exceeds the boundaries in the x-direction, we use an if-else statement like:
    if (x - radius < LEFT) {
        dx = abs(dx);
    } else if (x + radius > RIGHT) {
        dx = -abs(dx);
    }
    
  • If the ball exceeds the boundaries we reverse its direction
  • Similarly, we test if the ball exceeds the top and bottom boundaries with:
    if (y + radius > TOP) {
        dy = -abs(dy);
    } else if (y - radius < BOTTOM) {
        dy = abs(dy);
    }
    
  • The bounce code goes in the update() method of the animation loop as shown in the following example

Example Animation With Bounce

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <cmath>
using namespace std;
#include "ccc_win.h"

int ccc_win_main() {
    const int DELAY = 33333; // 30 FPS
    const int FRAMES = 500;
    const double TOP = 10.0;
    const double RIGHT = 10.0;
    const double BOTTOM = -10.0;
    const double LEFT = -10.0;

    // Random speed
    srand(time(0));
    double dx = .1 + ((double) rand() / RAND_MAX) / 4;
    double dy = .1 + ((double) rand() / RAND_MAX) / 4;

    Circle circ = Circle(Point(0, 0), 1);

    for (int frame = 0; frame < FRAMES; frame++) {
        // Update
        Point p = circ.get_center();
        double x = p.get_x();
        double y = p.get_y();
        double radius = circ.get_radius();
        if (x - radius < LEFT) {
            dx = abs(dx);
        } else if (x + radius > RIGHT) {
            dx = -abs(dx);
        }
        if (y + radius > TOP) {
            dy = -abs(dy);
        } else if (y - radius < BOTTOM) {
            dy = abs(dy);
        }
        circ.move(dx, dy);
        // Render
        cwin.clear();
        cwin << circ;
        // Pause
        usleep(DELAY);

    }
    Point p = cwin.get_mouse("Click to exit");
    exit(0);

    return 0;
}

12.2.5: Animating Two Objects

  • If we want to animate two shapes, we need separate variables for each object
  • As we add more shape objects, our code in the animation loop becomes more cluttered
  • To avoid the clutter and duplication, we can encapsulate the code for the shape in a class
  • Here is a Ball class that encapsulates the information for the moving shape
  • Following the Ball class is an animation application bouncing two balls
  • Notice how simple the animation loop remains

Ball Class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <cmath>
using namespace std;
#include "ccc_win.h"

const double TOP = 10.0;
const double RIGHT = 10.0;
const double BOTTOM = -10.0;
const double LEFT = -10.0;

class Ball {
public:
    Ball();
    Ball(double x, double y, double radius,
        double newDx, double newDy);
    void update();
    void draw();
private:
    Circle circ;
    double dx, dy;
};

Ball::Ball() {
    circ = Circle(Point(0, 0), 1.0);
    dx = 0.0;
    dy = 0.0;
}

Ball::Ball(double x, double y, double radius,
        double newDx, double newDy) {
    circ = Circle(Point(x, y), radius);
    dx = newDx;
    dy = newDy;
}

void Ball::update() {
    Point p = circ.get_center();
    double x = p.get_x();
    double y = p.get_y();
    double radius = circ.get_radius();
    if (x - radius < LEFT) {
        dx = abs(dx);
    } else if (x + radius > RIGHT) {
        dx = -abs(dx);
    }
    if (y + radius > TOP) {
        dy = -abs(dy);
    } else if (y - radius < BOTTOM) {
        dy = abs(dy);
    }
    circ.move(dx, dy);
}

void Ball::draw() {
    cwin << circ;
}

Example Animation With Two Balls

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include "ball.cpp"

int ccc_win_main() {
    const int DELAY = 33333; // 30 FPS
    const int FRAMES = 500;

    // Random speed
    srand(time(0));
    double dx = .1 + ((double) rand() / RAND_MAX) / 4;
    double dy = .1 + ((double) rand() / RAND_MAX) / 4;
    Ball b1 = Ball(1, 1, 1, dx, dy);
    dx = .1 + ((double) rand() / RAND_MAX) / 4;
    dy = .1 + ((double) rand() / RAND_MAX) / 4;
    Ball b2 = Ball(-1, -1, 1, dx, dy);

    for (int frame = 0; frame < FRAMES; frame++) {
        // Update
        b1.update();
        b2.update();
        // Render
        cwin.clear();
        b1.draw();
        b2.draw();
        // Pause
        usleep(DELAY);
    }
    Point p = cwin.get_mouse("Click to exit");
    exit(0);

    return 0;
}

12.2.6: Animating Many Objects

  • We can take our animation one step further and animate many objects
  • To juggle several balls at once we use a list such as a vector or array with a counting loop
  • You can see the loops with the vector in the following example

Example Animation With Many Balls

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <vector>
using namespace std;
#include "ball.cpp"

int ccc_win_main() {
    const int DELAY = 33333; // 30 FPS
    const int FRAMES = 500;
    const int NUM_BALLS = 10;

    srand(time(0));
    vector<Ball> balls(NUM_BALLS);

    // Initialize vector of balls
    for (unsigned i = 0; i < balls.size(); i++) {
        double x = rand() % 10 - 5;
        double y = rand() % 10 - 5;
        double dx = .1 + ((double) rand() / RAND_MAX) / 4;
        double dy = .1 + ((double) rand() / RAND_MAX) / 4;
        balls[i] = Ball(x, y, 1, dx, dy);
    }

    for (int frame = 0; frame < FRAMES; frame++) {
        // Update
        for (unsigned i = 0; i < balls.size(); i++) {
            balls[i].update();
        }
        // Render
        cwin.clear();
        for (unsigned i = 0; i < balls.size(); i++) {
            balls[i].draw();
        }
        // Pause
        usleep(DELAY);
    }
    Point p = cwin.get_mouse("Click to exit");
    exit(0);

    return 0;
}

Exercise 12.2

In this exercise we compile and run the example application showing the animation of several shapes.

Specifications

  1. Copy the following code into a text editor and save the file as ball.cpp
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    
    #include <cmath>
    using namespace std;
    #include "ccc_win.h"
    
    const double TOP = 10.0;
    const double RIGHT = 10.0;
    const double BOTTOM = -10.0;
    const double LEFT = -10.0;
    
    class Ball {
    public:
        Ball();
        Ball(double x, double y, double radius,
            double newDx, double newDy);
        void update();
        void draw();
    private:
        Circle circ;
        double dx, dy;
    };
    
    Ball::Ball() {
        circ = Circle(Point(0, 0), 1.0);
        dx = 0.0;
        dy = 0.0;
    }
    
    Ball::Ball(double x, double y, double radius,
            double newDx, double newDy) {
        circ = Circle(Point(x, y), radius);
        dx = newDx;
        dy = newDy;
    }
    
    void Ball::update() {
        Point p = circ.get_center();
        double x = p.get_x();
        double y = p.get_y();
        double radius = circ.get_radius();
        if (x - radius < LEFT) {
            dx = abs(dx);
        } else if (x + radius > RIGHT) {
            dx = -abs(dx);
        }
        if (y + radius > TOP) {
            dy = -abs(dy);
        } else if (y - radius < BOTTOM) {
            dy = abs(dy);
        }
        circ.move(dx, dy);
    }
    
    void Ball::draw() {
        cwin << circ;
    }
    
  2. Copy the following code into a text editor and save the file as animobj.cpp
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    
    #include <vector>
    using namespace std;
    #include "ball.cpp"
    
    int ccc_win_main() {
        const int DELAY = 33333; // 30 FPS
        const int FRAMES = 500;
        const int NUM_BALLS = 10;
    
        srand(time(0));
        vector<Ball> balls(NUM_BALLS);
    
        // Initialize vector of balls
        for (unsigned i = 0; i < balls.size(); i++) {
            double x = rand() % 10 - 5;
            double y = rand() % 10 - 5;
            double dx = .1 + ((double) rand() / RAND_MAX) / 4;
            double dy = .1 + ((double) rand() / RAND_MAX) / 4;
            balls[i] = Ball(x, y, 1, dx, dy);
        }
    
        for (int frame = 0; frame < FRAMES; frame++) {
            // Update
            for (unsigned i = 0; i < balls.size(); i++) {
                balls[i].update();
            }
            // Render
            cwin.clear();
            for (unsigned i = 0; i < balls.size(); i++) {
                balls[i].draw();
            }
            // Pause
            usleep(DELAY);
        }
        Point p = cwin.get_mouse("Click to exit");
        exit(0);
    
        return 0;
    }
    
  3. Compile and run the animobj.cpp file an verify the animation runs.

    If you have problems ask a classmate or the instructor for help.

  4. Take a few minutes to modify the number of objects in the animation.
  5. There is no need to turn in this exercise.

12.2.7: Summary

  • In this section we looked at how to create a simple animation by drawing shapes
  • Animation is the illusion of motion created by displaying a series of images or shapes:

    example animation

  • Computer animation draws the images or shapes at a specific place on your computer screen
  • As an example, we use a Circle object to simulate a bouncing ball
  • To create movement we used two variables:
    double dx = .125; // movement in x direction
    double dy = .125; // movement in y direction
    
  • These variables became the arguments to the move() function of Circle:
    circ.move(dx, dy);
    
  • To control the movement, we created an animation loop as shown in the following diagram:

    update,render,sleep

  • During the update portion of the loop, we calculated the position of our shape
  • During the render portion, we drew the shape
  • After rendering our shapes, we paused the loop using the function: usleep(microseconds)
  • Function usleep() stops the program for some specified number of microseconds (one millionth of a second)
  • To better simulate a ball, we added code to test for "walls" (the edge of the screen)
  • When the ball hit a wall, we reversed the dx and dydirections
  • If we add balls to the animation, the code in the animation loop becomes cluttered
  • To avoid the clutter, we created a Ball class to encapsulate the location, speed and behavior of a ball
  • We then looked at how to add several balls to the animation using a vector

Check Yourself

  1. What is animation?
  2. What is meant by the term "animation loop"?
  3. What three operations are present in an animation loop?
  4. What code did we use to calculate position from one animation frame to the next?
  5. True or false? To reduce clutter, you can encapsulate the animated object into a class.
  6. What two programming constructs allow you to easily animate multiple objects?

Wrap Up

Due Next:
Sampler Project (5/24/12)
When class is over, please shut down your computer if it is on
Work on your project!
Home | Blackboard | Day Schedule | Eve Schedule
Syllabus | Help | FAQ's | HowTo's | Links
Last Updated: February 05 2012 @16:01:15