What steps would be involved in constructing a destructible 2D landscape, like in Worms? Ideally, What are some ways that this process could be made efficient as possible?
-
8\$\begingroup\$ Excellent question. Worms has two challenges: destructability, and also movement on weird angles. \$\endgroup\$– ashes999Commented Dec 22, 2010 at 3:40
-
\$\begingroup\$ i think this has been asked here a number of times \$\endgroup\$– VishnuCommented Dec 22, 2010 at 4:20
-
2\$\begingroup\$ Vish, the related links don't seem to suggest that. \$\endgroup\$– PrettyPrincessKitty FSCommented Dec 22, 2010 at 11:47
-
3\$\begingroup\$ You could check how it's done in Hedgewars - it's opensource Worms clone. \$\endgroup\$– TJLCommented Apr 6, 2011 at 10:31
-
\$\begingroup\$ Not enough for an answer, but you might want to check out Clonk as well. It's an older 2D game by a German developer that also had destructible landscape, down to specific pixels. It's not under development any more, but the source code is available under the link above. There's also the open source successor OpenClonk, but from the videos it seems to have moved away from pixel-perfect destruction and took a turn in a Terraria-esque direction with kind of blocks that can be destroyed. \$\endgroup\$– ChristianCommented Oct 27, 2015 at 15:21
5 Answers
I don't know how the landscape in worms was implemented exactly, but I'm pretty sure they used a bitmap for the landscape (at least in the older games of the series).
A very basic approach would be a bitmap image (B/W) where black pixels represent air and white pixels represent ground. Destruction of the landscape can be done easily using pixel operations. So if a rocket hits the ground, paint a black circle with radius = blastRadius
at the point of impact.
You can then render your world (or just a portion of it) using that bitmap. For better performance I suggest you implement it in a way, that you can update/render just a portion of the "world". Eg. if some parts of the landscape are destroyed by a rocket, just re-render the affected areas, not the whole world.
Instead of a B/W image as your "collision-map", you could also use a 24bit image where you use two channels to store the surface-normal (x,y) per pixel and one channel to store the actual "collision-map". Having the surface-normal at hand will greatly help you to calculate bouncing grenades, or to determine if a character can move in a given direction.
-
4\$\begingroup\$ Storing extra information is the collision-map is a beautiful idea. \$\endgroup\$ Commented Apr 6, 2011 at 19:22
Use constructive solid geometry
I wrote a proof of concept that used constructive solid geometry to handle destructible terrain. I used the GLU Tessellator to perform the boolean operations. The documentation explains how, search for "CSG Uses for Winding Rules".
I fed the triangle output of the tessellator as static polygons into Box2D. The PoC worked quite well. I was able to arbitrarily subtract and add terrain in real-time and the terrain continued to behaved appropriately with Box2D. The only real hiccup was that the GLU tessellator can produce degenerate triangles which Box2D doesn't like, so I had to filter those out by hand.
The next step in the PoC (which I never got around to) was to use the SCC algorithm from the boost graph library to detect when a piece of the terrain had been severed (cut the top off a mountain). The severed terrain would still be destructible but now represented by a dynamic(non-static) Box2D body with the triangles attached as shapes. I had the design worked out but lost interest once I started digging into the boost documentation. I "plan" to revisit the idea when I make a scorched earth/Worms game someday.
One possibility off the top of my head:
Use a vector graphics path representation for storing the outline of the destructible "land". When a destruction event occurs (e.g., a grenade goes off), the blast area, represented as a circle, would be removed from the the land path via a boolean subtraction operation. The resulting path represents the new "land" for ground collision detection, and also possibly a mask for drawing the land.
-
2\$\begingroup\$ I think that's how Hedgewars does it. @Bill, you could take a look at it, since is opensource. \$\endgroup\$– GastónCommented Dec 22, 2010 at 11:58
-
2\$\begingroup\$ @Gastón The maps in Hedgewars are all images (PNGs). I doubt they are being converted to vector graphics. Also: using vector graphics (splines, bezier, etc.) is much more CPU heavy for things like collision-detection or subtracting shapes. Looking at the source is a good idea though (although the coding-style is rather bad :)) \$\endgroup\$– bummzackCommented Dec 22, 2010 at 19:07
-
4\$\begingroup\$ Computational geometry such as this can get VERY complicated, VERY fast! \$\endgroup\$ Commented Apr 6, 2011 at 21:29
-
\$\begingroup\$ Googling "box2d destructible terrain" now gives a few runnable vector demos. \$\endgroup\$ Commented Oct 14, 2017 at 10:11
All the answers above talk about implementing the simplest case, as in worms. That is, when area of impact is destroyed and everything else is untouched. Did you consider, that your landscape may eventually be split in two? Say, there's a mountain, and players cut the bottom of it with a rocket launcher. Now, shouldn't the mountain fall? Also, it would be natural for a landscape to be a little bit elastic. At the times of Worms (at least as I remember them, I didn't play Worms for, like, many years) computers weren't just strong enough to do it right. But they are now.
Of course, it totally depends on ambitions of your project. But if you want it to be really awesome, maybe you should try Box2D as a physics engine. There's a lot you can do with it.
-
3\$\begingroup\$ In worms you could dig a hole through the landscape using a torch. Wouldn't be so funny if that tunnel would just collapse on your poor torch-wielding worm. It was also possible to have pieces of the landscape "floating" in the air. Your proposal sounds like a fun idea, just not like a Worms game. \$\endgroup\$– bummzackCommented Dec 28, 2010 at 8:56
-
\$\begingroup\$ That was the whole point, I was thinking about variations on that gameplay. Also, some parts of landscape may be indestructible and/or permanently suspended in the air, which would let you create "floating" blocks. Also, some could have constant force applied to them, pulling them upwards or sideways, like what balls of air did in the World of Goo. \$\endgroup\$ Commented Dec 28, 2010 at 10:25
-
\$\begingroup\$ It's funny because I was actually considering making a game like this, it would be a fun twist to the Worms mechanic. The idea of bitmap rigid bodies would definitely be an interesting topic in itself, the complexity is a bit over my head though. \$\endgroup\$ Commented Dec 28, 2010 at 17:30
-
\$\begingroup\$ Well, in this case bitmap rigid bodies would be a no go, instead, I'd make a landscape as a triagonal grid of vertices, elastically connected. Have you played world of goo? If not, see the screenshots: vgchartz.com/games/pics/6644424aaa.jpg doublegames.de/images/screenshots/world-of-goo_1_big.jpg . No, no, no, no, if you didn't play it, you absolutely must :) Now imagine that instead of goo balls every triangle displays part of your landscape texture, and they are much smaller. Fiddle around with constants and your landscape will be either quite hard, or soft like a jelly \$\endgroup\$ Commented Dec 29, 2010 at 4:40
-
2\$\begingroup\$ take a look at the Physical engine. The entire engine is based around the idea that everything is a deforming/destructible lattice (like a tower of goo). \$\endgroup\$ Commented Apr 6, 2011 at 20:02
As bummzack said Bitmaps. Although you could use 1 bit transparencies or if you dont have that support use a horrible pink color that you wont use in your game.
The point of impact can be calculated just be checking the pixel color. and when an impact happens change the color (or delete it) of the bitmap.
As for the blast radius my first stop would be Bresenham's circle algorithm, very fast and efficient. Although I'd do a rought delete first with something like a square and put the circle round it to get the edges.