Showing posts with label spritebatch. Show all posts
Showing posts with label spritebatch. Show all posts

Thursday, June 23, 2011

XNA Game Design: Thinking Abstractly

The second part of this guide will focus on making two abstract classes to better handle certain aspects of our game. The first will involve creating a class that will better handle image drawing and holding related bitmap data (such as position, rotation, reflection, etc.). The second will use our improved sprites to create a standardized game window that will contain elements such as text, sprites, and selectable choices.

The reason this section is called thinking abstractly is because it will focus intently on elements of polymorphism and inheritance through the use of abstract classes.

To refresh your memory, an abstract class uses the abstract keyword and cannot have instances made of it. Simply put, it acts as a parent class perfect to hold the messier, often untouched variables used by it's child classes.


The Grandpa isn't dead, he's just abstract.
When thinking back to our biggest unsolved problem, we still have the spriteBatch lingering around our SCENE.Draw() method. At the moment, all image drawing must be called from the spritebatch.Draw() method. This makes for horrible looking code because all the methods are directed from the spriteBatch.

  • spriteBatch.Draw(Player.Texture2D, Player.Vector2, Player.Color...)
  • spriteBatch.Draw(Enemy.Texture2D, Enemy.Vector2, Enemy.Color...)
  • spriteBatch.Draw(PowerUp.Texture2D, PowerUp.Vector2, PowerUp.Color...)
  • //This repetitive code is boring!

Every line would be that repetitive. The less code we have to write, the better. So the first part of Abstraction will focus on creating a set of classes to let us instead say;
  • Player.Sprite.Draw(spriteBatch);
  • Enemy.Sprite.Draw(spriteBatch);
  • PowerUp.Sprite.Draw(spriteBatch);
  • //Easy like strawberry daiquiris in Tahiti!

The second part will focus on making a standardized game window, which is just a background with borders and organized elements. While every game does this visual aspect differently, It's inclusion is videogames is so ubiquitous it honestly deserves it's own focus. If you don't believe me, just see for your self. Menus, text boxes and selectable choices are so common in video games, and they're all composed of related objects. As such, it makes perfect sense to tackle them early on. By the end of this chapter, you should have the perfect framework to make and menu system or options screen your game would need (boring, yeah, but it'll make those parts of the game seem like a piece of cake).

Friday, June 3, 2011

XNA Game Design: Mouse Input (part 2)

I told you Mouse Input would be a bit more difficult.


In order to create the aforementioned method necessary to determine whether our mouse cursor is outside the confines of the game window, we need to know the dimensions of the game window. At a later point in time we will be setting these values to tangible variables so different game resolutions can be offered. In the meantime however, we actually need a value to work with.


In the Game1 class, create two new static variables. Name them whatever you want, as we will be doing away with them later. Recognize however that they will be representing our game window's width and height.
        public static readonly int wWIDTH = 640;
        public static readonly int wHEIGHT = 480;
Now, at the end of the constructor, add the following two lines.

        graphics.PreferredBackBufferHeight = wHEIGHT;
        graphics.PreferredBackBufferWidth = wWIDTH;
This essentially sets the game window to the specified dimensions. Again, the reason we want to use variables (for now) is to ensure that we have a mutable constant to refer to. Many aspects of the game will need to get the game window's width and height, and only a few will ever actually change it. An in-game change of the game window dimensions is a complex process, and for now we don't intend to ever change these dimensions (especially considering the variables we are using are only temporary). That is why we are setting their protection level to readonly.


Because wWIDTH and wHEIGHT now contain the maximum window dimensions, we can create the method for our cursor class to fix the game window mouse coordinates. This method should do the following:
  • If the Mouse.X coordinate is less than zero, the Cursor.X coordinate is set to zero.
  • If the Mouse.Y coordinate is less than zero, the Cursor.Y coordinate is set to zero.
  • If the Mouse.X coordinate is greater than the window width, the Cursor.X coordinate is set to the window width.
  • If the Mouse.Y coordinate is greater than the window height, the Cursor.Y coordinate is set to the window height.
Alright, let's get through this awful pitfall.


        private static void fix_bounds()
        {
            if (Pos.X < 0)
                Pos.X = 0;
            if (Pos.Y < 0)
                Pos.Y = 0;
            if (Pos.X > Game1.wWIDTH)
                Pos.X = Game1.wWIDTH;
            if (Pos.Y > Game1.wHEIGHT)
                Pos.Y = Game1.wHEIGHT;
        }
It's taking longer for me to explain why we need the code than to actually show it.

Stick the fix_bounds()method just at the end of our Cursor.Update(). Then let's return to our Game1class to start implementing our code.

At the end of the Game1.Update() method, add the following two lines.
            Input.Update();
            Cursor.Update();
And where the Game1.Draw() method designates code be added, append the following:
            // TODO: Add your drawing code here
            spriteBatch.Begin();
            Cursor.Draw(spriteBatch);
            spriteBatch.End();
Effectively, our game now has a practical understanding of keyboard and mouse input that updates whenever the game updates. Still, we don't have a custom mouse graphic, and the call to Cursor.Draw is effectively moot considering it currently contains no code. Our Input class is now effectively operational.

And just what is going on with the spritebatch? Why did we add those two extra lines of code? What are they meant to do?

In our next lesson, these questions will all be answered, and you'll learn why the SpriteBatch and ContentManager classes are two of the most frustrating aspects of XNA 4.0 to work with, and we will begin to segue into working around them.


Yesterdays Homework Solution: There are two effective ways of determining whether our cursor is within the bounds of a rectangle object. The first involves comparing the X and Y properties of Cursor.Pos to the bounds of the rectangle, and the second involves creating a Point object and using the Rectangle.Contains() method.


//Comparing the float coordinates to the rectangle coordinates
public static bool in_rectangle(Rectangle r)
{
    if ((Pos.X > r.X) && (Pos.X < r.X + r.Width) 
    && (Pos.Y > r.Y) && (Pos.Y < r.Y + r.Height))
    {
        return true;
    }
    else return false;
}


//Using Rectangle.Contains()
public static bool in_rectangle(Rectangle r)
{
    Point p = new Point(State.X, State.Y);
    return r.Contains(p);
}

I would recommended casting to a point, as it is effectively less lines of code, but both methods get the job done.

Homework: Find out how to import assets into your game. Add three folders into your Content folder labeled Audio, Graphics and Data.