Building a Dynamic Shadow Casting Engine in AS3 by Preview

Tutorial DetailsProgram: FlashDevelopDifficulty: AdvancedEstimated Completion Time: 1h
Join to Access

Dynamic shadows give game developers a way to recreate real life experience with lights and shadows. Every time we move, we cast shadows according to the position of the light sources around us. Dynamic shadows are no different than that. Our goal is to transfer this experience to the virtual world by creating an engine that will be able to cast these shadows.

These are common in 3D games. You have probably played a 3D game or watched a gameplay video and noticed that the shadows in most of them are dynamic. However, due to the complexity of the code, 2D games lack a good implementation of shadows, and often end up using a static alternative. The objective of this tutorial is to implement dynamic shadows in a 2D environment.


What Will You Need?

These two .swc files are used in this tutorial, so it’s better to grab them now!

Light ball

Texture


Step 1: Defining Terms

During this tutorial we will use some terms that might not be common in your vocabulary, so here’s a quick explanation of all of them:

  • Light source: any object that will create light. It will be represented by a single point and will have the following properties: range (radius of the circle created by the light), color (of the light), intensity (amount of light in the middle of the circle) and fall off (the amount of light that will still be present at the edges of the circle).
  • Light ball: if stated in the engine that they must be shown, the light ball will be in the center of a light source’s circle and will represent the light source.
  • Solid object: any object that will cast shadows when illuminated by a light source. Will be defined by its vertices (defined in the counter-clockwise direction) and can have any shape you want, as long as it’s a convex shape.
  • Display area: the area in which all the lights and objects are contained.
  • Light map: the sprite in which we will draw all the lights and shadows of the display area.
  • Objects map: the sprite in which we will draw all the objects of the display area.
  • Ambient light: it acts like sunlight, except that it can have any color you want. It will be applied to the entire light map, independant of the presence of lights and/or objects.

Important: Please note that the solid objects must be convex shapes and their vertices are defined in the counter-clockwise direction. This is very important and you may get different results if you don’t do it (the reason for that will be explained later in the tutorial).


Step 2: An Example of Static Shadow

Static shadows are not what we want, but they are shown here to explain how they are done and in which cases having them isn’t a problem.

Description: the circles below the characters are static shadows that only give the impression of a light source from the sky, like the sun.

Static shadows are simple circles with a radial alpha gradient (the most advanced ones have the shape of the object, for example) that lie below a character or an object. Sometimes their radii change if a character jumps or an object gets more distant from the gound, but they will always have a defined shape. Shadows like that are used when the light source is very distant from the objects, giving the impression that the shadows don’t change. This is common in platform games or flying games, but not what we want to achieve here.


Step 3: Creating the Classes

Let’s begin the code! First of all, we must set up all the classes that we will work with. For this tutorial, we will need three initial classes: ShadowEngine, Light and SolidObject. They must be created this way:

The classes don’t need to extend any other class.


Step 4: Defining the Light

We will now start adding code to the classes. The first one will be the light. Here’s the basic code:

package lightning
{
	import flash.display.Sprite;
	import flash.geom.Point;

	public class Light
	{
		protected var _color:uint;
		protected var _intensity:Number;
		protected var _range:Number;
		protected var _fallOff:Number;

		protected var _x:Number;
		protected var _y:Number;

		protected var _drawingArea:Sprite;

		protected var _shadowArea:Sprite;

		public function Light(initialPosition:Point, color:uint, range:Number, intensity:Number = 1, fallOff:Number = 0)
		{
			_x = initialPosition.x;
			_y = initialPosition.y;

			_color = color;
			_range = range;
			_intensity = intensity;
			_fallOff = fallOff;

			initializeDrawingArea();
		}

		private function initializeDrawingArea():void
		{
			_drawingArea = new Sprite();

			_shadowArea = new Sprite();
		}

		public function get x():Number
		{
			return _x;
		}

		public function set x(value:Number):void
		{
			_x = value;
		}

		public function get y():Number
		{
			return _y;
		}

		public function set y(value:Number):void
		{
			_y = value;
		}

		public function get drawingArea():Sprite
		{
			return _drawingArea;
		}

		public function get shadowArea():Sprite
		{
			return _shadowArea;
		}
	}
}

We defined the _x and _y properties of the light, the _color, _range, _intensity and _fallOff. Since we will need to access the x and y properties, we created getter and setter functions for them. They might look useless, but we will add more content in the functions as we start giving more “life” to our engine. The drawing area is a Sprite in which the light will be drawn, and the shadow area is the sprite in which all the shadows related to that light will be drawn. The drawing area and shadow area will blend together later. The initializeDrawingArea() function sets the drawing area and shadow area up for drawing. More will be added into that function later.

...and that's the end of the preview!

Unlock the full tutorial by becoming a member of Tuts+ Premium

Including...

  • 886 Exclusive Tutorials

  • Course Library

  • 35 Top-selling eBooks

  • New Content Weekly

Take the Tour or Join Tuts+ Premium

If you've already got a Premium account, just Sign in to Access