Dillinger Lee's profileProgramming 4NE1BlogLists Tools Help

Dillinger Lee Heermann

Occupation
Location
I told my daddy "When I grow up I want to be a musician". He told me "Son, you can't have both!"

Programming 4NE1

Tutorials in Plain English by Dillinger
May 01

Dillinger's first XNA Game

Well, my first rudimentary game written using C# and XNA is finally done.
Actually it's been done for quite some time but I've been taking advantage of all this gorgeous California weather to pursue some of my other hobbies like gardening. I usually do more programming during the cold months when it's too chilly for outdoor stuff. In fact, I was going into overtime a bit there: watching some beautiful spring days ticking by outside but I hadn't finished my game yet. So I made some last minute finishing touches and made a mad dash outside and haven't been heard from since. Now that I've got most of my plants in and have already begun harvesting a bunch of romaine lettuce and a few strawberries, I figured I could take a minute to post my game and let the critics rip it to shreds :)

Another reason it took so long was I was trying to see if  could get some free FTP space somewhere to post it which would allow you to just download the .zip file from a link, free of advertisements. The best I could do is some cheezy storage space that comes with my DSL service provider called Briefcase Storage. I guess people don't do FTP anymore cause it's a security risk or something. So anyways here's the link to my "Briefcase":
http://briefcase.yahoo.com/musicalglass@sbcglobal.net

In there you should be able to find the file called Keys & Locks.
I've included all the source code and have already compiled it once so the .exe  should already be in there in one of the folders if you don't want to compile it yourself.

I didn't go overboard and do much in the way of ergonomics, like adding sound and nice scene fades or 2 player mode or extra levels or anything. I just focused on getting the game logic complete. For now the weather is too nice and I'm working on one of my inventions for a solar water heater. Maybe see you when the weather gets mushy or something. Cheers ya'll.

March 14

XNA Clickable Sprite Sheet

If for any reason you may need to have an animated sprite which is still clickable at a per pixel level, you may find this usefull.
I didn't really need to solve this for my own game design plans. It was just one of those crossword puzzle kind of things: in trying to design the ultimate, versatile animated sprite class, I'm trying to think of different possible scenarios people might want to use it for. I'm thinking oh, what if someone wants to make a game of catch the octopus or something. You know.

One known bug I haven't quite worked out yet is how to make it work with scaling. I tried a couple random pokes at it but, once again, since I don't have a need for that feature at this time, I'll just put that on the back burner and get on with implementing various other features into my game. If anybody's a math whiz and can figure it out, feel free to send it to me.

 

