<?xml version="1.0" encoding="UTF-8"?>
<!--Generated by Squarespace Site Server v5.11.81 (http://www.squarespace.com/) on Fri, 24 Feb 2012 16:03:02 GMT--><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><title>XNA Tutorials</title><link>http://www.permafrostgaming.com/xna-tutorials/</link><description></description><lastBuildDate>Sat, 21 May 2011 02:08:15 +0000</lastBuildDate><copyright></copyright><language>en-US</language><generator>Squarespace Site Server v5.11.81 (http://www.squarespace.com/)</generator><item><title>Acid Rain TileMap and Camera System XNA Tutorial</title><dc:creator>Allan Chaney</dc:creator><pubDate>Mon, 20 Sep 2010 14:51:15 +0000</pubDate><link>http://www.permafrostgaming.com/xna-tutorials/2010/9/20/acid-rain-tilemap-and-camera-system-xna-tutorial.html</link><guid isPermaLink="false">566857:8010066:8937799</guid><description><![CDATA[<p><span style="font-size: 110%;">There's nothing quite as motivating as having someone contact you via your game's website and ask for instruction on how you accomplished something in your game.&nbsp; It means they looked at your game.&nbsp; And that's great for the ego.&nbsp; And let's face it.&nbsp; In today's world of hobbyist/Indie game development, programming is more of a mashup process than actually coding from scratch.&nbsp; I would equate it more to the music industry.&nbsp; At some point in your 30s, most music starts to sound a lot like the music you used to listen to only not as good.&nbsp; And that's because all of the young artists are just rehashing sounds from the past and mashing them into new compositions.&nbsp; And there's nothing wrong with that at all.&nbsp;</span></p>
<p><span style="font-size: 110%;">Raise your hand if you plan to code your own physics engine, particle system, rendering engine, content loading system etc.&nbsp; That's what I thought.&nbsp; Coding today is a mashup of existing&nbsp; ideas and code.&nbsp; When I developed Paladin's Legacy in the mid 80s, in 6809 assembly, this wasn't the case.&nbsp; I had one book that gave me the assembler commands and that was it.&nbsp; Today we have tons of open source projects, blogs, education samples etc. etc.&nbsp; For that reason, I felt the urge to post this tutorial in order to contribute to the great mashup in the cloud and to respond to that one request.&nbsp;</span></p>
<p><span style="font-size: 110%;">The quickest way to accomplish this tutorial was to simply rip out all of the code from</span><strong><a href="http://marketplace.xbox.com/en-US/games/media/66acd000-77fe-1000-9115-d802585505b1/?bt=0&amp;sb=1&amp;mt=32&amp;gu=66acd000-77fe-1000-9115-d802585505b1&amp;p=1&amp;of=0"> Acid  Rain</a></strong><span style="font-size: 110%;"> not directly related to the tile engine or the camera system.&nbsp;&nbsp; I would recommend that you download the project <strong><a href="http://www.permafrostgaming.com/storage/AcidRainTutorialNew.zip">HERE</a></strong> and sift through the code using this posting as notes to see how stuff works.</span></p>
<p><span style="font-size: 110%;">Acid Rain is organized around the <a href="http://creators.xna.com/en-US/samples/gamestatemanagement">GameStateManagement</a> sample over at the <a href="http://creators.xna.com/en-US">creatorsclub</a> website.&nbsp; This new link is for the XNA 4.0 version.&nbsp; I guess XNA 3.1 is on the way out.&nbsp; I'm not going to review how the GameStateManagement sample works.&nbsp; There's plenty of posts about that.&nbsp; Suffice it to say that all of the game play is directed out of the gameplayscreen.cs.&nbsp; My game1.cs has been renamed to Engine.cs.&nbsp; All Engine.cs does is provide a starting class with basic screen dimension setup and it adds the first screen to be displayed by the menu system.&nbsp; There are a lot of classes but most of them are used by the gamestate menu system.&nbsp; The actual gameplay is accomplished with Player.cs, Terrain.cs, FrontOfPlayer.cs, Camera.cs and of course Engine.cs.&nbsp; Also during gameplay, you are accessing Screenmanager.cs and InputState.cs which are provided by the gamestate sample.</span></p>
<p><span style="font-size: 110%;">So to start, let's look at Engine.cs.&nbsp; We first declare the basics....A GraphicsDeviceManager and we need to instantiate the Screenmanager game component from gamestatemanagement, add a static random function and set the screen sizes.        <br /> </span></p>
<pre class="brush: csharp">    public class Engine : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        ScreenManager screenManager;

        // a random number generator that the whole game can share.
        public static Random Random = new Random();

        //random number generator for floats that the whole game can share
        public static float RandomBetween(float min, float max)
        {
            return min + (float)Random.NextDouble() * (max - min);
        }

        #region setScreenSizes Method
        private void setScreenSizes()
        {
            graphics.PreferredBackBufferWidth = 1280;
            graphics.PreferredBackBufferHeight = 720;
            graphics.IsFullScreen = false;
            graphics.ApplyChanges();
            Window.Title = "Acid Rain";
        }
        #endregion
</pre>
<p>We then need to add the screenManager game component to the game services collection.  And then we use the AddScreen method within Screenmanager.cs to add our first screen that will be displayed by the menu system.</p>
<pre class="brush: csharp">    // Create the screen manager component.
            screenManager = new ScreenManager(this);
            Components.Add(screenManager);

            // Activate the first screens.
            screenManager.AddScreen(new MainMenuScreen(), null);
</pre>
<p>Now in Acid Rain, the game, I had several screens prior to the Main Menu screen but for the purposes of this tutorial we're just plowing along trying to get to the gameplayscreen.cs which is where the game actually begins.  So take a look at MainMenuScreen.cs in the Screens folder.  This is the class used to display the menu system.  It inherits from MenuScreen which in turn inherits from GameScreen.cs.  If you are new to Object Oriented Programming, this is a real mind screw.  It basically means MainMenuScreen can use anything from MenuScreen which can use anything from GameScreen.  2 levels of inheritance.  This is why Menuscreen and GameScreen are abstract classes with virtual methods.  But I digress.  Note in MainMenuScreen.cs, we have an event that is used to load GamePlayScreen.cs when the user chooses the New Game menu option.</p>
<pre class="brush: csharp">       public MainMenuScreen()
            : base("Acid Rain", "A Hero's Journey") //base("Acid Rain", "A Hero's Journey")
        {
            
            // Create our menu entries.
            MenuEntry playGameMenuEntry = new MenuEntry("New Game");
            MenuEntry exitMenuEntry = new MenuEntry("Exit");

            // Hook up menu event handlers.
            playGameMenuEntry.Selected += PlayNewGameMenuEntrySelected;
            exitMenuEntry.Selected += OnCancel;

            // Add entries to the menu.
            MenuEntries.Add(playGameMenuEntry);
            MenuEntries.Add(exitMenuEntry);
        }

        #region New Game
        /// 
        /// Event handler for when the Play Game menu entry is selected.
        /// 
        void PlayNewGameMenuEntrySelected(object sender, PlayerIndexEventArgs e)
        {
            LoadingScreen.Load(ScreenManager, true, e.PlayerIndex, new GameplayScreen());
        }
        #endregion
</pre>
<p>Once GamePlayScreen.cs has been added to the ScreenManager screens using the LoadingScreen.cs Load method, we are plowing along through the GamePlayScreen class.  ScreenManager.cs basically unloads all of the content from the menu system and jumps into GamePlayScreen.cs and starts running that class.  Our game stays in that class until we Pause the game and exit, at which point we reload the menu system and jump back into the menu system.  But enough of that stuff.  We're finally in GameplayScreen.cs.</p>
<p>&nbsp;</p>
<p>The first thing I should talk about is Game Components and Game Services.  You'll need to know how these work in order to understand the organization of my game.  I really like Game Components.  A class is made into a game component by having it inherit from the game component interface.....like so.  Using my player class as an example.</p>
<pre class="brush: csharp">   public class Player : Microsoft.Xna.Framework.DrawableGameComponent
</pre>
<p>Game Components have the unique advantage over a class in that they have their own Update loop.  If it's a DrawableGameComponent as in the case of Player.cs, then it also comes with its own Draw loop.  This means you can have all of the update and draw logic within that class and the game is geared to loop through those methods so you don't have to call them from somewhere else.  It's nice and clean.  All Game Components also have their own copy of Game so you have access to graphics device  and Game Services etc.  This saves you from having to figure out how to pass that stuff into a naked class.  The downside to Game Components is that there is a small performance cost.  I say small, but try using a Game Component class as an enemy.  Then instantiate 50 copies of that game component class into a List for your game.  You will destroy performance.  If you are going to make multiple copies of a class, use a regular class.  In my game I have an ActorManager.cs Game component that manages my enemy and actor classes.  I have lots of enemies and lots of actors so in this case I want those to be regular classes that I can copy and add into lists.  And I call those classes update and draw methods from the ActorManager.cs update and draw methods.  If you take a look at GamePlayScreen.cs, you'll see at the top where I declare my game Components.</p>
<pre class="brush: csharp">  #region Game Component declarations
        Terrain terrain;
        FrontOfPlayer frontOfPlayer;
        Player player;
        #endregion 
</pre>
<p>Then in the Load method, I need to instantiate those game component classes and add them to the components collection maintained by XNA.  While doing this I have the ability to do something very important.  I can declare the Draworder of that game component.  The Draworder can be changed on the fly during runtime from anywhere in the game that has access to that class.  This is another nice advantage of Game Components.....you get to tell it in what order you wish to do it's draw.  This is really important for a 2D game.  Because Draw Order determines how things are layered on the screen.  For instance, I want my player to run behind some trees but on top of the grass and some rocks and even some of the tree trunks.  So in this case, Terrain has a Draworder of 5, Player is at 8 and the appropriately named FrontofPlayer is at 10.  So everything in Terrain.cs is drawn first, then Player.cs, then FrontOfPlayer.cs.  Having this all in one place let's you quickly alter the layering in your game as needed.  Very important since Acid Rain had dozens of game Componant classes and lots of layering.  Once you are in the game component class the order of drawing is determine by the sequence of spritebatch.Draw calls.</p>
<pre class="brush: csharp">  #region Instantiate Game Component Classes and determine draworder
            //Game components have their own Update and Draw methods.  This allows me to 
            //use a different spriteBatch.Begin in each Component Draw method.  In HUD, I am able to avoid the camera by not calling 
            //camera.transfrom in the HUD spritebatch.begin thus my HUD remains stationary and does not scale.
            //I am also able to use SpriteSortMode.Immediate which is faster than BackToFront.
            //DrawOrder determines the order a component is drawn to the screen and thus it's layerdepth.
            //Lower DrawOrder is back of the screen, higher is close to your face.  Another benefit of Game Components
            //is that they all have access to Game and thus the Game Services Collection.  We can add stuff to the Game Services collection
            //like audioManager, spriteBatch and thus our game components can all share resources. 

            player = new Player(ScreenManager.Game, this, ScreenManager, playerIndex);
            player.DrawOrder = 8;
            ScreenManager.Game.Components.Add(player);

            terrain = new Terrain(ScreenManager.Game, player);  //2-3 secs
            terrain.DrawOrder = 5;
            ScreenManager.Game.Components.Add(terrain);

            frontOfPlayer = new FrontOfPlayer(ScreenManager.Game);
            frontOfPlayer.DrawOrder = 10;
            ScreenManager.Game.Components.Add(frontOfPlayer);
            #endregion 
</pre>
<p>Another cool thing you can do with a Game component is to utilize the built in Enable and Visible bool functions.  This allows you to start and stop the update and draw loops at any time.  This is really useful when you pause the game.  You may want to disable the Update loop so there is no more movement but keep the Draw on so you see a static image where you paused the game.  If you look at my pause game code, you'll see that functionality.  By default Enable which controls the update loop and Visible which controls the Draw loop are set to true.  At any time, you can say Terrain.Enable = false or Terrain.Visible = false and this will no longer update or draw the Terrain Update and Draw methods.  OK let's get to the TileMap and Camera...finally.  First up is the Camera.  You should notice that Spritebatch has an overload that accepts a Matrix TransformMatrix.</p>
<pre class="brush: csharp">   spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None, ScreenManager.Camera.Transform);
</pre>
<p>My Matrix TransformMatrix is in my camera.cs class that I declare as static in ScreenManager.cs at the top of ScreenManager.cs.  This way I have access to camera everywhere.  I keep my camera class really simple for the reason that it took me a long long time to really understand what the heck was going on here.  Once I read that Spritebatch is just a very high performance and efficient Shader that the brains at MS wrote and all of those overloads just give you easy access to functions and methods within that shader code, I started to get a picture of how spritebatch worked.  I use SpriteSortMode.Immediate because it is faster than BackToFront or FrontToBack.  It also allows you to use custom shaders.  I use a Shader for my Water in Acid Rain.  And it allows you to manually keep control of your draw layering.  Once I learned that Immediate was the only option that allowed you to use shaders of your own and it was the fastest while allowing transparency and layering, I had to use Immediate.  Here is the entire Camera class.</p>
<pre class="brush: csharp">   public class Camera
    {
        public Vector2 Position = new Vector2(0, 0);  //This positions the camera at upper left corner of tilemap
        
        public float scale { get; set; }
        public float rotation { get; set; }
        public Vector2 Origin {get; set; }
        public float MaxWorldScale { get; set; }
        public float MinWorldScale { get; set; }

        public Matrix Transform = Matrix.Identity;

        public Camera(Game game)
        {
            MaxWorldScale = .5f; //  .5f Zoom Out
            MinWorldScale = 1.5f;  //  2f  Zoom In
            
            scale = 1f;
            Origin = Vector2.Zero;
        }

        public Matrix TransformMatrix(GameTime gameTime)
        {
            Transform = Matrix.CreateTranslation(new Vector3(-Position, 0)) * 
                        Matrix.CreateRotationZ(rotation) *      
                        Matrix.CreateTranslation(Origin.X, Origin.Y, 0) * 
                        Matrix.CreateScale(new Vector3(scale, scale, 0));
           
            return Transform;
         }
</pre>
<p>The MaxWordScale and MinWorldScale simply limit how far you can scale in and out of the world.  These are used in GamePlayScreen.cs in the SetWorldScale() method.  You use the joystick's right and left triggers to zoom in an out.  Left stick to move player around.    I then declare a Matrix called Transform and set it to Zero. (In the nebulous world of the Matrix, this is called Matrix.Identity.)  This is about the time I wished I had taken the red pill.  Then I alter that Transform in the TransformMatrix method by using those funky CreateTranslation,Rotation, Scale functions.  The key is that you place that Matrix Transform into the Spritebatch Begin Methods in any class where you want the draw stuff to be altered by your camera.  This somehow tools the Matrix math contained within the CreateTranslation,Rotation,Translation,Scale Matrix commands into the Spritebatch shader and puts them to work altering the screen.  You may notice that that Matrix stuff uses Vector3 in order to pass X, Y, Z coordinates.  This Matrix stuff is the same thing used for 3D game development.  By making all of the Zs equal to Zero, we simply eliminate that dimension and Matrix then works great for a 2D camera system.   So to summarize, the SetWorldScale() method is called in the Update loop in GamePlayScreen.cs.  This changes the scale value in the Camera class depending on joystick Triggers or keyboard (Z,X,C) keys. This works because the Matrix method is tooled into Spritebatch in every class where we draw and want to have that camera capability.  If you create a HUD class as I did in Acid Rain, then you would want to not have that Matrix Transform tooled into the Spritebatch.Begin.  That way your HUD remains unchanged by camera changes.&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>The final thing you need to do to make this work is to call that Camera TransformMatrix method from within your game loop.  You aren't doing that by putting the Matrix Transform into your SpriteBatch.Begin calls.  You need to have that Camera TransformMatrix called in every loop cycle so it is always looking for changes to the Matrix Transform.  Look at the Draw method in GamePlayScreen.cs and you see this is where I call it.  You only need to do this once.</p>
<pre class="brush: csharp">   public override void Draw(GameTime gameTime)
        {
            //Call TransfromMatrix method in camera class.  This runs the Matrix math in the draw loop.
            //I'm calling the transforMatrix method from the camera class (camera.Transform) 
            //and passing the return value into the Matrix transformMatirx overload in spritebatch.begin in the Game Component classes draw method.  
            //This turns on the camera matrix math for spriteBatch.Draw 
            //that allows scaling, rotation and panning(translation). I use a 3D camera with z set to 0.  
            ScreenManager.Camera.TransformMatrix(gameTime);
        }
</pre>
<p>Next we attach the camera to the Player.  I do all of this in the Player.cs class in the CameraPlayerAttach() method.</p>
<pre class="brush: csharp">   //Attach camera to player so camera moves with player.  Camera is set at 0,0 in camera class.
            //Player Origin sets player position in the center of the player texture/animation.
            //First we make camera position = to player position.  Then we need to subtract half the screen width and height
            //So the camera position ends up at the top left of the screen.
            //We adjust the screen width and height by the camera scale by dividing.  This keeps the player in the center of the screen.
            //So as the camera scales, we divide screen dimensions by camera scale.
            ScreenManager.Camera.Position.X = Player.PlayerPos.X - ((screenBounds.Width / 2) / ScreenManager.Camera.scale);
            ScreenManager.Camera.Position.Y = Player.PlayerPos.Y - ((screenBounds.Height / 2) / ScreenManager.Camera.scale);
</pre>
<p>I also Lock the Camera to the Map boundaries in the CameraScreenBoundry() method in Player.cs and of course I lock the Player to the Screen boundaries in the PlayerScreenBounrdy() method.  I do all of this in Player because I have easy access to Player Position.  And it seemed to me like this was about the player not the camera.  But some people like having all of this code in their camera class.  You can do it either way.  Same goes for that SetWorldScale() method.  I think all of those methods are self explanatory.  And my comments in the code should help you figure out what I'm doing.  One thing is I don't lock the Camera when you move the player to the top of the map.  This is so you can see that pretty/ominous blue sky.  On to the TileMap system.  First I should mention my design is based upon the Nick Gravelyn TileMap video series.  It's worth checking out since he creates an editor etc.  All of my Tile Mapping is done in Terrain.cs.  First I declare the variables for the Ground Tiles.  My base map will be 20 X 10 of 512 X 512 tiles.  So ultimately it's 10240 X 5120 in pixel dimensions.</p>
<pre class="brush: csharp">   #region Setup variables for Ground Tiles
        int mapWidth = 20;
        int mapHeight = 10;
        private Rectangle groundSourceBase;
        private Rectangle caveSourceBase;
        public static int TotalMapWidth;
        public static int TotalMapHeight;
        #endregion
</pre>
<p>Take a look at the Initialize method and you'll see I use TotalMapWidth and TotalMapHeight to store those pixel dimensions.  This is useful when you are placing stationary stuff around the map.</p>
<pre class="brush: csharp">   public override void Initialize()
        {
            groundSourceBase = new Rectangle(0, 0, 512, 512);
            TotalMapWidth = groundSourceBase.Width * mapWidth;
            TotalMapHeight = groundSourceBase.Height * mapHeight;
            
            base.Initialize();
        }
</pre>
<p>In the interest of "keeping it simple stupid" which helps for me,I just use two nested for loops in the Draw method to draw the map.  I use the grass texture from my mapObjectsSheet and grab it off of that sheet at location groundSourceBase (0, 0, 512, 512).  That's the source rectangle.  I draw it at position 0,0 and then increment it by X for every 10 times it's incremented by Y.  It draws so fast, it just looks like one big map.&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>Now to mix things up, because let's face it, the map only looks isometric due to the tilt of objects you place on the map.  In my case just about everything is tilted somewhere between 20 and 40 degrees.  But the key is you need other stuff on the map.  So I created a Struct of objects that I can randomly place around the map.  Any of them that I draw in Terrain.cs will go behind the player.  In some cases, I want the player to walk behind a tree but in front of it's trunk.  So I draw some of the tree trunks in Terrain and I draw some of them in FrontOfPlayer.  I draw most of the trees in FrontOfPlayer so the player walks underneath the Trees. This is why you see a TreeStruct in FrontOfPlayer.  If you look through the code, you'll see that all I do is randomly place rocks, trees, lumps of grass and patches of snow on top of the map.  In some cases these are drawn before the player and in some cases after the player.  If you play Acid Rain and you are very observant, you will notice that every time you exit the Tent or the Cave, the Trees are in a different place.  I re-randomize them every time you enter the main map so you're cover from the Acid Rain is always different.  The map is always changing to mix things up.  Plus I wanted to reset the trees so they could be burned down again by Volcanic rocks in all of their flaming glory.    &nbsp;</p>
<p>&nbsp;</p>
<p>The final thing I will mention is about spritebatch and content.  I continue to remain baffled as to why spritebatch and content aren't just static by default.  Since when you make a game, you only want to use one copy of spriteBatch and in most cases you only need one copy on ContentManager.  But hey....I'm not an OOP expert.  I'm only 2 years into this whole OOP game.  What I discovered is it can get really really messy trying top pass spritebatch and content too all of your classes and Game Components yet you need them pretty much everywhere you Draw and Load.&nbsp;</p>
<p>&nbsp;</p>
<p>I found the easiest way to do this was to add them to the Game Services Collection, then in each class where I need them, just call them back out. Take a look at Player.cs.  In the constructor, I retrieve the spriteBatch and content so I can use them in that class/game component.  Don't forget to declare them at the top of the class so you can use them throughout the entire class.</p>
<pre class="brush: csharp">    public class Player : Microsoft.Xna.Framework.DrawableGameComponent
    {
        GameplayScreen gamePlayScreen;
        ScreenManager screenManager;
        private Rectangle screenBounds;
        SpriteBatch spriteBatch;
        ContentManager content;
</pre>
<p>&nbsp;</p>
<pre class="brush: csharp">       public Player(Game game, GameplayScreen gamePlayScreen, ScreenManager screenManager, PlayerIndex playerIndex)
            : base(game)
        {
            this.gamePlayScreen = gamePlayScreen;
            this.screenManager = screenManager;
            this.playerIndex = playerIndex;

            //Retrieve from Game Services
            spriteBatch = ((SpriteBatch)game.Services.GetService(typeof(SpriteBatch)));
            content = ((ContentManager)game.Services.GetService(typeof(ContentManager)));

            PlayerPos = GameplayScreen.PlayerStartPos;
            startPlayerPos = PlayerPos;
   
        }
</pre>
<p>I add them to the Game Service collection in the LoadContent() methods of ScreenManager.cs and GameplayScreen.cs.  I use the content that is created from GameplayScreen.cs and I create my spritebatch and add it to Game Services in ScreenManager.cs.</p>
<pre class="brush: csharp">    if (content == null)
                content = new ContentManager(ScreenManager.Game.Services, "Content");

            //Game Services is a way for Game Components to communicate with each other since each component has a copy of Game
            //Add to content from GamePlayScreen to Game Services
            //I can then access this contentmanager from any gameplay class or Component and 
            //it will be unloaded when I call content.unload in this class.
            ScreenManager.Game.Services.AddService(typeof(ContentManager), content);  
</pre>
<p>&nbsp;</p>
<pre class="brush: csharp">  protected override void LoadContent()
        {
            // Load content belonging to the screen manager.
            //by using the contentManager from Game, I believe I will be able to have content created in screenmanager that can be shared
            //throughout the entire game including the menu system, including ParticleSystem.cs.  Unlike Gameplayscreen.cs that creates a new
            //contentmanager just for content loaded in that screen.  So any content used in both the menu system and the gameplay needs to be
            //loaded in ScreenManager.cs.
            content = Game.Content;
            spriteBatch = new SpriteBatch(GraphicsDevice);
           
            #region Game Services
            //Game Services is a way for Game Components to communicate with each other since each component has a copy of Game
            //SpriteBatch - Add to Game Services
            Game.Services.AddService(typeof(SpriteBatch), spriteBatch);
            #endregion    
</pre>
<p>I hope this helps anyone interested in a simple Tile Mapping system and Camera system.  The most complex part is simply organizing the game in the world of Object Orientation. &nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>Download the Entire Project <a href="http://www.permafrostgaming.com/storage/AcidRainTutorialNew.zip">HERE</a>. &nbsp;</p>
<p>&nbsp;</p>
<p>Allan Chaney</p>]]></description><wfw:commentRss>http://www.permafrostgaming.com/xna-tutorials/rss-comments-entry-8937799.xml</wfw:commentRss></item><item><title>Simple 2D Shadows Extended XNA Tutorial</title><dc:creator>Allan Chaney</dc:creator><pubDate>Mon, 20 Sep 2010 14:48:42 +0000</pubDate><link>http://www.permafrostgaming.com/xna-tutorials/2010/9/20/simple-2d-shadows-extended-xna-tutorial.html</link><guid isPermaLink="false">566857:8010066:8937778</guid><description><![CDATA[<object width="480" height="385" data="http://www.youtube.com/v/obqDI2oj6cQ&amp;hl=en&amp;fs=1&amp;color1=0x006699&amp;color2=0x54abd6" type="application/x-shockwave-flash"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube.com/v/obqDI2oj6cQ&amp;hl=en&amp;fs=1&amp;color1=0x006699&amp;color2=0x54abd6" /><param name="allowfullscreen" value="true" /></object> <br/>In this tutorial, I'll show you how to add simple 2D shadows to your 2D game. My original blog post demonstrated that you can create simple 2D Shadows that are realistic, with no additional textures, no new lines of code and no math.<br/>At the end of the blog post, I theorized that you could extend the concept by having dynamic shadows that are repositioned based upon the sun. So I created a simple Sun Cycle to go along with my simple 2D shadows. <strong>You can download the source code with lots of comments at the bottom of this tutorial.</strong><br/><br/><img class="alignleft size-medium wp-image-388" title="2dshadowssimple1" src="http://s3.media.squarespace.com/production/566857/6567309/wp-content/uploads/2009/02/2dshadowssimple1-300x168.png" alt="2dshadowssimple1" width="300" height="168" /><br/><br/>Inspired by other 2D shadow tutorials, I wanted to create a very simple method for adding shadows that I could understand, would add as little code as possible and would add no additional textures. One method I found involved simply using photoshop to make your textures black and transparent and then load those new textures into your game. But then you end up with two textures for every object, the real object and the blackened, transparent object (shadow). It occurred to me that spritebatch.draw will do exactly what this method did in photoshop. Thus you can do 2D shadows in your game without adding the shadow textures.<br/><br/><img class="alignleft size-medium wp-image-392" title="2dshadowssimple21" src="http://s3.media.squarespace.com/production/566857/6567309/wp-content/uploads/2009/02/2dshadowssimple21-300x168.png" alt="2dshadowssimple21" width="300" height="168" />Ultimately, all I do is redraw my existing texture, make it black and transparent, and reposition it based upon my arbitrary sun position. In order to create a sun cycle, I create variables out of my spritebatch.draw parameters that control position, color and layer depth.

<br/>I started with the default XNA 3.0 game template and just started adding code. The first thing I needed were variables to control my shadow. These variables are primarily used in the second spritebatch.draw where I redraw the canopy of my tree as a shadow. My textures are canopy and trunk. I keep them as separate pieces because if you shadow the trunk, it will appear to float over the ground. So I just want to shadow the canopy and leave the trunk flat and on the ground. My textures are designed to be sort of isometric in that they are tilted forward 45 degrees. This works for my little game project but the idea can be applied to any 2D perspective you might choose. I create a rectangle for the canopy so I have easy control over positioning both the canopy and it's shadow. I create variables for alpha and color because that's how I'm going to make my canopy texture black and transparent in the second spritebatch.draw. I create a couple of offsets so I can fine tune the shadow position. I have a variable for rotation, again, for positioning, and finally a boolean for sunCycle so I can have a little running demo.

<br/>
<pre class="brush: csharp">
  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";
        }
