Bouncing Ball animation in C++ with glfw

A glfw application with C++11:


This is how our bouncing ball animation will look like, sorry if its too bright.

bouncing ball animation c++

 

glfw has a C API but as a C++ application use this API in a simple inheritance-based little framework.
glfw_app BASE CLASS
class glfw_app
{
public:
    glfw_app(const std::string& window_title, int window_width, int window_height);
    virtual ~glfw_app();

    void start();

    virtual void on_keydown(GLFWwindow* window, int key, int scancode, int action, int mods);
    virtual void on_error(int error, const char* desc);
    virtual void on_resize(GLFWwindow* window, int width, int height);
    virtual void glloop() = 0;

    GLFWwindow* window() const;
};

This base class is simple: It manages a glfw window and their OpenGL context for us, wraps (and currently hides) the event and rendering loop, finally and provides us some polymorphic functions to say what to do when a key is pressed, when the window is resized, etc.

Here’s the declaration of the bouncing ball glfw application:
class ball : public glfw_app
{
public:
 template<typename... ARGS>
 ball(ARGS&&... args) : glfw_app{ std::forward<ARGS>(args)... } ,
  x_ball{ 0.0f },
  y_ball{ 0.8f },
  vx_ball{ 0.0f },
  vy_ball{ 0.0f }
 {}

 virtual void on_keydown(GLFWwindow* window, int key, int scancode, int action, int mods) override;

 virtual void glloop() override;

private:
 float x_ball, y_ball;
 float vx_ball, vy_ball;
 const float gravity = 0.01;
 const float radius = 0.05f;

 void draw_ball();
};

 

We have ball coordinates, ball speed, and its radius. There is also a `gravity` constant, since we want our ball to bounce. 

The template stuff on the constructor is a variadic template with perfect forwarding, just to bypass all the arguments to the base class constructor.

The on_keydon() callback is not complex: Just closes the window when the user presses ESC:
void ball::on_keydown(GLFWwindow* window, int key, int scancode, int action, int mods)
{
 if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
  glfwSetWindowShouldClose(window, GL_TRUE);
}

Now this is the body of our rendering loop:

void ball::glloop()
{
 float ratio = framebuffer_width() / (float)framebuffer_height();

 glClear(GL_COLOR_BUFFER_BIT);

 glMatrixMode(GL_PROJECTION);
 glLoadIdentity();
 glOrtho(-ratio, ratio, -1.f, 1.f, 1.f, -1.f);
 glMatrixMode(GL_MODELVIEW);

 //Bounce on window bottom
 if (y_ball + radious <= radious)
  vy_ball = std::abs(vy_ball);
 else
  vy_ball -= gravity; //Apply gravity

 //Update ball coordinates
 x_ball += vx_ball;
 y_ball += vy_ball;

 //Lets draw the ball!
 draw_ball();
}

 

Note how the ball is projected. The visible area of our OpenGL scene (The area which matches the viewport) goes from -1 to 1 in both axes, where -1 is the bottom-left corner of our window, and 1 is its top-left. 

Working with coordinates [-1,1] makes it simple to deal with window bounds, since they are independent of the window’s size.
 
Check how the animation works:
//Bounce on window bottom
 if (y_ball - radious <= - 1)
  vy_ball = std::abs(vy_ball);
 else
  vy_ball -= gravity; //Apply gravity

 //Update ball coordinates
 x_ball += vx_ball;
 y_ball += vy_ball;

 //Lets draw the ball!
 draw_ball();

The ball’s position and speed are updated following the equations v’ = v + a*t and p’ = p + v * t, where v is velocity (speed), a is acceleration (The gravity constant), and t is time.

Time is measured in frames, so in all the equations t is one. That’s why there’s no t in our code. If you want a stable simulation (independent of frame rate) you should use a more complex technique, like those described in this article.

If the ball goes out of the window bounds, that is, y_ball – radious is less than -1, we should make the ball go upwards: Set its vertical speed as positive:

if (y_ball - radious <= - 1)

vy_ball = std::abs(vy_ball);

Also apply gravity. Don’t apply acceleration when the ball bounces.

The final step is to draw the ball: Draw a white “circle” (a regular polygon) using GL_POLYGON:

void ball::draw_ball()
{
const float full_angle = 2.0f*3.141592654f;
float x, y;
glBegin(GL_POLYGON);
glColor3f(1.0f, 1.0f, 1.0f);
for (std::size_t i = 0; i < 20; ++i)
{
    x = x_ball + radious*(std::cos(i*full_angle / 20.0f));
    y = y_ball + radious*(std::sin(i*full_angle / 20.0f));
    glVertex2f(x, y);
}
glEnd();
}

 

Now here the main() function

#include "glfw_app.hpp"
#include "ball.hpp"

int main()
{
auto app = make_app<ball>("bouncing ball!" , 800 , 600);
app->start();
}

glfw is a great library to write OpenGL applications. Its C API is clear and simple, and making it work in the C++ way can be done with just a little effort. We learnt here how to make a little framework to write simple OpenGL applications in a OO way. Encapsulating the most common tasks in a base class reduces noise in our simple OpenGL examples.

1 thought on “Bouncing Ball animation in C++ with glfw”

Leave a Comment