#region Using Statements
using System;
using System.Collections;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
#endregion
 // Tutorials in plain English by Dillinger - http://musicalglass.spaces.live.com
 /// <summary> This is the main squeeze for your game </summary>
 public class Game1 : Microsoft.Xna.Framework.Game
 {
         static GraphicsDeviceManager graphics;
         static public ContentManager content;
         static SpriteBatch spriteBatch;
 static ArrayList SpriteManager = new ArrayList();
 static public Viewport viewport;
 static Vector2 mousePosition;
 static public int spritesAcross = 3;
 public Game1()
         {
         graphics = new GraphicsDeviceManager(this);
         content = new ContentManager(Services);
         }
         /// <summary> Allows the game to perform any pre-game initialization. </summary>
         protected override void Initialize()
         {
         // TODO: Add your initialization logic here
         base.Initialize();
         }
 /// <summary> Load your graphics content. </summary>
         /// <param name="loadAllContent"> Specify which type of content to load.</param>
         protected override void LoadGraphicsContent(bool loadAllContent)
         {
         if (loadAllContent)
         {
         IsMouseVisible = true; // Show the mouse cursor ( default is false )
 spriteBatch = new SpriteBatch(graphics.GraphicsDevice);
 viewport = graphics.GraphicsDevice.Viewport;
 // we use a For Loop to cycle through the SpriteManager ArrayList and Add the specified number of Sprites
         for (int counter = 0; counter < spritesAcross; counter++)
         SpriteManager.Add(new SpriteSheet(@"FolderName\SpriteSheetTexture", 0, 3, 3, 1, 1));
 // Use a For Loop to make changes to each Sprite in the Array.
         for (int counter = 0; counter < spritesAcross; counter++)
         {
         SpriteSheet tempSprite = new SpriteSheet(@"FolderName\SpriteSheetTexture", 0, 3, 3, 1, 1); // "Stunt Double!!"
         tempSprite.Position = new Vector2(((counter + 1) * (viewport.Width / 4)), viewport.Height / 2); // Position the Stuntman
         tempSprite.OriginCentered = true;
         tempSprite.CurrentFrame = counter;
         SpriteManager[counter] = tempSprite; // Jettison Stuntman
         }
 }
 // TODO: Load any ResourceManagementMode.Manual content
         }
         /// <summary> Unload your graphics content. </summary>
         /// <param name="unloadAllContent"> Specify which type of content to unload.</param>
         protected override void UnloadGraphicsContent(bool unloadAllContent)
         {
         if (unloadAllContent)
         {
         foreach (SpriteSheet Dude in SpriteManager)
         Dude.Dispose();
 spriteBatch.Dispose();
 content.Unload();
         }
         }
         /// <summary> Update Game Logic </summary>
         /// <param name="gameTime"> Update only when the game engine says so. </param>
         protected override void Update(GameTime gameTime)
         {
         // Allows the default game to exit on Xbox 360 or Windows if the Back Button or 
         // the Escape key has been pressed
         if ((GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) ||
         (Keyboard.GetState().IsKeyDown(Keys.Escape)))
         this.Exit();
 UpdateMouse();
 foreach (SpriteSheet Dude in SpriteManager)
         {
         Dude.MouseOver(mousePosition);
         Dude.Update(gameTime);
         }
 base.Update(gameTime);
         }
         /// <summary> Clear Screen & Draw Game </summary>
         /// <param name="gameTime"> "We will update no game, before it's time." Will Wright </param>
         protected override void Draw(GameTime gameTime)
         {
         graphics.GraphicsDevice.Clear(Color.Black);
 spriteBatch.Begin();
 foreach (SpriteSheet Dude in SpriteManager)
         {
         Dude.DrawFrame(spriteBatch);
         }
 spriteBatch.End();
 base.Draw(gameTime);
         }
 /// <summary> Get Mouse Data and store X and Y coords as Vector2 </summary>
         protected void UpdateMouse()
         {
         MouseState mouseState = Mouse.GetState(); // MouseState has a lot of different properties. All we need is the Position for now.
 // The mouse X and Y positions are set relative to the Top, Left of the game window.
         mousePosition.X = mouseState.X; // Get current Mouse Coordinates and store in Vector2 mousePosition.
         mousePosition.Y = mouseState.Y;
 } // end UpdateMouse Method 
 }
 /// <summary> SpriteSheet Class 
         /// Play Animation Sequence using multiple images from a single Texture  file </summary>
         class SpriteSheet
         {
         #region SpriteSheet Properties & Fields - Public && Private
 private Texture2D texture;
         public Texture2D MyTexture
         {
         get { return texture; }
         set { texture = value; }
         }
 private Vector2 position;
         public Vector2 Position
         {
         get { return position; }
         set { position = value; }
         }
 private Rectangle textureSegment;
         public Rectangle TextureSegment
         {
         get { return textureSegment; }
         set { textureSegment = value; }
         }
 private Color color;
         public Color Color
         {
         get { return color; }
         set { color = value; }
         }
 private float rotation;
         public float Rotation
         {
         get { return rotation; }
         set { rotation = value; }
         }
 private float rotationSpeed;
         public float RotationSpeed
         {
         get { return rotationSpeed; }
         set { rotationSpeed = value; }
         }
 private float scale;
         public float Scale
         {
         get { return scale; }
         set { scale = value; }
         }
 private Vector2 origin;
         public Vector2 Origin
         {
         get { return origin; }
         set { origin = value; }
         }
 private bool centered;
         public bool OriginCentered
         {
         get { return centered; }
         set { centered = value; }
         }
 private bool centerOfScreen;
         public bool CenterOfScreen
         {
         get { return centerOfScreen; }
         set { centerOfScreen = value; }
         }
 private SpriteEffects spriteEffects;
         public SpriteEffects SpriteEffects
         {
         get { return spriteEffects; }
         set { spriteEffects = value; }
         }
 private float layerDepth;
         public float LayerDepth
         {
         get { return layerDepth; }
         set { layerDepth = value; }
         }
 private int currentFrame;
         public int CurrentFrame
         {
         get { return currentFrame; }
         set { currentFrame = value; }
         }
 private int startFrame;
         public int StartFrame
         {
         get { return startFrame; }
         set { startFrame = value; }
         }
 private int endFrame;
         public int EndFrame
         {
         get { return endFrame; }
         set { endFrame = value; }
         }
 private double frameDuration;
         public double FrameDuration
         {
         get { return frameDuration; }
         set { frameDuration = value; }
         }
 private bool paused;
         public bool Paused
         {
         get { return paused; }
         set { paused = value; }
         }
 private bool looped;
         public bool Looped
         {
         get { return looped; }
         set { looped = value; }
         }
 private bool finishedPlaying;
         public bool FinishedPlaying
         {
         get { return finishedPlaying; }
         set { finishedPlaying = value; }
         }
 private bool isClicked;
         public bool IsClicked
         {
         get { return isClicked; }
         set { isClicked = value; }
         }
 public void Reset()
         {
         currentFrame = startFrame;
         finishedPlaying = false;
         frameTimer = 0f;
         }
         public void Stop()
         {
         Pause();
         Reset();
         }
         public void Play()
         {
         paused = false;
         if (finishedPlaying)
         Reset();
         }
         public void Pause()
         {
         currentFrame--;
         paused = true;
         }
 private int framesAcross;
         private int framesDown;
         private Vector2 frameDimensions;
         private double frameTimer;
 #endregion
 /// <summary> Load SpriteSheet default settings
         /// </summary>
         /// <param name="Texture"></param> <param name="StartFrame"></param> <param name="EndFrame"></param>
         /// <param name="FramesAcross"></param> <param name="FramesDown"></param> <param name="FramesPerSecond"></param>
         public SpriteSheet(string Texture, int StartFrame, int EndFrame, int FramesAcross,  int FramesDown, double FramesPerSecond)
         {
         texture = Game1.content.Load<Texture2D>(Texture);
         color = Color.White;
         startFrame = StartFrame;
         endFrame = EndFrame;
         framesAcross = FramesAcross;
         framesDown = FramesDown;
         frameDuration = 1 / FramesPerSecond;
         currentFrame = StartFrame;
         frameDimensions = new Vector2(texture.Width / framesAcross, texture.Height  / framesDown);
         scale = 1.0f;
         rotation = 0.0f;
         rotationSpeed = 0.0f;
         spriteEffects = SpriteEffects.None;
         layerDepth = 0.5f;
         looped = true;
         }
 /// <summary> Update Current Frame </summary>
         /// <param name="gameTime"> Update only when the Game Engine says it's OK </param>
         public void Update(GameTime gameTime)
         {
         if (centerOfScreen)
         position = new Vector2(Game1.viewport.Width / 2, Game1.viewport.Height  / 2); // If true, Position Sprite in Center of Screen
 if (centered)
         origin = frameDimensions / 2; // Set the Sprite's Center relative to the Texture Segment
 UpdateFrame(gameTime);
 // rotation += rotationSpeed; // Update rotation if rotationSpeed is greater than 0.0
         }
 /// <summary> Autonomous Sprite Checks to see if Mouse has been  clicked on it and 
         /// if Yes, Changes it's own Color :) </summary>
         /// <param name="mousePosition"> Current Mouse Position must be passed in from outside because it's not part of the Sprite Class </param>
         public void MouseOver(Vector2 mousePosition)
         {
         if (Mouse.GetState().LeftButton == ButtonState.Pressed) // Don't bother doing anything unless the Mouse has been clicked.
         {
         if (MouseOverSprite(mousePosition) == true) // First we do a simple collision check to see if we're within bounds of the Sprite.
         { // If yes, we get all anal and check each Pixel to see if it's Alpha  ( visible ) or not.
         if (GnatsAssPixelCheck(mousePosition) == true) // If the Pixel the Mouse is over is Visible....
         isClicked = true; // do something.
         }
         }
         else
         {
         isClicked = false; // If not, set it back the way it was. 
         }
 if (isClicked)
         {
         paused = true;
 }
         else
         paused = false;
 }
 /// <summary> Update SpriteSheet Index </summary>
         /// <param name="gameTime"> When the Game Engine says jump, the Sprites say "how high?" </param>
         public void UpdateFrame(GameTime gameTime)
         {
         if (paused)
         return;
 frameTimer += gameTime.ElapsedGameTime.TotalSeconds; // Add a tick to the Frame Duration Timer.
         if (frameTimer > frameDuration) // If frame has finished...
         {
         currentFrame++; // Increment to Next Frame.
         // Play the SpriteSheet Animation from startFrame to endFrame
         if ((currentFrame >= endFrame) || (currentFrame < startFrame)) // Ensure that the index stays inside the SpriteSheet
         if (looped)
         {
         currentFrame = startFrame;
         }
         else
         {
         finishedPlaying = true;
         Pause();
         }
 frameTimer -= frameDuration; // Reset Frame Duration Timer
         }
         }
         public void DrawFrame(SpriteBatch spriteBatch)
         {
         // If the number of total frames is more than the number of frames across the texture, the texture has more than one row of frames. 
         // Calculate how many rows needed to wrap total number of frames in Index.
         // Store Division result as Int, which drops any decimals. Telling us how many full rows there are.
         int indexY = currentFrame / framesAcross;
         // Subtract number of complete rows * number of frames across texture,  from total index. 
         // The remainder tells us how many frames are left in incomplete row. Giving us the X coordinate of the current frame :)
         int indexX = currentFrame - (indexY * framesAcross);
 textureSegment = new Rectangle(
         indexX * (int)frameDimensions.X,
         indexY * (int)frameDimensions.Y,
         (int)frameDimensions.X,
         (int)frameDimensions.Y
         );
 spriteBatch.Draw(texture, position, textureSegment, color, rotation, origin, scale, spriteEffects, layerDepth);
         }
 public void Dispose()
         {
         texture.Dispose();
         }
 /// <summary> Check to see if the Mouse is within the specified Sprite's Texture Coords. </summary>
         /// <param name="sprite2Check"> Simply pass in the name of the Sprite Class instance you would like to check :) </param>
         /// <returns> Boolean Value - true if Mouse is over Sprite. </returns>
         bool MouseOverSprite(Vector2 mousePosition)
         {
         if (mousePosition.X >= (position.X - origin.X) && mousePosition.X < (position.X + (textureSegment.Width) - origin.X) &&
         mousePosition.Y >= (position.Y - origin.Y) && mousePosition.Y < (position.Y + (textureSegment.Height) - origin.Y))
         return true;
         else return false;
         } // end MouseOverSprite Method 
 bool GnatsAssPixelCheck(Vector2 mousePosition)
         {
         // Get Mouse position relative to top left of SpriteSheet Texture. ( This wuz a brain fry folks! )
         Vector2 pixelPosition = mousePosition - position - origin + (frameDimensions)+ new Vector2(textureSegment.X, textureSegment.Y);
 uint[] PixelData = new uint[1]; // Declare an Array of 1 space just to store data for one pixel.
 // Get the Texture Data within the specified Rectangle coords, in this case a 1 X 1 rectangle.
         // Store the data in pixelData Array.
         texture.GetData<uint>(0, new Rectangle((int)pixelPosition.X, (int)pixelPosition.Y, (1), (1)), PixelData, 0, 1);
 // Check if pixel in Array is non Alpha ( plus a fudge factor of 20 )
         if (((PixelData[0] & 0xFF000000) >> 24) > 20)
         return true;
         else return false;
         } // end GnatsAssPixelCheck Method 
 }
       
        
