Acid Rain Technical Details

DEVELOPMENT FACTS

Development Time - 18 months
Language - C#
IDE - Microsoft Visual Studio Express Edition 2008
API Framework - XNA

Audio Tools

  • Microsoft Cross-Platform Audio Creation Tool XACT
  • Pro Tools LE (Music)
  • Audacity (Effects)
  • Wavosaur (Effects)

 Graphics  

  • Poser 7, 8 (Character Animation)
  • ZBrush 3.1, 3.5 (3D Modeling)
  • Photoshop CS4 (Texture editing and Painting)
  • EarthSculpter (Terrain Formation)
  • Vue 8 (Box Art)
  • Fraps (Video Capture for Gameplay Video)

Acid Rain TileMap and Camera System XNA Tutorial

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.  It means they looked at your game.  And that's great for the ego.  And let's face it.  In today's world of hobbyist/Indie game development, programming is more of a mashup process than actually coding from scratch.  I would equate it more to the musicindustry.  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.  And that's because all of the young artists are just rehashing sounds from the past and mashing them into new compositions.  Andthere's nothing wrong with that at all. 

Raise your hand if you plan to code your own physics engine, particle system, rendering engine, content loading system etc.  That's what I thought.  Coding today is a mashup of existing  ideas and code.  When I developed Paladin's Legacy in the mid 80s, in 6809 assembly, this wasn't the case.  I had one book that gave me the assembler commands and that was it.  Today we have tons of open source projects, blogs, education samples etc. etc.  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.

Acid Rain is organized around the GameStateManagement sample over at the creatorsclub website.  This new link is for the XNA 4.0 version.  I guess XNA 3.1 is on the way out.  I'm not going to review how the GameStateManagement sample works.  There's plenty of posts about that.  Suffice it to say that all of the game play is directed out of the gameplayscreen.cs.  My game1.cs has been renamed to Engine.cs.  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.  There are a lot of classes but most of them are used by the gamestate menu system.  The actual gameplay is accomplished with Player.cs, Terrain.cs, FrontOfPlayer.cs, Camera.cs and of course Engine.cs.  Also during gameplay, you are accessing Screenmanager.cs and InputState.cs which are provided by the gamestate sample.

So to start, let's look at Engine.cs.  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.       

    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

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.

    // Create the screen manager component.
            screenManager = new ScreenManager(this);
            Components.Add(screenManager);

            // Activate the first screens.
            screenManager.AddScreen(new MainMenuScreen(), null);

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.

       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

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.

 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.

   public class Player : Microsoft.Xna.Framework.DrawableGameComponent

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.

  #region Game Component declarations
        Terrain terrain;
        FrontOfPlayer frontOfPlayer;
        Player player;
        #endregion 

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.

  #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 

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.

   spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None, ScreenManager.Camera.Transform);

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.

   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;
         }

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. 

 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.

   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);
        }

Next we attach the camera to the Player.  I do all of this in the Player.cs class in the CameraPlayerAttach() method.

   //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);

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.

   #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

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.

   public override void Initialize()
        {
            groundSourceBase = new Rectangle(0, 0, 512, 512);
            TotalMapWidth = groundSourceBase.Width * mapWidth;
            TotalMapHeight = groundSourceBase.Height * mapHeight;
            
            base.Initialize();
        }

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. 

 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.     

 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. 

 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.

    public class Player : Microsoft.Xna.Framework.DrawableGameComponent
    {
        GameplayScreen gamePlayScreen;
        ScreenManager screenManager;
        private Rectangle screenBounds;
        SpriteBatch spriteBatch;
        ContentManager content;

 

       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;
   
        }

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.

    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);  

 

  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    

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.  

 Download the Entire Project HERE.  

 Allan Chaney

Acid Rain in Review for Xbox Live Indie Game Marketplace

Acid Rain is finally on it's last leg of development.  I submitted my game for review at the Creators Club website.

In order to view or review games in review, you have to be a premium member of the Creator's Club which costs $90 per year.  So the link above will not take you directly to my game.  If you are a premium member, here is the link to Acid Rain in Review:

This is the final step needed in order to sell your game on the Xbox 360 in the Xbox Live Indie Game (XBLIG) marketplace.  I actually submitted it on March 15th...and so far I have had one person review it and provide information on a bug that I have been unable to replicate.

So at this point, it's really just a waiting game.  You wait and hope some kind soul will take their volunteer time to download your game, play it and either pass or fail it.  You need 3 passes to be approved and I think it's two fails to fail.  If you fail, you pull the game, make fixes and resubmit after a 7 day waiting period.

In the meantime, I've been working on forming my company, developing the box art for the game and putting together a website for my company.  It's really important anytime you plan on selling something to the public that you form an LLC or an S-Corp.  Yes you could always just use your social security number but that places you in grave personal risk at the whim of a litigious happy public.  Instead, when you form an LLC or S-Corp, you are not selling anything.  The company is selling the product and thus the risk is shifted from you personally to the company.  You are simply an employee of the company.  The bottomline here is something called the corporate veil.  It is a veil of protection that protects you, your family, your savings and any other assets you have built over your lifetime from lowlife nuts who would like to rob you of those things.  Remember, in this country, anyone can sue you for any reason.  If a person decides they are not happy with your product, they can sue you for everything you are worth.  When you form a company, they can not come after you or your personal assets, they can only sue the company.  Now they can destroy your company...but they can't take your home, your children's college funds etc.  You are protected by the corporate veil.  This is also known as liability protection and it is the #1 reason for forming a company.  And should be standard practice anytime you offer anything to the public.

