Destructible terrain - Worms

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.



Physics

1. Make Box2D bodies with chain fixtures that would match "collidable" areas on the background image:





There are probably some algorithms out there which could generate those shapes based on the given image, but for now I did it manually in the editor. It is not something that you would like to do every day:




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).

Rendering

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;

void main()
{   
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:


14 comments:

  1. How to run an example?
    Error inicialized FMOD audio system!
    windows 7 x64
    log:
    BMUG engine started.
    Engine object created.
    Game preload finished.
    SDL initialized.
    SDL video mode initialized.
    OpenGL version: 3.3.0
    Multitexturing: 4
    Window handle found.
    Input set.
    Audio manager deleted.
    Renderer deleted.
    Input manager deleted.
    Texture manager deleted.
    Font manager deleted.
    GUI manager deleted.
    Skeleton manager deleted.
    Animation manager deleted.
    Particle manager deleted.
    BMUG engine shut down.

    ReplyDelete
    Replies
    1. Hi, for some reason the audio system fails to initialize and the game shuts down. Unfortunately I don't know why, you are the first one who actually tried to run this and reported back. Could you try downloading the newest version of the engine http://antonior-software.blogspot.com/2014/12/broken-mug-engine-2d-ragdoll-physics.html If this one fails too, I will try to see if I could get FMOD write down a more detailed error message.

      Delete
    2. I have that error too, in my computer is not have audio device out put. It seems that the problem is causing the error

      Delete
  2. Very interesting work that you've done there. Would it be possible to get hold of source for this solely for my own educational purpose?

    ReplyDelete
    Replies
    1. Thanks. The problem is that this was only a proof of concept, and was hacked in to my existing code, so I can make a video showing it. I don't have the working code anymore.

      Delete
  3. Hi, I'm having problems with Rendering. Do I get it right that the FBO "only" works as a data storage and is not cleared every frame?

    ReplyDelete
    Replies
    1. what does FBO mean? could you give me any information about this?

      Delete
    2. FBO stands for "framebuffer object". It enables you to render things on a texture, instead of rendering directly on the screen.

      Delete
  4. Thanks for your fast reply!
    By "FBO which supports alpha channel" do you mean that the texture in COLOR_ATTACHMENT_0 has to be created with format GL_RGBA ?

    ReplyDelete
    Replies
    1. I use GL_RGBA when I create a texture using glTexImage2D()then I attach that texture to a framebuffer object using glFramebufferTexture2D(). Here is my code: https://pastebin.com/d8Q6VkPT

      Delete
    2. Awesome, thank you!
      Now lets see if I can get it to render..

      Delete
    3. Hello Antonio,
      unfortunately I am not able to render the content of my texture buffer. I was just thinking to ask a question on StackOverflow, but before that I wanted to ask if there is any chance to look into some of your rendering code?
      Thanks for your help!

      Delete
    4. I don't have a clean piece of code that I could send you, so you could understand it. I think it would be best you make that topic on StackOverflow, show your own code and explain what you are doing, then I can look it up there. You could send me an email when you do it instead of posting here, you can find the address on top of the blog under Contact.

      Delete