March 07

Xna Sprite Manager

Earlier, we made more than one Instance of the same Sprite using a Sprite Class. Each Sprite was given a unique name and we could do things to it by calling it by name.
That's fine if we've got a few Sprites to work with, but what if we have dozens of Sprites? That can turn into a lot of hand coding.
In this example I'm using the same Clickable Sprite Class from earlier. Only this time instead of creating individual instances of the Sprite Class, I make an entire Array of Sprites using an ArrayList.
Now we can use a Loop to cycle through each Sprite in the ArrayList and make whatever changes, such as calling each Sprite's Update Method.
I also demonstrate how to make changes to individual Sprite's in the ArrayList. All of the Sprite's should turn red if clicked except one, which turns green.

 

#region Using Statements
using System;
using System.Collections;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
#endregion
// Tutorials in plain English by Dillinger http://musicalglass.spaces.live.com
         /// <summary> this is the main snip for your game </summary>
         public class Game1 : Microsoft.Xna.Framework.Game
         {
         static GraphicsDeviceManager graphics;
         static ContentManager content;
         static SpriteBatch spriteBatch;
 static ArrayList SpriteManager = new ArrayList(); // A Clean, well lighted place for Sprites.
 static Vector2 mousePosition; // Minnie's favorite way to get down.
 static int numberOfSprites = 5;
 Random RandNumb = new Random();
 public Game1()
         {
         graphics = new GraphicsDeviceManager(this);
         content = new ContentManager(Services);
         }
 /// <summary> Initialize Stuff </summary>
         protected override void Initialize()
         {
         // TODO: Add your initialization stuff here
         base.Initialize();
         }
 /// <summary> Load Graphics Stuff </summary>
         protected override void LoadGraphicsContent(bool loadAllContent)
         {
         if (loadAllContent)
         {
         IsMouseVisible = true; // Show the mouse cursor ( default is false )
 // Now, instead of loading each Sprite affectionately by name...
         // mySprite = new Sprite(content.Load<Texture2D>(@"FolderName\TextureName"), new Vector2(100, 200), Color.White);
 // we use a For Loop to cycle through the SpriteManager ArrayList and Add the specified number of Sprites
         for (int counter = 0; counter < numberOfSprites; counter++)
         SpriteManager.Add(new Sprite(content.Load<Texture2D>(@"FolderName\TextureName")));  // All I specify is which Texture to use, 
         // since that may change for different sprites. But other attributes such as Position and Color are things which are inherent to all Sprites.
         // Those values are part of the Sprite Class below.
         // Now that we've created an Array of Sprite Instances, we can change some of their parameters if we like:
 // Update each Sprite in the ArrayList using ForEach Loop
         foreach (Sprite Dude in SpriteManager)
         {
         Dude.Position = new Vector2(RandNumb.Next(10, 500), RandNumb.Next(10, 500)); // Changes each Sprite's Position X & Y to Random values
         }
 spriteBatch = new SpriteBatch(graphics.GraphicsDevice);
         }
         }
 /// <summary> Unload Graphics Stuff </summary>
         protected override void UnloadGraphicsContent(bool unloadAllContent)
         {
         if (unloadAllContent)
         {
         // Trash each Sprite in the ArrayList using ForEach Loop
         foreach (Sprite Dude in SpriteManager)
         {
         Dude.Dispose();
         }
 spriteBatch.Dispose();
         content.Unload();
         }
         }
 /// <summary> Update Game Stuff </summary>
         protected override void Update( GameTime gameTime )
         {
         // Allows the default game to exit on Windows if the Keyboard Escape key has been pressed.
         if ( Keyboard.GetState().IsKeyDown( Keys.Escape ) ) // Obviously if you're using a Mouse, you're probably not on the XBox.
         this.Exit();
 UpdateMouse();
 // mySprite.Update( mousePosition ); // Instead of Updating each Sprite  individually...
 // Update each Sprite in the ArrayList using ForEach Loop
         foreach ( Sprite Dude in SpriteManager )
         {
         // Update Sprite parameters such as Position. This line makes Sprites dance about ( not being used )
         // Dude.Position = new Vector2(Dude.Position.X + (RandNumb.Next(3) - 1), Dude.Position.Y + (RandNumb.Next(3) - 1)); // Random from -1 to +1
         Dude.Update( mousePosition );
         }
 // Update only 1 individual Sprite in the ArrayList
         Sprite tempSprite = (Sprite)SpriteManager[1]; // Store ArrayList Sprite in a proxy Sprite
         if ( tempSprite.IsClicked == true ) // Modify the proxy
         tempSprite.Color = Color.Green;
         SpriteManager[1] = tempSprite; // Ship it back from whence it came
 base.Update( gameTime );
         }
 /// <summary> Clear Screen & Draw Stuff </summary>
         protected override void Draw( GameTime gameTime )
         {
         graphics.GraphicsDevice.Clear( Color.Black );
         spriteBatch.Begin();
 // mySprite.Draw(spriteBatch); // Draw 1 Sprite by name
 // Draw each Sprite in the ArrayList
         foreach (Sprite Dude in SpriteManager)
         {
         Dude.Draw(spriteBatch);
         }
 spriteBatch.End();
         base.Draw(gameTime);
         }
 /// <summary> Get Mouse Data and store X and Y coords as Vector2 </summary>
         protected void UpdateMouse()
         {
         MouseState mouseState = Mouse.GetState(); // MouseState has a lot of different properties. All we need is the Position for now.
 // The mouse X and Y positions are set relative to the Top, Left of the game window.
         mousePosition.X = mouseState.X; // Get current Mouse Coordinates and store in Vector2 mousePosition.
         mousePosition.Y = mouseState.Y;
 } // end UpdateMouse Method 
         /// <summary> 2D Sprite Class </summary> ==================================================================
         class Sprite
         {
         public Sprite(Texture2D texture)
         {
         Texture = texture;
         }
 #region Properties & Fields - Public & Private
 private Texture2D texture;
         public Texture2D Texture
         {
         get { return texture; }
         set { texture = value; }
         }
 private Vector2 position;
         public Vector2 Position
         {
         get { return position; }
         set { position = value; }
         }
 private Color color;
         public Color Color
         {
         get { return color; }
         set { color = value; }
         }
 private bool isClicked;
         public bool IsClicked
         {
         get { return isClicked; }
         set { isClicked = value; }
         }
 #endregion
 /// <summary> Autonomous Sprite Checks to see if Mouse has been clicked on it and 
         /// if Yes, Changes it's own Color :) </summary>
         /// <param name="mousePosition"> Current Mouse Position must be passed in from outside because it's not part of the Sprite Class </param>
         public void Update( Vector2 mousePosition )
         {
         if ( Mouse.GetState().LeftButton == ButtonState.Pressed ) // Don't bother doing anything unless the Mouse has been clicked.
         {
         if (MouseOverSprite( mousePosition ) == true ) // First we do a simple collision check to see if we're within bounds of the Texture Coordinates.
         { // If yes, we get all anal and check each Pixel to see if it's Alpha ( visible ) or not.
         if (GnatsAssPixelCheck( mousePosition ) == true) // If the Pixel the Mouse is over is Visible....
         isClicked = true; // do something.
         }
         }
         // else isClicked = false; // If not, set it back the way it was. 
 if (isClicked == true)
         color = Color.Red;
 else
         color = Color.White;
 }
 public void Draw( SpriteBatch spriteBatch )
         {
         spriteBatch.Draw( texture, position, color );
         }
 public void Dispose()
         {
         texture.Dispose();
         }
         /// <summary> Check to see if the Mouse is within the specified Sprite's Texture Coords. </summary>
         /// <param name="mousePosition"> Pass in the current Mouse Position </param>
         /// <returns> Boolean Value: true if Mouse is over Sprite. </returns>
         bool MouseOverSprite(Vector2 mousePosition)
         {
         if ( mousePosition.X >= position.X && mousePosition.X < ( position.X + texture.Width ) &&
         mousePosition.Y >= position.Y && mousePosition.Y < ( position.Y          + texture.Height ) )
         return true;
         else return false;
         } // end MouseOverSprite Method 
         /// <summary> Check individual pixels in the Texture for Alpha Transparency </summary>
         /// <param name="mousePosition"> Pass in the current Mouse Position </param>
         /// <returns> Boolean Value: true if current Pixel is Visible </returns>
         bool GnatsAssPixelCheck(Vector2 mousePosition)
         {
         // Get Mouse position relative to top left of Sprite Texture.
         Vector2 pixelPosition = mousePosition - position;
 uint[] PixelData = new uint[1]; // Declare an Array of 1 space just to store data for one pixel.
 // Get the Texture Data within the specified Rectangle coords, in this case a 1 X 1 rectangle.
         // Store the data in pixelData Array.
         texture.GetData<uint>( 0, new Rectangle((int)pixelPosition.X, (int)pixelPosition.Y, (1), (1)), PixelData, 0, 1 );
 // Check if pixel in Array is non Alpha ( plus a fudge factor of 20 )
         if ( ((PixelData[0] & 0xFF000000) >> 24) > 20 )
         return true;
         else return false;
         } // end GnatsAssPixelCheck Method 
         }
         }

 