</pre>

<br/><img class="alignleft size-full wp-image-393" title="canopy145" src="http://s3.media.squarespace.com/production/566857/6567309/wp-content/uploads/2009/02/canopy145.png" alt="canopy145" width="256" height="320" /><br/><br/><img class="alignright size-full wp-image-395" title="trunk145" src="http://s3.media.squarespace.com/production/566857/6567309/wp-content/uploads/2009/02/trunk145.png" alt="trunk145" width="175" height="303" /><br/><br/> In my initialize method, I set the screen dimensions and name my little game window. Then I setup the starting values for my variables. I set alpha to 40 but you can play with this value depending on how dark you have your background. The darker your background, the darker you will want your shadow. The real magic of this concept is in the color command. Typically we would just use Color.White and that would make our texture opaque. Instead of saying Color.White, I use one of the overloads in Color. Amazingly, there are 9 overloads for Color. I use #8 which uses bytes to represent R, G, B, A. New Color(byte r, byte g, byte b, byte a). That’s Red, Green, Blue and Alpha. A byte is 0 - 255. Zero is black, 255 is white/opaque. So when you are saying Color.White, it’s the same as if you said New Color(255, 255, 255, 255). The Alpha is transparency which you can set on the fly for your texture. And here is the key... If you make r, g and b all equal Zero, you get black. Set your Alpha to 40. Thus you are saying redraw my texture in a different position, make it black and make it transparent down to 40 instead of fully opaque at 255. I then setup my shadow position variables, the offsets and rotation.

