I have an arbitrary destructible bitmap terrain like the one in "Worms". It's easy to work out if a character or missile intersects the terrain, but how do I work out the angle of the slope at the contact point, so I can make grenades roll down hills, bounce off at the right angle, etc. I know it can be down by somehow taking a sample of points around the impact point and seeing which ones intersect, but I'm not sure exactly how to go about it, and in an efficient way.
If you're happy sampling then run a coarse sample at a defined radius around your hit point. 16 samples in a circle will provide you with quite accurate curvature. If you add up all the vectors that "missed", you'll have a vector that can be normalised to a surface normal.
If you hit the flat floor, all the vectors will miss if they're pointing up at all, so they add up to an up vector. If you hit a 45 degree slope, the vectors that point away from the slope will miss and add up to a 45 degree vector away from the slope. Even a rough surface will provide a reasonable surface normal as you're checking for "misses" not a surface.
This works fine until you get into really tight spaces, at which point, curvature is all shot to crap anyway, and you would probably not get a sensible result in any technique other than precomputed surface normals (which can be found by blurring a "vector to closest feature" map where feature is non colliding / non matter).
Vec collisionPoint # point of collision Vec acc(0,0) for f = 0 to 2pi: vec check = vec( sin( f ), cos( f ) ) if ( check + collisionPoint ).collides(): acc += check normal = acc.normalise() # yes, there is a chance of a divide by zero.
If you want to go crazy, you could take a grid of samples around your test-point, do an edge-detection algorithm to identify the surface (i.e. any point part of the terrain with a neighbour which isn't, or vice-versa, is a surface point), and then find the best-fit line through those points to use as an approximation to the surface.
Might be overkill though :)
The original Worms probably didn't do anything more complex than bitmap/bitmap intersections - i.e. does the bitmap of the grenade intersect with the collision map of the world. Moving the grenade (or whatever) would follow these steps:
- Can the object move down one pixel without a collision? If so, move object down one pixel and end test.
- Can the object move left and down without a collision? If so, move object down and left one pixel and end test.
- Can the object move right and down without a collision? If so, move object down and right one pixel and end test.
- If object moved left and down (2) last time, can object move left one pixel? If so, move object left one pixel and end test.
- If object moved right and down (3) last time, can object move left one pixel? If so, move object right one pixel and end test.
You probably only want to do (4) and (5) for a few frame to simulate friction, e.g. repeat (4) for each preceding (2).