March 06

XNA Sprite Sheet Animation

Here's the new Animated Sprite Sheet Class I've been working on. A SpriteSheet is an animated Sprite using multiple images from a single Texture File.
Here is an example:

SpriteSheet Texture

In my SpriteSheet Class the size of the Texture is irrelevant. The computer does all the math for you. You simpy specify how many images Across and how many Down.
So this SpriteSheet Texture's parameters would be: 4, 2

When changing the Sprite's Center of Origin, you have to account for the size of the current texture segment. Not the whole Texture size. All that is built in as well.
I've included built in CenterOfOrigin as well as CenterToScreen.

In this example I have 3 Sprites instances from the same class, but they each do a little bit different things. They should all be animating at different speeds. One Sprite uses CenterToScreen and OriginCentered. Another has it's Center of Origin offset a bit. I have a couple rotating at different speeds to demonstrate that the whole Origin thing is working properly.

You can see that my Sprite class is getting larger. This would be a good excuse to bust the SpriteSheet Class into it's own page. But to make it comprehensive for a web tutorial, I put it all on one page.
With Visual C#, that's fairly easy to do: In the Solution Explorer, right click on the name of your project and select Add / Class. Name your new class SpriteSheet.cs
Select everything between the curly brackets in your existing SpriteSheet Class, Cut it and paste it into your new SpriteSheet Class Page. Now just clean up the leftover empty class and compile.
This allows you to keep your code in separate, manageable sections when your program starts getting a little large.
Hopefully that should be sufficient explaination for you to go ahead and do it. If not, let me know and I'll throw in some screenshots.

 