<br/>
<pre class="brush: csharp">
 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();
        }
</pre>
<br/>
In my load content method, I load my textures and create a rectangle for my canopy texture. I set the width and height of the rectangle to the width and height of the texture. So my rectangle is the same size as my canopy texture.
<br/><br/>
<pre class="brush: csharp">
 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<Texture2D>(@"Canopy145");
            trunk = Content.Load<Texture2D>(@"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
        }
</pre>
<br/>
My update method is pretty simple. All I'm doing is checking to see if the user hits the space bar. If they do, I set the boolean sunCycle to true. It was originally set to false. I have another If then that checks to see if sunCycle is true. If it is true, then increment my rotation variable, shadowRotation, and then keep incrementing until shadowRotation is equal to 1f and set sunCycle to false. This stops the rotation.
<br/><br/>
<pre class="brush: csharp">
  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);
        }
</pre>

<br/>
The draw method is where all of the real work gets done. First you'll notice I turned on SpriteSortMode.BackToFront in the spritebatch.begin. This allows me to sort my sprites from back to front on the screen in each draw statemnent. If you don't do this, your sprites will be drawn based upon the order of your spritebatch.draw commands. Personally, I like to control the ordering or layering of my sprites on the screen. Then I don't have to worry about the specific order of my draw commands. The first spritebatch.draw simply draws our canopy texture inside of the previously defined canopyRectangle. The source rectangle is null since it is unused. I set Color to white or opaque. No rotation. Origin is unused. No spriteeffects. Layer Depth is set to .2. This keeps the canopy on top of the trunk and shadow, or you could say it's closer to the camera or your face. 0 is in your face. 1 is the back of your screen.<br/><br/>In the second spritebatch.draw, we redraw the same canopy texture but change a number of parameters in the draw command. Our destination rectangle is the center bottom of the canopy rectangle with an offset variable for X and Y used for fine tuning the position of our shadow. Source rectangle is set to null since it's unused. The color variable gives us our magic. I set color to black (0, 0, 0, alpha) with alpha(transparency) set to 40. ShadowRotation is our float for rotation. Next is Origin. The rotate variable will rotate around the origin point. We could just use new vector(0,0) but the shadow rotation would then rotate around the top left corner of the rectangle. It works better if you set the origin to the center bottom of the rectangle so that becomes your rotation point. I set the rotation point or the origin at the center of the texture X and at the Bottom Y. We don't use scale. No spriteeffects. Layer Depth is below or under the canopy. This puts the transparent canopy under the regular canopy.<br/><br/>Finally we draw the trunk. Again, I use origin to find the center of the truck texture and then place the center of the trunk in the center of the canopy rectangle so it is nicely positioned. I offset the center point slightly, just to fine tune it's position.
<br/>
<pre class="brush: csharp">
 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);
        }
</pre>
<br/>
So there you have it. A simple 2D shadow that changes depending on where you position your sun. I think it looks pretty good. Now consider that if you kept your sun position the same throughout your game, you could eliminate all of the variables and just put your final values in your second spritebatch.draw command. By doing this, you would be adding 2D shadows with no additional textures, a simple copy of your already existing draw command (with changes to parameters you are passing) and no math.<br/><br/>Of if you're making some form of RPG, wouldn't it be cool to have a sun cycle with dynamic shadows all the while being mindful of the file size constraints required by Xbox 360 community game submission.
<br/>
<a href="http://www.permafrostgaming.com/storage/sourcecode/2DShadowsSimple.zip">Download 2D Shadows Extended</a>
<br/>
Allan Chaney]]></description><wfw:commentRss>http://www.permafrostgaming.com/xna-tutorials/rss-comments-entry-8937778.xml</wfw:commentRss></item></channel></rss>