My new company is called PermaFrost Gaming LLC.  That's a cute reference to my roots since I was born and raised in Fairbanks, Alaska.  And I thought it would be cool to model an ice cube in Zbrush with a chunk of ground on top, with a little dude trying to climb up the cube.

Acid Rain: A Hero's Journey --Dream Build Play 2010 Entry

I submitted my game into Microsoft's 2010 Dream Build Play competition today. Deadline is tomorrow March 3rd so i just made it in.

Watch it full screen at Youtube: Acid Rain  

Make sure you switch the video to 720p in the lower right of the video window.  It defaults to 360p which looks fuzzy.

Whew.  I'm going to take a little break from my game and catch up on stuff I have neglected. I hope to do some posts about the tools I used to make my game and I'd like to do a series of tutorials on spritebatch. Oh yeah and I need to get my taxes done. I'm not sure how long the judging lasts but since I know there is no way I'll hear anything back, my plan is to go ahead and playtest for another couple of weeks then submit my game for playtesting with Microsoft (ie. the Creator's Club website). If it passes that I'll submit for review and with any luck get it on the Indie Live Marketplace. The DBP contest gave me a focus point which forced me to cut things off and consolidate/finalize missions etc.

So here is my gameplay video for Acid Rain. It's not a trailer. That will take a lot more work. This is just my submission video for DBP. This is also too long for a trailer which should probably be under a minute.

 

Simple 2D Shadows Tutorial recognized

So this was a pleasant surprise.

My first XNA tutorial that I submitted to Ziggyware.com here and of course posted on this site here was recognized by Microsoft.

I know it's a small thing but it's those small things that encourage us to continue forging ahead.

Here is the link to MS's reference to my tutorial on 2D simple Shadows.  What I really like is I am categorized with other "Space Brains".

http://blogs.msdn.com/xna/archive/2009/03/10/creators-club-communiqu-21.aspx

Allan

Volcano Storm Update - Working on GamePlay

I'm finally posting an update video on my efforts with XNA.

This is about a month and a half of work after my last video.  What have I added/changed?  Pretty much everything.

I completely dumped the Tile System that I was using from Nick Gravelyn's video tutorials series.  I just couldn't stand the look of the repetitive Tiles.  Perhaps it is my lack of artistic knowledge in creating seamless tiles that don't look so repetitive but after trying to create seamless tiles that don't look repetitive for months, I finally gave up.  Once my programming knowledge increased a little I was able to start toying with other terrain generation ideas.  I'm still using a bottom foundation of rocky grass tiles, however since my game structure is not constrained to tile size, there was no reason why I counldn't branch out on the tile concept.  My foundation tiles are now 510 X 510, created in ZBrush, rotated forward at 20 degrees and then screen captured as 510 X 510 Top Down tiles.  I have a bunch of game Objects that litter the foundation base.  All of these are created as 3D objects in ZBrush, tilted 20-45 degrees and randomly placed on my map.  This includes the mountains, Rocks, Trees, downed Trees, Volcano etc.  This helps break the repitition.  I also created a second layer of snowy landscape  Tiles that overlays the rocky grass layer.   I'm still vasilating on the look of the snowy ground layer.  I like the snow but it starts to make things look kind of busy. Perhaps too busy.  Since it's all randomly generated (except for the foundation rocky grass layer) I'm able to adjust the size of my map on the fly and the volume of stuff on the map.

I added a cloud layer that scales as you zoom in and out with the camera.  There are clouds that roll across the mountain range at all times and then there are higher clouds that only appear when you start to zoom out.  As you zoom out, I adjust the clouds transparency and scale so it looks like you are moving through the cloud layers.   My son said, "You need to adjust the sound so when you zoom out and are further away, your rock explosions and AcidRain Bursts are quieter."...so I did that....except for the thunder of course....because that's up where you are.   He said, "You need storm clouds."  So I added stormy clouds with lightning and thunder.  He reminded me that there is a delay between thunder sound and lightning.  OK.  That took a few days.  Then he said, what happens when the volcano rocks hit the trees.  I guess they should burn.  A week later and they burn.  And of course I needed burnt tree textures to replace the regular tree textures.

So now I have a look that I am moderately satisfied with.  Now the hard part....I need to make gameplay.

Thankfully I didn't neglect collision detection in my design so my player collides with the acidrain and the volcano rocks..  He also collides with the mountains and the volcano.  That collsion makes him slow and scale since he is climbing.  And of course I have to keep track of everything's depth.  Since the player walks behind some things and in front of others.  And he collides with certain higher rock formations.

Adding player health is the first step to gameplay once you have collision detection.  So I started working on a HUD.  Since my player is a vacationing mountain climber/hiker, I thought a rope would be appropriate for my health bar.  After several days trying to make a rope in ZBrush....(one that I could rotate and frey into strings and pieces)..in order to capture the frames I needed for a desintigrating rope/health bar, I integrated it into my game.  I added a rope exploding particle effect, code to tie the length of the rope to player health and a temperary text field just so I can make sure the rope length is actually tied to player health.  I showed this to my daughter and I said, "How do you like the health bar?"  She said, "Oh that...it looks ok."  See my guy is a vactioning mountain climber, so I thought a rope would be a good....  She said, "Oh that's a rope?" 

Ouch.  She got a good laugh out of that.
 
Allan

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.

Review Learn Programming Now! XNA Game Studio 2.0 by Rob Miles

Very Silly Games

Rob,

As a new C#/XNA programmer, I've really enjoyed your book, "Learning Programming Now!" If you don't mind I have a few basic coding questions.

My 1st question is, Why do you use an algorithim to scale sprites to the displaywidth and height in your Bread and Cheese game when it seems that you could just use the scale feature built into the SpriteBatch.Draw method. There is an overload for Draw that includes scale. Would it not be simpler to just use that built-in scale feature in Draw and adjust it relative to DisplayWidth and Height?

My 2nd question is, On the XNA Creator's Club Website in the Getting Started section, there is a tutorial teaching you to make a 2D "Shoot the Flying Saucers" game. In this tutorial, the author uses a seperate class to define his sprites. He calls his class GameObjects and in that class assigns the various sprite fields etc. In his main Game class he then refers to those fields by using GameObjects dot field. (GameObjects.field) However in your book in the Bread and Cheese game you use a Structure to hold the sprite information. Is this simply a personnal coding perference or is one way better than the other?

My Final Quesiton is more complicated so please bear with me. I've read a few books that use GameComponents and Game Services to organize their code. (I'm specifically referring to "Beginning XNA 2.0 Game Programming" by Lobao, Evangelista and Faris.) This organizational structure seems bizarrly complicated to me and it seems to me that it breaks the elegance of using the class structure and proper inheritance/parameter passing between classes that you learn in C#. However the game code works and in some regards it's much simpler because is seems that it gets around all of the inheritance problems that become very complicated using multiple classes.