#region Using Statements
using System;
using System.Collections;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
#endregion
// Tutorials in plain English by Dillinger - http://musicalglass.spaces.live.com
/// <summary> This is the main squeeze for your game </summary>
public class Game1 : Microsoft.Xna.Framework.Game
 {
         static GraphicsDeviceManager graphics;
         static public ContentManager content;
         static public Viewport viewport;

         static SpriteBatch spriteBatch;
         private SpriteSheet animatedSprite1;
         private SpriteSheet animatedSprite2;
         private SpriteSheet animatedSprite3;
 public Game1()
         {
         graphics = new GraphicsDeviceManager(this);
         content = new ContentManager(Services); 
         }
         /// <summary> Allows the game to perform any pre-game initialization. </summary>
         protected override void Initialize()
         {
         // TODO: Add your initialization logic here
         base.Initialize();
         }
         
         /// <summary> Load your graphics content. </summary>
         /// <param name="loadAllContent"> Specify which type of content to load.</param>
         protected override void LoadGraphicsContent(bool loadAllContent)
         {
         if (loadAllContent)
         {
         spriteBatch = new SpriteBatch(graphics.GraphicsDevice);
viewport = graphics.GraphicsDevice.Viewport;
         animatedSprite1 = new SpriteSheet();
         animatedSprite2 = new SpriteSheet();
         animatedSprite3 = new SpriteSheet();
         // Load SpriteSheet Texture.
         // Numbers indicate StartFrame, EndFrame, FramesAcrossSpriteSheet, FramesDownSpriteSheet, FramesPerSecond
         animatedSprite1.Load( @"FolderName\SpriteSheetTexture", 0, 7,  4, 2, 4 );
         animatedSprite1.Position = new Vector2( viewport.Width / 3, viewport.Height / 3 );
         animatedSprite2.Load( @"FolderName\SpriteSheetTexture", 3, 5, 4, 2, 1 );
         animatedSprite2.CenterOfScreen = true;
         animatedSprite2.OriginCentered = true;
         animatedSprite2.RotationSpeed = 0.02f;
         animatedSprite3.Load( @"FolderName\SpriteSheetTexture", 4, 7, 4, 2, 0.4 );
         animatedSprite3.Position = new Vector2( (viewport.Width / 3) * 2, (viewport.Height / 3) * 2 );
         animatedSprite3.Origin = new Vector2( 20, 20 );
         animatedSprite3.RotationSpeed = 0.04f;
         }
 // TODO: Load any ResourceManagementMode.Manual content
         }
         /// <summary> Unload your graphics content. </summary>
         /// <param name="unloadAllContent"> Specify which type of content to unload.</param>
         protected override void UnloadGraphicsContent(bool unloadAllContent)
         {
         if (unloadAllContent)
         {
         animatedSprite1.Dispose();
         animatedSprite2.Dispose();
         animatedSprite3.Dispose();
         spriteBatch.Dispose();
 content.Unload();
         }
         }
         /// <summary> Update Game Logic </summary>
         /// <param name="gameTime"> "We will update no game, before it's time." Will Wright </param>
         protected override void Update(GameTime gameTime)
         {
         // Allows the default game to exit on Xbox 360 or Windows if the Back Button or 
         // the Escape key has been pressed
         if ( (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed ) || 
         ( Keyboard.GetState().IsKeyDown(Keys.Escape)) )
         this.Exit();
         animatedSprite1.Update(gameTime);
         animatedSprite2.Update(gameTime);
         animatedSprite3.Update(gameTime);
 base.Update(gameTime);
         }
         /// <summary> Clear Screen & Draw Game </summary>
         /// <param name="gameTime"> When to Draw </param>
         protected override void Draw(GameTime gameTime)
         {
         graphics.GraphicsDevice.Clear(Color.Black);
         spriteBatch.Begin();

         animatedSprite1.DrawFrame(spriteBatch);
         animatedSprite2.DrawFrame(spriteBatch);
         animatedSprite3.DrawFrame(spriteBatch); 

         spriteBatch.End();
 base.Draw(gameTime);
         }
         /// <summary> SpriteSheet Class 
         /// Play Animation Sequence using multiple images from a single Texture file </summary>
         class SpriteSheet
         {
         #region SpriteSheet Properties & Fields - Public && Private
 private Texture2D texture;
         public Texture2D MyTexture
         {
         get { return texture; }
         set { texture = value; }
         }
 private Vector2 position;
         public Vector2 Position
         {
         get { return position; }
         set { position = value; }
         }
 private Rectangle textureSegment;
         public Rectangle TextureSegment
         {
         get { return textureSegment; }
         set { textureSegment = value; }
         }
 private Color color;
         public Color Color
         {
         get { return color; }
         set { color = value; }
         }
 private float rotation;
         public float Rotation
         {
         get { return rotation; }
         set { rotation = value; }
         }
 private float rotationSpeed;
         public float RotationSpeed
         {
         get { return rotationSpeed; }
         set { rotationSpeed = value; }
         }
 private float scale;
         public float Scale
         {
         get { return scale; }
         set { scale = value; }
         }
 private Vector2 origin;
         public Vector2 Origin
         {
         get { return origin; }
         set { origin = value; }
         }
 private bool centered;
         public bool OriginCentered
         {
         get { return centered; }
         set { centered = value; }
         }
 private bool centerOfScreen;
         public bool CenterOfScreen
         {
         get { return centerOfScreen; }
         set { centerOfScreen = value; }
         }
 private SpriteEffects spriteEffects;
         public SpriteEffects SpriteEffects
         {
         get { return spriteEffects; }
         set { spriteEffects = value; }
         }
 private float layerDepth;
         public float LayerDepth
         {
         get { return layerDepth; }
         set { layerDepth = value; }
         }
 private int currentFrame;
         public int CurrentFrame
         {
         get { return currentFrame; }
         set { currentFrame = value; }
         }
 private int startFrame;
         public int StartFrame
         {
         get { return startFrame; }
         set { startFrame = value; }
         }
 private int endFrame;
         public int EndFrame
         {
         get { return endFrame; }
         set { endFrame = value; }
         }
 private double frameDuration;
         public double FrameDuration
         {
         get { return frameDuration; }
         set { frameDuration = value; }
         }
 private bool paused;
         public bool Paused
         {
         get { return paused; }
         set { paused = value; }
         }
 private bool looped;
         public bool Looped
         {
         get { return looped; }
         set { looped = value; }
         }
 private bool finishedPlaying;
         public bool FinishedPlaying
         {
         get { return finishedPlaying; }
         set { finishedPlaying = value; }
         }
         public void Reset()
         {
         currentFrame = startFrame;
         finishedPlaying = false;
         }
public void Stop() { Pause(); frameTimer = 0f; Reset(); }
public void Play() { paused = false; finishedPlaying = false; }
public void Pause() { currentFrame--; paused = true; }
         private int framesAcross;
         private int framesDown;
         private double frameTimer;
         private Vector2 frameDimensions;
 #endregion
 /// <summary> Load SpriteSheet default settings
         /// </summary>
         /// <param name="Texture"></param> <param name="StartFrame"></param> <param name="EndFrame"></param>
         /// <param name="FramesAcross"></param> <param name="FramesDown"></param> <param name="FramesPerSecond"></param>
         public void Load(string Texture, int StartFrame, int EndFrame, int FramesAcross, int FramesDown, double FramesPerSecond)
         {
         texture = Game1.content.Load<Texture2D>(Texture);
         color = Color.White;
         startFrame = StartFrame;
         endFrame = EndFrame;
         framesAcross = FramesAcross;
         framesDown = FramesDown;
         frameDuration = 1 / FramesPerSecond;
         currentFrame = StartFrame;
         frameTimer = 0.0;
         frameDimensions = new Vector2(texture.Width / framesAcross, texture.Height  / framesDown);
         scale = 1.0f;
         rotation = 0.0f;
         rotationSpeed = 0.0f;
         spriteEffects = SpriteEffects.None;
         layerDepth = 0.5f;
         looped = true;
         paused = false;
         }
 /// <summary> Update Current Frame </summary>
         /// <param name="gameTime"> Update only when the Game  Engine says it's OK </param>
         public void Update(GameTime gameTime)
         {
         if (centerOfScreen)
         position = new Vector2(Game1.viewport.Width / 2, Game1.viewport.Height  / 2); // If true, Position Sprite in Center of Screen
 if (centered)
         origin = frameDimensions / 2; // Set the Sprite's Center relative to the Texture Segment
         UpdateFrame(gameTime);
         rotation += rotationSpeed; // Update rotation if rotationSpeed is greater  than 0.0
         }
         /// <summary> Update SpriteSheet Index </summary>
         /// <param name="gameTime"> Update when the game engine says so </param>
         public void UpdateFrame(GameTime gameTime)
         {
         if (paused)
         return;
 frameTimer += gameTime.ElapsedGameTime.TotalSeconds; // Add a tick to the Frame Duration Timer.
         if (frameTimer > frameDuration) // If frame has finished...
         {
         currentFrame++; // Increment to Next Frame.
         // Play the SpriteSheet Animation from startFrame to endFrame
         if ((currentFrame >= endFrame + 1) || (currentFrame < startFrame)) // Ensure that the index stays inside the SpriteSheet
         if (looped)
         {
         Reset();
         }
         else
         {
         finishedPlaying = true;
         Pause();
         }
 frameTimer -= frameDuration; // Reset Frame Duration Timer
         }
         }
         public void DrawFrame(SpriteBatch spriteBatch)
         {
         // If the number of total frames is more than the number of frames across  the texture, the texture has more than one row of frames. 
         // Calculate how many rows needed to wrap total number of frames in Index.
         // Store Division result as Int, which drops any decimals. Telling us how many full rows there are.
         int indexY = currentFrame / framesAcross;
         // Subtract number of complete rows * number of frames across texture,  from total index. 
         // The remainder tells us how many frames are left in incomplete row. Giving us the X coordinate of the current frame :)
         int indexX = currentFrame - (indexY * framesAcross);
 textureSegment = new Rectangle(
         indexX * (int)frameDimensions.X,
         indexY * (int)frameDimensions.Y,
         (int)frameDimensions.X,
         (int)frameDimensions.Y
         );
 spriteBatch.Draw(texture, position, textureSegment, color, rotation, origin, scale, spriteEffects, layerDepth);
         }
 public void Dispose()
         {
         texture.Dispose();
         }
         }
 }
       
