XNA 101 .Net

Learn how to program in C# while writing games in XNA Game Studio 3.0!
Our upcoming Silverlight book for beginners (includes a great chapter on game development in Silverlight!) Hello! Silverlight 2 with Dave Campbell, available online now!



Pages

Recent posts

Navigation

Archive

Blogroll

    Tampa Divorce Lawyer

    North of Tampa in Lutz, Florida. A Tampa Divorce Lawyer focusing on family, divorce, and real estate law.

    Disclaimer

    The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

    Lesson 10: Sprite Color

    Source code for this lesson completed: http://www.bluerosegames.com/xna101/lessons/XnaLesson10.zip

    So far, when drawing the sprites we've been using Color.White as the color to draw with. Color.White will preserve the original color of the sprite, but we can get some interesting effects by using other colors.

    In order to allow each BouncingBall sprite to have its own drawing color, let's add a DrawingColor Property to the BouncingBall class and an associated private field _drawingColor to store the color. The code will look something like this:

    private Color _drawingColor; 
     
    public Color DrawingColor
    {
       get { return _drawingColor; }
       set { _drawingColor = value; }
    } 
     

    In the BouncingBall constructor, add the following line to initialize the value in _drawingColor:

    _drawingColor = Color.White;

    So if we don't set the drawing color to something else, it will default to white.

    Now change the BouncingBall.Draw() method to use this color instead of Color.White. The method will now look like this:

    public void Draw(SpriteBatch spriteBatch)
    {
       spriteBatch.Draw(Texture, _position, _drawingColor);
    } 

    So again the Game1 class is simplified and more logic is put in the BouncingBall class. Now imagine that we have another sprite class that does something completely different than the BouncingBall class. We could still have the same Draw() and Update() methods, and call them exactly the same way from the Game1 class, and do two totally different things.

    So now if you run the program again, it does the same thing as always. Now for something completely different. Add the following image to your project by saving it to your computer and then right click on the Content folder in the solution and select "Add Existing Item" from the menu. It should be called white_ball.png.

    In the Game1.LoadContent() method,  change red_ball to white_ball. Then after the ball2.Velocity = new Vector2(10f, 5f);
    statement, add the following:

    ball2.DrawingColor = Color.Purple;

    Now if you run the program again, you should have a white ball and a purple ball.

    purple

    Colors can also be specified as a combination of Red, Green and Blue. Pretty much any color can be represented by the correct combination of red, green, and blue. So you can change the above line to:

    ball2.DrawingColor = new Color(255, 0, 255);

    Where the first argument is the amount of red the color will have, with 255 being the maximum and 0 being the minimum. The second argument is the amount of green for the color, and the last is the amount of blue. So this color will be full red, no green, and full blue. When referring to colors in computer programming, especially in web design, we often refer to the RGB value of a color (short for Red, Green Blue). Run the program again. The ball should now be a bright purple.

    Posted: Oct 18 2008, 12:45 by Bill Reiss | Comments (1) RSS comment feed |
    • Currently 5/5 Stars.
    • 1
    • 2
    • 3
    • 4
    • 5
    Filed under:

    Lesson 9: Using Properties

    Lesson 9 starts with the code as it was at the end of Lesson 8.

    Source code after the Lesson 9 changes: http://www.bluerosegames.com/xna101/lessons/XnaLesson9.zip 

    C# provides a nice alternative to accessing Fields directly from outside the class using something called Properties which are more like a method call, but look to other objects like public Fields.

    The benefits of Properties over direct access to Fields include but are not limited to:

    • Sanity checks, the object can check if a value is valid before it accepts the change. 
    • Ability to combine Field values to make things easier for the calling object.
    • The underlying structure of the data can be changed without requiring changes to the calling object.
    • Properties can be made read only or write only.
    • Easier to accommodate future needs of the class.

    There are also some negatives:

    • Fields inside value type properties are read only. You have to create a new copy of the entire value type (like Vector2) to set a new value. With fields, you can just say Position.X = 10, with properties you would have to do Position = new Vector2(10, Position.Y);
    • Properties cause a small performance hit. a bit more code has to run compared to accessing/setting a field.
    • They can make your code a bit more verbose impacting readability. 

    There are also some more advanced benefits having to do with packaging a class library as an assembly and maintaining compatibility across versions.

    For game programming, the use of properties can be a hotly debated topic, but Shawn Hargreaves who I highly respect falls on the side of using properties only when necessary. So consider this more of a "how to use properties" than a "you should always do this".

    In the case of the BouncingBall class, there are 2 public Fields that we will convert to Properties. Here is a sample property definition which can replace the previously public Field Position:

    private Vector2 _position;
     
    public Vector2 Position
    {
        get
        {
            return _position;
        }
        set
        {
            _position = value;
        }
    }

    Notice the "get" and "set" blocks. If you remove the "set" block, the property would be read only. Likewise, if you remove the "get" block, the property would be write only. Since _position is declared private, other objects will not be able to access the value of _position directly, only through the property Position. Go ahead and replace the declaration of Velocity as follows:

    private Vector2 _velocity;
     
    public Vector2 Velocity
    {
        get
        {
            return _velocity;
        }
        set
        {
            _velocity = value;
        }
    }

    In the "set" block, notice that there is a reference to a field named value. This is a special keyword that is used when setting a property and always contains the value that is being assigned to the property. It has the same data type as the property definition, or in this case, Vector2. So in the case of the BouncingBall class, if we had the following line in our Game1 class:

    ball2.Velocity = new Vector2(10, 5); 

    then in the Property setter for Velocity, "value" would contain a Vector2 object with X of 10 and Y of 5.

    In most classes, the methods of the class will probably deal directly with the private Fields instead of going through the property logic, although in some cases it will make sense to access the data through the Properties as well, if some of the same reasons listed above apply to these values. In the BouncingBall class, it probably makes sense to access the Fields directly from inside the class, so in the Update method and the constructor, change all references to the properties to the Field names instead.

    So change the BouncingBall.Update() method to use the private Fields instead of the public Properties:

    public void Update()
    {
       // TODO: Add the BouncingBall update logic here
       _position = _position + _velocity;
       if (_position.X < 0 || _position.X > GraphicsViewport.Width - Texture.Width)
       {
          // If we get in here, we've hit a vertical wall
          _velocity.X = -_velocity.X;
          _position.X = _position.X + Velocity.X;
       }
       if (_position.Y < 0 || _position.Y > GraphicsViewport.Height - Texture.Height)
       {
          // If we get in here, we've hit a horizontal wall
          _velocity.Y = -_velocity.Y;
          _position.Y = _position.Y + _velocity.Y;
       }
    } 

    So run the program again, and it should behave exactly as it did before the changes.

    So it's really up to you and up to the situation. Use Properties if they help you with whatever you're trying to accomplish. In most cases, you can change a Field to a Property later if you need to.

    Posted: Oct 18 2008, 11:17 by Bill Reiss | Comments (0) RSS comment feed |
    • Currently 5/5 Stars.
    • 1
    • 2
    • 3
    • 4
    • 5
    Filed under:

    Lesson 8: Double Trouble (Part 2)

    In this lesson we continue creating the BouncingBall class by moving the BouncingBall related logic into the class.

    This lesson picks up right where lesson 7 left off.

    Source code after completion of lesson 8: http://www.bluerosegames.com/xna101/lessons/XnaLesson8.zip

    In Part 1, we cleaned up our code a bit by creating a BouncingBall class and moving the BouncingBall related data into that class. The fancy term for this is encapsulating the data in a class. However, it usually isn't enough to just encapsulate the data, we also need to move the BouncingBall related logic into methods of the BouncingBall class. If you notice from Part 1, we cleaned up the declarations in the Game1 class (reducing 4 declarations to 1) but the Game1.Update() method actually got uglier.

    So in Part 2 we'll tackle the Update() method and clean it up.

    Following the model that XNA has implemented where XNA calls the Update method of the Game1 class to update positions, etc. we can do the same thing for the BouncingBall class. We will tell the BouncingBall objects to Update themselves.

    First define a new Update() method in the BouncingBall class. Inside the BouncingBall class block, add the following lines of code:

    public void Update()
    {
        // TODO: Add the BouncingBall update logic here
    }

    Then replace the // TODO line with all of the ball1 related code from the Game1.Update() method (so everything in the method except the first and last statements) and then remove the "ball1." prefix from everything in the new code. We won't need the "ball1." references any more because this code is now part of our BouncingBall class and it knows which copy of the data to access.

    Now the BouncingBall.Update() method should look like this:

    public void Update()
    {
       // TODO: Add the BouncingBall update logic here
       Position = Position + Velocity;
       if (Position.X < 0 || Position.X > graphics.GraphicsDevice.Viewport.Width - spriteTexture.Width)
       {
          // If we get in here, we've hit a vertical wall
          Velocity.X = -Velocity.X;
          Position.X = Position.X + Velocity.X;
       }
       if (Position.Y < 0 || Position.Y > graphics.GraphicsDevice.Viewport.Height - spriteTexture.Height)
       {
          // If we get in here, we've hit a horizontal wall
          Velocity.Y = -Velocity.Y;
          Position.Y = Position.Y + Velocity.Y;
       }
    } 

    Uh oh, there's a couple of problems. The spriteTexture object is declared in the Game1 object, and we can't access it from inside the BouncingBall class directly. There are a few ways to handle this, but in this case let's create static Fields in the BouncingBall class to store the sprite texture and the game Viewport. Static Fields are Fields that can be accessed by all objects of that type and can be accessed from outside the class by specifying the class name instead of an instance of the class. So after the "public Vector2 Velocity;" declaration at the top of the BouncingBall class definition, add the following:

    public static Texture2D Texture;
    public static Viewport GraphicsViewport; 

    In the BouncingBall.Update() method, change all references to spriteTexture to Texture, and graphics.GraphicsDevice.Viewport to GraphicsViewport. So now the BouncingBall.Update() method should look like this:

    public void Update()
    {
       // TODO: Add the BouncingBall update logic here
       Position = Position + Velocity;
       if (Position.X < 0 || Position.X > GraphicsViewport.Width - Texture.Width)
       {
          // If we get in here, we've hit a vertical wall
          Velocity.X = -Velocity.X;
          Position.X = Position.X + Velocity.X;
       }
       if (Position.Y < 0 || Position.Y > GraphicsViewport.Height - Texture.Height)
       {
          // If we get in here, we've hit a horizontal wall
          Velocity.Y = -Velocity.Y;
          Position.Y = Position.Y + Velocity.Y;
       }
    } 

    Now in the Game1 class, remove the spriteTexture definition from the class, since it will be stored in the static Texture Field in the BouncingBall class. Change the Game1.LoadContent() method to look like this:

    protected override void LoadContent()
    {
        // Create a new SpriteBatch, which can be used to draw textures.
        spriteBatch = new SpriteBatch(GraphicsDevice);
     
        // TODO: use this.Content to load your game content here
        BouncingBall.Texture = Content.Load<Texture2D>("red_ball");
        BouncingBall.GraphicsViewport = graphics.GraphicsDevice.Viewport;
     
    }

    Note the use of the BouncingBall class name to set the static fields.

    Inside the Game1.Update() method, we need to replace the code to update the ball's position with a call to the ball1 Update() method. So Game1.Update() should now look like this:

    protected override void Update(GameTime gameTime)
    {
       // Allows the default game to exit on Xbox 360 and Windows
       if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
          this.Exit();
       ball1.Update();
       base.Update(gameTime);
    } 

    Now add a BouncingBall.Draw() method as follows:

    public void Draw(SpriteBatch spriteBatch)
    {
       spriteBatch.Draw(Texture, Position, Color.White);
    } 

    and in the Game1.Draw() method, change the spriteBatch.Draw() statement to this:

    ball1.Draw(spriteBatch);

    This is MUCH cleaner. Notice how little code there is now in the Game1 class. It makes the code easier to understand, and it will also be easier to manitain your code and to make changes later. Run the program and see that it still behaves the way it was behaving before.

    Now for the second ball. EVERYWHERE in the Game1.cs file where there is a reference to ball1, copy the line and paste another line directly below the first, changing all "ball1"s to "ball2"s.

    Run the program again. What? No difference? This is because both balls are being drawn in exactly the same locations. They have the same x and y positions and velocities. So after we create the ball2 object, let's change some of its data. At the bottom of the Game1.Initialize() method, after the line

    ball2 = new BouncingBall(); 

    add the following:

    ball2.Velocity = new Vector2(10f, 5f); 

    Now the initial x velocity of ball2 will be 10, and the initial y velocity will be 5. Run the program again and you should see 2 balls bouncing around at different speeds.

    I hope that now you can see the power of creating and using classes in your program. Basically any time you find yourself copying the same code you should ask yourself if there is some way you can create a class to simplify things.

    Posted: Oct 17 2008, 05:05 by Bill Reiss | Comments (0) RSS comment feed |
    • Currently 5/5 Stars.
    • 1
    • 2
    • 3
    • 4
    • 5
    Filed under:

    XNA 3.0 to be released on October 30

    October 30 isn't that far off so now I'm really glad I decided to go straight to 3.0 while updating these posts.

    http://creators.xna.com/en-us/xna_goes_live_october30th

    Very exciting, and I hope to have at least one game ready for the Xbox Community Games when it goes live.

    Posted: Oct 15 2008, 02:40 by Bill Reiss | Comments (0) RSS comment feed |
    • Currently 0/5 Stars.
    • 1
    • 2
    • 3
    • 4
    • 5
    Filed under:

    Lesson 7: Double Trouble (Part 1)

    Lesson 7 deals with creating your own classes. By creating your own classes, you can make it a lot easier to reuse your code and simplify your program.

    Note: See my last post about lessons learned since the original post was written.

    This lesson picks up where Lesson 6 left off.

    After this lesson, your code should look something like this: http://www.bluerosegames.com/xna101/lessons/XnaLesson7.zip

    Great, so there's a ball bouncing around the screen. Now what if we wanted 2 balls bouncing around the screen? Well we could duplicate all of the code we did for the one ball, declaring new variables spriteLocation2 and spriteVelocity2, and duplicating all of the conditional logic. Then what happens if we want to have 3 bouncing balls? Or 10? That would be a lot of copying and pasting, and there's a good chance you could make a mistake somewhere along the line.

    If that isn't bad enough, then let's say we find a problem with the bouncing ball code, or we want the balls to behave differently. We would have to change that code in all 10 copies of the code.

    Luckily, there is a good answer to this problem. Using object oriented design, we can encapsulate all of the data and logic related to the bouncing ball in a class definition. We can then create as many of them as we want and just refer to the methods and properties of the objects created from that class definition to do the work.

    Naming Your Classes

    Give your classes descriptive names, and always capitalize the first letter of the class name. Also capitalize the first letter of each word in the class name, and if you have an acronym of 3 or more letters in the name, only capitalize the first letter of the acronym.

    Since this class is going to have the data and methods which control a bouncing ball, let's go out on a limb and call the class BouncingBall (I know, so original).

    Defining the BouncingBall Class

    It is good programming style to put each of your class definitions in a separate file. Do I sometimes put multiple class definitions in the same file? Yes, I admit it. Usually when I'm in a hurry and want to get something done quickly, but if things get too hairy I'll usually go back and split it up later.

    Fortunately for us, Microsoft Visual C# Express (and Visual Studio) have a built in wizard to help us define a class. 

    In the Solution Explorer, right click on MyFirstGame and select Add->New Item. You should see a dialog similar to the following:

    newclass

    Under Visual Studio installed templates, select Class. Enter BouncingBall.cs for the Name (all C# class files require the .cs file extension). Similar to how a new project and corresponding files were automatically generated for us earlier, in this case the BouncingBall class file is generated giving us a good starting point for coding our BouncingBall class. Since the class wizard doesn't really know about XNA, we need to add a couple of "using" statements to the beginning of the BouncingBall.cs file:

    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Graphics;

    As stated previously, classes are made up of Methods, Properties, and Fields. For now let's concentrate on Fields and Methods. Our Fields store the data associated with a particular class. Each instance of the class, or each object created from the class template, stores its own copy of the data. So what data do we have that should be associated with the ball object? In this case it's fairly straightforward. We have  the vector for the current x and y position of the ball, and the vector for the current x and y velocities.

    Inside the BouncingBall class's block (inside the curly braces just below the "class BouncingBall" statement in the BouncingBall.cs file) add the following:

    public Vector2 Position; 
    public Vector2 Velocity; 

    The keyword public before each of the Field declarations just tells C# that this data can be accessed by other objects in your program. If the keyword private was used instead, only methods of the object itself would be able to access the data. When Fields or methods are public, try to follow the standard C# naming conventions of capitalizing the first letter and then the first letter of each word.

    Now as discussed earlier, there is a special method called a constructor. It has the same name as the class, and is used to initialize the object, or assign the initial values to the data. Notice above that we didn't assign values to the Fields when we declared them.

    So again inside the BouncingBall class's block add the following:

    public BouncingBall() 
    { 
        Position = new Vector2(0f, 0f); 
        Velocity = new Vector2(1f, 1f); 
    }

    Now any time a new BouncingBall object is created, the initial values of its data will be 0 for the x and y position, and 1 for the x and y velocity.

    Now to change the Game1 class to use this new class.

    Remove the definitions in the Game1 class for spriteLocation and spriteVelocity. We will be using the Fields inside the BouncingBall object instead. Where those definitions were, add the following line declaring a BouncingBall object:

    BouncingBall ball1;

    In the Game1.Initialize() method, before the

    base.Initialize(); 

    statement, add the following line:

    ball1 = new BouncingBall();

    which creates a new BouncingBall object named ball1. When this statement executes, the BouncingBall constructor we defined earlier will execute, and so after this line of code, the data inside our ball1 object will be initialized.

    Now to change our Game1.Update() and Game1.Draw() methods to use the ball1 object.

    In the Game1.Update() method, change all "spriteLocation"s to ball1.Location and all "spriteVelocity"s to ball1.Velocity so that it looks as follows:

    protected override void Update(GameTime gameTime) 
    { 
       // Allows the default game to exit on Xbox 360 and Windows 
       if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) 
          this.Exit(); 
     
       // TODO: Add your update logic here 
       ball1.Position = ball1.Position + ball1.Velocity; 
       if (ball1.Position.X < 0 || ball1.Position.X > graphics.GraphicsDevice.Viewport.Width - spriteTexture.Width) 
       { 
          // If we get in here, we've hit a vertical wall 
          ball1.Velocity.X = -ball1.Velocity.X; 
          ball1.Position.X = ball1.Position.X + ball1.Velocity.X; 
       } 
       if (ball1.Position.Y < 0 || ball1.Position.Y > graphics.GraphicsDevice.Viewport.Height - spriteTexture.Height) 
       { 
          // If we get in here, we've hit a horizontal wall 
          ball1.Velocity.Y = -ball1.Velocity.Y; 
          ball1.Position.Y = ball1.Position.Y + ball1.Velocity.Y; 
       } 
       base.Update(gameTime); 
    } 
     

    Now in the Game1.Draw() method, change the x and y to ball1.X and ball1.Y so that the spriteBatch.Draw statement looks as follows:

    spriteBatch.Draw(spriteTexture, ball1.Position, Color.White);

    If you run the program again you'll see that it behaves just like it did before these changes. Not that exciting yet, but in part 2 of "Double Trouble", we'll tackle moving the Update logic into the BouncingBall class, and then show how this makes drawing 2 or more balls much easier.