Since you don't address this type of structure in your book, would you be willing to offer your opinion on the use of GameComponents/Services vs. classes as a way to structure game code in C# and XNA?

Thanks so much for your help.

Allan Chaney

Sorry about the delay in getting back to you. Been awfully busy recently. I've put my answers in line...

My 1st question is, Why do you use an algorithim to scale sprites to the displaywidth and height in your Bread and Cheese game when it seems that you could just use the scale feature built into the SpriteBatch

Draw method. There is an overload for Draw that includes scale. Would it not be simpler to just use that built-in scale feature in Draw and adjust it relative to DisplayWidth and Height?

>>> Indeed I could use the scale. The thing is that I wanted to use this to teach about programming and scaling. Perhaps in a future book I could mention that the method is avaiable.

My 2nd question is, On the XNA Creator's Club Website in the Getting Started section, there is a tutorial teaching you to make a 2D "Shoot the Flying Saucers" game. In this tutorial, the author uses a seperate class to define his sprites. He calls his class GameObjects and in that class assigns the various sprite fields etc. In his main Game class he then refers to those fields by using GameObjects dot field. (GameObjects.field) However in your book in the Bread and Cheese game you use a Structure to hold the sprite information. Is this simply a personnal coding perference or is one way better than the other?

>>> I wanted to start with structures and then move into objects later.

My Final Quesiton is more complicated so please bear with me. I've read a few books that use GameComponents and Game Services to organize their code. (I'm specifically referring to "Beginning XNA 2.0 Game Programming" by Lobao, Evangelista and Faris.) This organizational structure seems bizarrly complicated to me and it seems to me that it breaks the elegance of using the class structure and proper inheritance/parameter passing between classes that you learn in C#. However the game code works and in some regards it's much simpler because is seems that it gets around all of the inheritance problems that become very complicated using multiple classes.

Since you don't address this type of structure in your book, would you be willing to offer your opinion on the use of GameComponents/Services vs. classes as a way to structure game code in C# and XNA?

>>> I've not had a chance to look at this book I'm afraid. If you want my philosophy on game structure take a look at my Starlight game for Smartphone. It is not an XNA game, but it has a lot of stuff about game design and sprite management. It also has some stuff about animation that you might find useful.

http://msdn.microsoft.com/en-us/library/aa446569.aspx

I'm immensely impressed anytime an author both supports their work with this kind of dedication and takes the time to communicate with their readers.  His website is amazing.  He has the code for a ton of his games you can download and learn from.

I highly highly recommend this book for any beginning or intermediate XNA developer.

My only recommendation for Mr. Miles is that he please write another book updating the text for XNA version 3.0 and I think he should spend a chapter or two addressing muli-class structured code and the use of Game Components.  Although these are complex topics, they are unavoidable and Rob Miles is the perfectly suited to explain them to you and me.

Allan