March 05

C# Methods

There's a madness to my Method.

Let's say you have a whole group of code that you use pretty regularly, or more than once in the same program. C# has a method for storing batches of code in a container that you can call by name. When coming up with a name for this method, they decided to call it a Method. Maybe they could have come up with something a little more descriptive like, I don't know, "Thing" or something.
O.K. let's start with a simple batch of code:  Say you have to print your company's return address on everything; letterheads, envelopes, packaging for urinal cakes in the executive washroom, all that good stuff:

 

 // Print a bunch o' stuff to the screen 
using System ;
public class Whazzup
{
static void Main()
{
Console.WriteLine( "Izzie D. Goose" );
Console.WriteLine( "250 Redwood Shores Parkway" );
Console.WriteLine( "Redwood Shores, CA" );
Console.WriteLine ("94061" );
}
}

 

We'll put the block of code we want to print into a Method called "returnAddress" :

 

    static void returnAddress()
{
Console.WriteLine("Izzie D. Goose");
Console.WriteLine("250 Redwood Shores Parkway");
Console.WriteLine("Redwood Shores, CA");
Console.WriteLine("94061");
}

 

Now to execute the block of code, we simply call it by name thusly:

 

returnAddress() ;

 

like so:

 

 // Print a bunch o' stuff to the screen using a Method
