Make circles in ofxBox2d
Box2d, simply put, is incredible! You can do so much with it, and the results are so satisfying. I want to show you how to make simple circles bounce around your screen. This is a simple introduction to the addon I created ofxBox2d and the creative coding platform openFrameworks.
ofxBox2d was created to simplify the process of creating objects for box2d. There are many steps in order to create a box2d object and this addon helps speed up this process to a few lines of code.
First, download ofxBox2d from GitHub and place it in your openFrameworks addon folder.
Open the project generator in OF/projectGenerator/projectGenerator. let's call this project “box2d circles” now click and add ofxBox2d in the addons dropdown, click generate and open in your IDE.
I am using a mac to build this demo but this will all work on any platform that openFrameworks supports.
Box2d is set up where we have objects like rectangles, circles, polygons, lines, etc. These objects have properties like position, size, density, bounce, and friction. We need to set these properties then add them to the box2d world. The “world” is what runs the simulation, we can set things like gravity and world size. We also have nice helper functions to create bounds to constrain objects and set up object grabbing so that you can interact with the shapes.
We are going to use a very simple circle to start. In ofApp.h include ofxBox2d.h and add a circle object as well as the box2d world.
// add to ofApp.h
ofxBox2d box2d;ofxBox2dCircle circle;
Now let's get things set up and make a circle bounce! We first initialize box2d, create bounds for the world, and set gravity. Next set the circle position, radius, density, bounce, and friction. You can play with these values and get very different results. If you set the density to zero it will make the object static and not move. Increasing the bounce will cause the circle to, well be very bouncy. Increasing the friction will cause the circle to come to rest faster. Lastly, add the circle to the world.
In the update function, we “step” the world calling box2d.update() and then draw the default circle in the main draw loop. Build + Run and see that circle bounce!
Ok, cool but not amazing. We at least now understand how an object in box2d is set up, but let's make a ton of circles and get something more interesting. We need to use a vector to store all the objects. We store the objects as a shared_ptr, we do this because when we create the object and add it to the box2d world there is memory allocated and referenced in the box2d world. If we use a vector of dynamic objects every time we push_back a new object we are reallocating the entire vector, destroying the objects. This will cause a memory leak and crash. A shared_ptr will prevent this and make everyone happy when adding tons of circles.
The shared_ptr syntax is simple, we create an object with a set <TYPE>. In our example, we will make ofxBox2dCricle our type and use that in our vector type.
ofxBox2d box2d;
vector<shared_ptr<ofxBox2dCircle>> circles;
Now let's create a circle object every 30 frames and add it to the vector. We will draw all the circles by looping through the vector and drawing the circle. When we want to address the circle in the vector, we just treat it like a pointer object and use the arrow syntax.
Now we have tons of circles being created! Very quickly you will notice that your machine will slow down if too many circles are created. Let's add a bit of code to remove the first circle in the vector if we have more than 500 circles.
if (circles.size() > 500) {
circles.erase(circles.begin());
}
If we want to draw the circles with our own color we can do that like so.
void ofApp::draw() {
ofBackground(249, 220, 196);
for(auto &circle : circles) {
auto radius = circle->getRadius();
auto pos = circle->getPosition();
ofFill();
ofSetColor(240, 128, 128);
ofDrawCircle(pos, radius);
}
}
Try drawing just the angles of the circles as lines.
void ofApp::draw() {
ofBackground(249, 220, 196);
for(auto &circle : circles) {
auto radius = circle->getRadius();
auto pos = circle->getPosition();
auto angle = circle->getRotation();
ofSetColor(10);
ofPushMatrix();
ofTranslate(pos);
ofRotateDeg(angle);
ofDrawLine(-radius, 0, radius, 0);
ofPopMatrix();
}
}
From here there is a ton you can do. Play with other ways of rendering the circles. Try making other types of shapes, mix shapes. I will be creating some more tutorials on creating custom box2d shapes and other ways to render shapes. All the code can be downloaded here from Github, feel free to reach out with any questions. Have Fun!