This is a short tutorial about how to make 2D destructible terrain similar to old Worms games. This technique uses Box2D and Clipper libraries. I wont explain the code, just the general idea.
1. Make Box2D bodies with chain fixtures that would match "collidable" areas on the background image:
2. During the game when a bullet hits the destructible terrain I just make a circular polygon(explosion), then take the vertices that define the terrain and do polygon clipping using Clipper. In Clipper Execute method I use ctDifference as clipType to get vertices outside the circle. Each path in the solution holds vertices that I use to define new Box2D chain fixtures, while the previous ones are destroyed. And that is basically it.
There are several reasons why I use chains instead of polygons:
a) Box2D only supports convex polygons and chains can have any (non intersecting) shape.
b) By default Box2D polygons can have up to 8 vertices. Even though that can be increased, there is still an issue with a).
c) You could use polygon triangulation(Poly2Tri or Polypartition library) on non-convex(concave) polygons, but then every time you do it the number of fixtures in the scene will increase and you will end up with hundreds of tiny fixtures. Another problem with polygon triangulation is that it can make polygons with sharp edges and the player could get stuck on those, just like he can get stuck on tiny fixtures.
But there is a problem with chains too, they are hollow. If the player is right next to the terrain and his weapon barrel is inside it you can fire a bullet inside the terrain and it will collide only when it reaches the other side of the chain fixture. A solution for that is that when generating new terrain, you create both chains and polygons using triangulation, but you set the collision filters so that the player only collides with the chains(so he doesn't get stuck) and bullets collide with the polygons(so they don't pass trough).
a) The "collidable" area/texture is rendered on a FBO which supports alpha channel.
b) When bullet hits the terrain I draw a circular polygon with an alpha value of 0 to that FBO on the location of the bullet. Using glBlendFunc(GL_SRC_ALPHA,GL_SRC_ALPHA) this makes holes in the texture.
c) I also render another, a bit bigger, circle on another FBO of the same size to make those explosion outlines.
d) Then, using multitexturing and a shader, I combine the collision FBO with the explosion outline FBO, to render those outlines only there where is visible pixels on the collison texture and outline texture, else I render pixels from collision FBO.
a) b) c) d)
uniform sampler2D img;
uniform sampler2D img2;
varying vec2 texcoord;
vec4 texcolor = texture2D(img,texcoord);
vec4 texcolor2 = texture2D(img2,texcoord);
if(texcolor.a!=0 && texcolor2.a!=0) gl_FragColor = texcolor2;
else gl_FragColor = texcolor;
The end result is rendered on screen: