House of Shadows is a Flash-based web game I’ve been working on for quite some time. It is set on Halloween night. You are a young boy trick-or-treating with your little sister. As you inch past a creepy old house, she decides to run up and knock on the door. It opens and suddenly she is pulled inside. You have to enter the house, find your sister and rescue her. Along the way you encounter ghosts and ghouls, stalking through the house and looking for little kids. You have to sneak past them or they’ll notice you, chase you, and gobble you up. So in terms of gameplay it’s a “sneaker” like Metal Gear Solid or Thief. But it also has some pretty cool tech.
I’ve written a couple of prototypes for the game, and the people who have played it are begging me to finish it. So far I haven’t been able to find the time. The game not only has fun, spooky gameplay, but some pretty nifty shadowing technology. Well, pretty cool as far as 2D Flash games go. Specifically, it has a shadow casting system that works like a top-down version of Doom 3. Allow me to demonstrate.

Here, for the technically minded, is an overview of how these shadows work.
The game world is a grid, and each grid cell is marked as “blocking” or “unblocking.” Blocking cells block the light and therefore cast shadows; unblocking cells, naturally, do not.
To generate the shadows, I start by identifying which grid cell the light source is in. I then visit every other cell in the world that lies within the light’s maximum radius. For every blocked cell I add the one or two edges that “face toward” the light source to a list of blocking edges. (Actually, this step is done once when the map loads and cached for later access.)
Now that I have a list of blocking edges, each consisting of two vertices, I measure the angle from the light to each vertex and then sort all vertices by their angle. This gives me a 360-degree “panoramic” list of the vertices.
Now I walk this list in order, generating the “render vertices” as I go. This step is complicated, but basically, for each vertex visited, I check for:
- Coterminal vertices. Two vertices that are at the same location can be treated as one vertex.
- Silhouette vertices. A vertex at the “edge” of a blocking cell (or group of cells) casts a shadow. I create a new “shadow edge” by casting a ray back through each silhouette vertex. I then have to check if this shadow edge intersects another blocking edge, in which case the blocking edge is bisected and a new vertex created. Otherwise—if the shadow edge doesn’t intersect anything, but goes past the light’s radius—then I create a new “far edge”—an arc representing the far limit of the light’s area.
Once I’ve visited all the blocking vertices, I now have a list of “render edges.” These consist of line segments and curves that I then pass into Flash (using graphics.drawPaths()) in order to render a shape that represents the area illuminated by the light.
I do this for all light sources, rendering one shape per light source.
This collection of rendered shapes is then used as a mask onto the actual world—the floor boards, characters, etc. Flash uses masks to decide what to render, so in effect, my light shapes cut away parts of the world that no light illuminates.
I also use the collection of rendered shapes, along with a glow filter, to create the fuzzy darkness that haunts the edges of the shadows. Without this step, shadow edges would be absolutely sharp (as in Doom 3).
Finally, each light source is also given its own MovieClip so that it shows up as a glowing ball with a colored alpha gradient. This gives the illusion of colored light sources. Up to this point, lights have no color.
That, in a nutshell, is how it works. If you’re interested and want more detail, let me know.
As you can see, the shadowing technology is done. I have another prototype of the actual gameplay. Hopefully I’ll get some time this summer to go beyond prototyping, to finish the game and make it available.
11 Comments
Impressive, but your shadow technology is hardly “done.” There are still several dozen artifacts and odd shadow shapes that occur very easily and totally spoil the effect. Lots of unrealistic merging of shadows and sharp pointy things where there shouldn’t be any. Also, when there are two blocks corner to corner then a shadow is generated in the corner when there should be none. There’s an article on these 2D shadows like this on GameDev.net you should check out. Here’s the link: http://www.gamedev.net/reference/programming/features/2dsoftshadow/
Cool link. Thanks for that. But those techniques are for Direct3D/OpenGL, and I’m implementing in Flash. For Flash, this is far as I’m taking it, and I doubt it could be taken much farther due to performance considerations. The only serious artifacts remaining are those that occur when you move the light source out of the map or inside a blocker—which can’t happen in the real game because of collision detection.
Looks cool, however now and then the debugger spits out
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at CShadowCalculator/GetRayRayIntersection()
at CShadowCalculator/GetIntersection()
at CShadowCalculator/CalculateLightPolygonBasedOnBlockages()
at CShadowCalculator/CalculateLightPolygon()
at CShadowCastGame/NotifyEnterFrame()
This happens pretty much every time I move the light into the obstacle in the middle of the left hand side.
Thanks for the bug report! I will look into that. As I mentioned in a previous comment, the ability to move lights inside things that block lights is a temporary, developer feature, so I’m not surprised there’s a bug there. But I’d still like to kill it.
Oh man this is cool! I would love to chat with you about how this is done as I’m looking for a lighting solution for a shockwave tile engine I am working on!
So cool!
- ook
Hi Jeramy! Let’s talk—I’d be happy to share more about it. Also, check out this solution that someone else pointed out. I think it’s basically the same approach but with some interesting differences.
Cool demo. I found it after knocking up my own shadow/light casting system for a game I’m doing (also in Flash). In order to better blend the shadows between multiple lights I’m creating new shadow layers per light. This way, you can blend more easily between the shadow layers to create a smoother transition. I’ve gotten it working nicely with any shape (including irregular shapes with multiple vertices) – the algorithm behind this is very simple to keep flash running smoothly. Also I’ve worked out a nice (fast/cpu-unintensive) method of doing hard-soft shadow shaping if you’re interested…
That’s sounds awesome. I’d love to see more. Incidentally, my system has developed a bit over the summer but I haven’t had time to post the new demo. The new system is pretty ideal in terms of features and still runs fast, though it doesn’t support soft shadows. Check back in a week or so if you’re interested.
I’ll pop it online when I get a chance some time – haven’t had much of a chance to work on it. I re-wrote it from the ground up after some initial prototyping and I’m still optimizing it. The soft-shadows technique was a visual cheat, not fully calculated (flash needs as many cheats as possible): http://img268.yfrog.com/i/znf.jpg. However, there is a really nice “how to” I found afterwards for working out soft-shadows properly with penumbra calculations, etc. (http://www.gamedev.net/reference/programming/features/2dsoftshadow/). It’s written with OpenGl in mind, but much can be taken over to flash.
Thanks for the update, stringy. Incidentally, that first link to the jpg image is broken. Could you update?
Weird, it worked when I tested previously, yFrog seems to have nixed it. Try this: http://s697.photobucket.com/albums/vv338/stringycustard/?action=view¤t=soft-shadow.jpg
Bad quality on Photobucket but still legible.