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 (9) 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 (2) 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 (2) 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.Position 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.

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

    Lessons learned since the first time around (XNA and Model-View)

    I've been struggling with the next few posts since if I had it to do again, I'd probably do it differently. There has been a lot of buzz about Model-View-Controller (MVC) patterns. Model-View-ViewModel (M-V-VM) is also gaining ground, and is a recommended pattern for WPF and Silverlight applications. Now I'm not a big Test Driven Development guy, but there are definitely some benefits to these Model-View patterns. They may take a bit longer up front and cause some more design work, but your code will generally be more reusable and you'll have a better separation of display logic and back end logic.

    For writing games, should I care? Isn't game development more of a GED (Git 'er done) design pattern? It depends. For me personally, porting my Dr. Popper game from XNA to Silverlight was a pretty painful process and pretty much a complete rewrite. Why? Because the way things are displayed on the screen is completely different in Silverlight. In XNA, you draw everything, every frame. In Silverlight, you place something on the screen and forget it until you need to move it or remove it.

    By implementing one of the design patterns above, you can separate the drawing logic from the rest of the game logic and make it much easier to run your game on multiple platforms.

    On the other hand, using these concepts can be a more advanced development style, and introducing those concepts at this part of the tutorial series is probably a mistake. So what I've decided is to continue on the original path of the tutorials, and after covering some of the basics of classes, objects, and collections, I'll show how we can refactor the code to be more Model-View based.

    Model-View designs, like any other technique, are just another tool you can use to create your applications, and in my opinion there are cases where it makes sense and others where it doesn't, and we probably will implement the parts of it that make sense for this, but I won't claim that it's 100% conforming to the doctrine.

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

    Ziggyware XNA Article contest, win an Xbox!

    For those of you that don't already know (which is probably nobody), XNA MVP Ziggy runs one of the best XNA sites around at http://www.ziggyware.com. Chock full of tutorials, news, and forums, you can find pretty much anything XNA related there.

    From time to time, Ziggy will run a contest on his site, and he has just started a new one.

    ziggyware

    Submit an XNA related article by November 30 and you could win an Xbox 360 Elite with a year's subscription to the XNA Creators Club (which would give you a great jump on creating the next great Xbox Community Game (or you can just play everyone else's before they are available). Second place is the Creator's Club subscription without the Xbox.

    They say the best way to learn something is to teach it, but I also thing that while learning something you have a great perspective on what it takes to learn it, and you can offer advice that an expert in the technology may gloss over, so even if you're just learning XNA you can write a great article.

     

    So get going, the details are here: http://www.ziggyware.com/news.php?readmore=905

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

    Lesson 6: Follow the Bouncing Ball

    This lesson introduces conditional logic and vector math by adding code to check whether the ball hits a wall and changing its velocity based on the collision.

    This lesson starts off with the code as it is at the end of lesson 5.

    At the end of this lesson, your code should look something like this:

    http://www.bluerosegames.com/xna101/lessons/XnaLesson6.zip

    Now that the ball is moving, let's say we want to make it reverse direction when it hits the edges of the window. To do this, we will need to mimic the physics of objects bouncing off of a surface. Ignoring the energy lost as the ball bounces, a simple model for this is to keep the velocity parallel to the surface the same, and reverse the velocity perpendicular to the surface. Since our boundaries are parallel to the x and y axis, we simply need to reverse either the x velocity or the y velocity when the ball hits a wall.

    So we need to add code for the following behaviors:

    1. Detect that a wall collision has taken place.
    2. Reverse the x or y velocity appropriately.

    In lesson 5 the x and y velocity were constants. These need to be changed to variables, just like the x and y positions were made variables in the last lesson.

    Declare and initialize a Vector2 object at the top of the class just like spriteLocation was declared previously. The new line of code will look as follows:

    Vector2 spriteVelocity = new Vector2(1f, 1f);

    This sets the initial values of the x and y velocity to the same values as previously, just now they are variables and can be changed while the program is running.

    Now in the Game1.Update() method, change

    spriteLocation.X = spriteLocation.X + 1;
    spriteLocation.Y = spriteLocation.Y + 1; 

    to

    spriteLocation = spriteLocation + spriteVelocity;

    This may look a little strange, since we don't explicity refer to X and Y. Since spriteLocation and spriteVelocity are both of type Vector2, he can be added together and the Vector2 objects know that to add two Vector2 objects together, you need to add their X values together and their Y values together.

    Now immediately after those lines of code, we need to check for a collision with the walls. In order to do this, we need to use what is called a conditional statement. A conditional statement uses boolean logic (true or false) to determine whether a block of code should be executed. In C#, conditional statements use the if keyword.

    So what are the conditions we need to check for to see if we've hit a wall? Well there are 4 walls, so there are 4 conditions. For the purposes of this program, we will actually check to see if the ball has intersected with the wall, which makes the calculations a bit easier. So the conditions are as follows:

    1. x < 0
    2. y < 0
    3. x > width of the window - width of the ball
    4. y > height of the window - height of the ball

    For the third and fourth conditions, we need to take into account the size of the ball since x and y actually represent the top left corner of the bounding box that contains the ball.

    For each of the above conditions, we need to take the following actions respectively:

    1. Reverse the x velocity and add the new x velocity to the x position to get the ball out from inside the wall
    2. Reverse the y velocity and add the new y velocity to the y position to get the ball out from inside the wall
    3. Same as 1
    4. Same as 2

    Since 1 and 3 require the same action, and 2 and 4 require the same action, we can group the 4 conditions into 2 conditional statements. Writing these as code looks as follows:

    if (spriteLocation.X < 0 || spriteLocation.X > graphics.GraphicsDevice.Viewport.Width - spriteTexture.Width)
    {
       // If we get in here, we've hit a vertical wall
       spriteVelocity.X = -spriteVelocity.X;
       spriteLocation.X = spriteLocation.X + spriteVelocity.X;
    }
    if (spriteLocation.Y < 0 || spriteLocation.Y > graphics.GraphicsDevice.Viewport.Height - spriteTexture.Height)
    {
       // If we get in here, we've hit a horizontal wall
       spriteVelocity.Y = -spriteVelocity.Y;
       spriteLocation.Y = spriteLocation.Y + spriteVelocity.Y;
    } 

    The code in the block (between the curly braces) is only run if the conditional statement directly before it evaluates to true. the || characters mean "or" so in the case of the first "if" statement, it will be true if either spriteLocation.X is less than zero, or spriteLocation.X is greater than the width of the game surface minus the width of the ball. If the || characters were replaced with && characters, that would mean "and", and spriteLocation.X would have to be both less than zero and greater than the width of the game surface minus the width of the ball.

    Run the program and you will see the ball bouncing around the screen. Change the initialization of spriteVelocity changing the X and Y values and see what happens. I would suggest different combinations of 0, 5, and 10 for the x and y velocity values.

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

    Lesson 5: Bust a Move

    This lesson focuses on local variables and class-level variables. Class-level variables are also known as Fields. This lesson also shows how to update Fields in the Update method.

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

    For this lesson, start with the MyFirstGame project code from after Lesson 3. This means that if you want to use the code as it was after Lesson 4, delete the code which was added to show the second sprite. The Game1.Draw() method should look like this to start:

    protected override void Draw(GameTime gameTime)
    {
       graphics.GraphicsDevice.Clear(Color.Black); 
     
       // TODO: Add your drawing code here
       spriteBatch.Begin();
       spriteBatch.Draw(spriteTexture, new Vector2(0f, 0f), Color.White);
       spriteBatch.End();
       base.Draw(gameTime);
    } 

    What if we want to draw the sprite somewhere else? Well we could change the Vector2(0f, 0f) to Vector2(100f, 100f) for example, and this may be fine for a sprite that isn't going to move, but for a moving sprite things need to be more dynamic. The 0f values in the above code are floating point constants (the "f" after the number indicated that it is a floating point number). Floating point numbers are numbers that contain a decimal point, and the approximate range of a floating point number in C# is -3.4E38 to 3.4E38 where E stands for "times 10 to the Nth power". We can replace the Vector2 constant with a Vector2 variable. A variable is a named piece of data of a particular data type. To use a variable, first we have to declare it. So before the spriteBatch.Draw() method call, let's declare a Vector2 variable. Add the following line before the spriteBatch.Draw() call:

    Vector2 spriteLocation = new Vector2(0f, 0f);

    This gives us a variable named spriteLocation with values of 0f for X, and 0f for Y. In this case we are initializing the spriteLocation variable in the same line of code in which we declare it. Variables can be initialized as part of the declaration, or can be initialized later. All variables must be initialized before they are used for the first time.

    Now replace the Vector2 constant in the spriteBatch.Draw() call with the spriteLocation variable, as follows:

    spriteBatch.Draw(spriteTexture, spriteLocation, Color.White);

    Now if you run the program, you should get the same result as before, since spriteLocation has the same values that the Vector2 constant had.

    Now change the line where spriteLocation was declared to the following:

    Vector2 spriteLocation = new Vector2(100f, 0f);

    and run the program again. You will see that the ball is now shifted over.

    Since this variable are declared inside a method block, they are local to the method. This means that every time the Draw() method is called, this variable is re-declared and re-initialized, so there is no way for our code to remember the previous values and assign different values to the variable. To fix this, variables can be declared at the class level. Just like we did before in Lesson 3 with the spriteBatch and spriteTexture objects, we can declare spriteLocation at the class level and then it will be available to all methods in the Game1 object for the life of the object. The variable will be initialized once when the object is created and will keep that value until changed.

    So move the spriteLocation declaration (make sure you remove it from the Draw method!) to immediately after the

    Texture2D spriteTexture; 

    line at the top of the class. So it should now look like this:

    Texture2D spriteTexture;
    Vector2 spriteLocation = new Vector2(0f, 0f);

    And now add the following lines to the Game1.Update() method immediately after the

    // TODO: Add your update logic here

    comment:

    spriteLocation.X = spriteLocation.X + 1f;
    spriteLocation.Y = spriteLocation.Y + 1f; 

    Now every time the Update method is called, the X value in the spriteLocation object will be set to the value of the current level of X plus 1 and the same goes for Y. Now run the code again. The ball should move slowly diagonally and eventually off the screen.

    Notice how the code to change the position of the sprite is in the Game1.Update() method and only the code directly related to drawing the sprite is in the Game1.Draw() method. This is how we will proceed going forward. Keeping the positioning and the drawing code separate will be important as things get more complicated.

    Try playing around with the 2 lines that we added to the Update() method and instead of adding 1 each time, try some other values and see what happens.

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

    Lesson 4: The More the Merrier

    In this short lesson we'll look at drawing more than one sprite on the screen.

    Project code for this lesson:

    http://www.bluerosegames.com/xna101/lessons/XnaLesson4.zip

    We can use the same texture to draw more than one sprite. All we need to do is to add another SpriteBatch.Draw() method call specifying the same texture object as the first argument to the method.

    In our program from Lesson 3, go to the Draw() method of Game1 and find the following line:

    spriteBatch.Draw(spriteTexture, new Vector2(0f, 0f), Color.White); 

    Add another copy of this line of code directly after the first one, then change the (0f, 0f) to (175f, 175f) so that the code now looks like this:

    spriteBatch.Draw(spriteTexture, new Vector2(0f, 0f), Color.White);
    spriteBatch.Draw(spriteTexture, new Vector2(175f, 175f), Color.White);

    Now run the program, and you should see something like this:

    Simple as that. This can be repeated for as many sprites as you want. You can also define and load more Texture2D objects and have sprites that are different images.

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