using System ;
public class Whazzup
{
static void Main()
{
returnAddress() ; // We call the Method here
}
 static void returnAddress() // This is what get's called 
         {
         Console.WriteLine("Izzie D. Goose");
         Console.WriteLine("250 Redwood Shores Parkway");
         Console.WriteLine("Redwood Shores, CA");
         Console.WriteLine("94061");
         }
}
       

 

The above Method is specified as void because it doesn't return any values.
The Method being called can also return a value to the caller:

class MethodReturnsValue
{
static void Main()
{
System.Console.WriteLine( "The number of thy counting shall be: {0}", NumberOfThyCounting( ) );
}
 static int NumberOfThyCounting() // This Method Returns a Numerical Integer Value.
         {
         return 1 + 2; // Thy Method doth doeth something and returneth thy value, wherever fine methods are called. As thou doth see fit.
         }
 }
       

and foithermore, you can pass various types of values to the Method. Which can in turn, do something with them and return a value. 
In this example, I pass 2 numbers to a Method called Add, which simply adds the 2 numbers together and returns the sum:

 

class MethodParameters
{
         static void Main()
         {
         System.Console.WriteLine( "The Sum returned is: {0}", Add( 2, 3 ) ) ;  // Pass 2 values to the Method called Add, and print the result.
}
 static int Add( int Arg1, int Arg2 )  // Assign Temporary Variable names to the Arguments being passed to the Method.
         {
         return Arg1 + Arg2 ;  // Do someting with the Arguments being passed and send  a value back.
         }
 }
       

 

