Graphics

Simple 2D Shadows Extended XNA Tutorial



You can download the source code with lots of comments at the bottom of this tutorial.

2dshadowssimple1



2dshadowssimple21

  public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        private Texture2D canopy;
        private Texture2D trunk;
        private Rectangle canopyRect;
        private byte shadowAlpha;
        private Color color;
        private int shadowOffsetX;
        private int shadowOffsetY;
        private float shadowRotation;
        private bool sunCycle = false;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

canopy145

trunk145


 protected override void Initialize()
        {
            //Set screen dimensions
            graphics.PreferredBackBufferWidth = 1280;
            graphics.PreferredBackBufferHeight = 720;
            graphics.IsFullScreen = false;
            graphics.ApplyChanges();
            Window.Title = "Simple 2D Shadows";
            
 
            //Set Shadow Start values.  These variables are used in the second spritebatch.draw in order to make our shadow.
            shadowAlpha = 40; // set transparency level, Adjust this depending on how dark your background is
            //I use the color variable to define the color of our canopy texture in the second draw of the canopy texture.
            //Using overload number 8 gives us color(byte r, byte g, byte b, byte a)
            //Remember a byte is 0 to 255. These values represent Red, Green, Blue and Alpha(transparency)
            //Setting r,g,b to 0 makes out texture black and then we can play with the alpha level to determine how transparent we
            //want our texture.  Make it darker for a darker background or adjust it based on game design.
            color = new Color(0, 0, 0, shadowAlpha); 
            shadowOffsetX = 0; // Shadow X Position offset, Use this to fine tune shadow position
            shadowOffsetY = 20; // Shadow y position offset, Use this to fine tune shadow position
            shadowRotation = -1f; //Shadow rotation starting position.  Use this to rotate the texture based upon sun position.
            
            base.Initialize();
        }



 protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            //Load canopy and trunk
            canopy = Content.Load(@"Canopy145");
            trunk = Content.Load(@"Trunk145");
            //create rectangle for canopy, sized to width and height of canopy texture
            canopyRect = new Rectangle(500, 200, canopy.Width, canopy.Height); 

            // TODO: use this.Content to load your game content here
        }



  protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            //Check if user hits spacebar and set sunCycle to true to start sun cycle
            if (Keyboard.GetState().IsKeyDown(Keys.Space) && sunCycle == false)
            {
                sunCycle = true;
            }

            //if suncycle is true (ie. you hit space bar), increment shadowRotation to rotate shadow texture 
            if (sunCycle)
            { 
                shadowRotation += .005f;

                if (shadowRotation >= 1f)  //stop shadowRotation when it is greater than 1.
                {
                    sunCycle = false;
                }
            }
          
            base.Update(gameTime);
        }






 protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.SkyBlue);

            spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.BackToFront, SaveStateMode.None);

                        spriteBatch.Draw(canopy,
                           canopyRect,
                           null,
                           Color.White,
                           0f,
                           new Vector2(0f, 0f),
                           SpriteEffects.None, 0.2f);
                       
            spriteBatch.Draw(canopy,
                             new Vector2(canopyRect.Center.X + shadowOffsetX,
                             canopyRect.Bottom - shadowOffsetY),
                             null,
                             color,
                             shadowRotation,
                             new Vector2(canopy.Width / 2, canopy.Height),
                             1f,
                             SpriteEffects.None, 0.5f);
            
            spriteBatch.Draw(trunk, 
                            new Vector2(canopyRect.Center.X, canopyRect.Center.Y), 
                            null, 
                            Color.White, 
                            0f,
                            new Vector2(trunk.Width / 2, trunk.Height / 2 - 25), 
                            1f, 
                            SpriteEffects.None, 
                            0.5f);

            spriteBatch.End();

            base.Draw(gameTime);
        }




Download 2D Shadows Extended

Simple 2D Shadows in XNA



notreeshadow1

runleft2



hereZiggywarewinners



this





behindtree1



















private Texture2D treeTop; 



treeTop = content.Load<Texture2D>(@"Tiles/canopy145"); 

You'll need your spriteBatch.Draw statements sandwiched in between spritebatch.begin and spritebatch.end in your main draw method as usual.

spriteBatch.Begin(SpriteBlendMode.AlphaBlend,SpriteSortMode.BackToFront, SaveStateMode.None, camera.Transform);

spriteBatch.Draw.....

spriteBatch.Draw....

spriteBatch.End();

I use a 2dCamera in my little game thus the camera.Transform but you don't need this for this example.

Now if you want to extend this, you could make color a variable and make your shadow x, y positions variables.  Then you could adjust your shadow position and transparency based upon wherever you want your sun.  If you want to go crazy, you could have a day night cycle and alter your shadow positions and transparency based upon the time of day.  That would be cool in an RPG.

In order to make color a variable, one way I have found that you can do it is to make color a Vector4.






Notice how I use the variable color in place of Color.White or New Color() in the second draw statement.  The only thing to keep in mind is when you make color a Vector4, you're now using floats instead of bytes.  So color is from 0 - 1.

You can apply the exact same logic to a player character.  The added benefit is your X, Y offsets for your shadows all stay the same for every direction you draw your character, thus your shadows appear consistant as you turn your character.  Here is a video of my character running and circling.  I increased the alpha to 80 so the video would show the shadow better.  I offset the player rectangle X +10 and Y - 5 on every player animation.  So all player animations have the same offset.  This places my Sun somewhere in the Southwestern sky.  It's easier to see the shadows if you watch the video in HD.