Since the Method returns a value, you can also use Operators to test the Method for various conditions, just as you would a Variable.

 

 if NumberOfThyCounting() > 3 
    { 
     Console.WriteLine( "That is way off!" );
     selfDestruct();
playHarps();

Console.WriteLine( " Have a nice day :) " ); }

 

Here's a Method you may find extremely useful for testing numeric values:

 

using System ;
class CheckNumber
{
static void Main()
{
Console.Write( " Please enter a number to check: " ); // Prompt the user for input.
int NumberToCheck = int.Parse(Console.ReadLine() ); // Store whatever user types in Numeric Variable.
 if ( ZeroOrNonZero( NumberToCheck ) == true ) // Send it down to the Number Checking Method for rigorous testing and quality assurance.
         {
         Console.WriteLine( " The number you have entered: {0} is, \n in all probability, a Zero or Non-Zero number. :) ", NumberToCheck );
         Console.WriteLine( " Way to go Einstein! " );
         }
         else if ( ZeroOrNonZero( NumberToCheck ) == false )
         {
         Console.WriteLine( " You have exceeded the improbability factor. " );
         }
     }
 static bool ZeroOrNonZero( int NumberToCheck ) // This Method Returns a Boolean Value. ( true or false )
         {
         if ( NumberToCheck == 0 || NumberToCheck > 0 || NumberToCheck < 0 ) // If test is true...
         return true; // return Boolean value
 else
         return false;
         }
 }
       

 

maybe not. Now, I know what you're thinking: a brilliant person such as yourself probably took one look at the above example and said "Hey! Why do I have to say If Boolean == false?? If it's not true, isn't it automatically assumed to be false?" Boy, nothing gets past you, does it? That is absolutely correct. Since a Boolean has only 2 possibilities; true or false, then if the first condition is not true, obviously it is automatically assumed to be false:

 

 if ( MyCoin == true ) // A Boolean has only 2 possibilities
         {
         Console.Write( " Heads, I win. " );
         }
         else
         {
         Console.Write( "  Tails, You Lose. " );
         }

 

Also, I confess. I was trying to be clever and slip another one past you. You might have noticed right away.
When using Booleans, it's not necessary to write
if ( BooleanValue == true )
one can simply write:
if ( BooleanValue )

:)