This article focuses on the following concepts:
- Using the Content Pipeline to load textures from disk
- Creating classes to divide code into logical units
- Recursively evaluating the status of the game board to check for scoring chains
- Drawing textures using the SpriteBatch.Draw() method
- Managing simple game states
It was just another day at the bottom of the ocean until an explosion in one of the storage bays cracked the protective dome around Deep Sea Research Lab Alpha. Now the entire place is flooding, and the emergency pump system is a chaotic jumble of loose parts.
Designing a puzzle game
The Puzzler has always been a popular game genre. From old standbys like Tetris to modern crazes like Bejeweled, puzzle games are attractive to players because they do not require a long-term time investment or a steep learning curve.
The game mechanic is the heart of any good puzzle game. This mechanic is usually very simple, with perhaps a few twists to keep the players on their toes.
In Flood Control, the player will be faced with a board containing 80 pieces of pipe. Some will be straight pipes and some will be curved. The objective of the game is to rotate the pipes to form a continuous line to pump water from the left side of the board to the right side of the board.
Completing a section of pipe drains water out of the base and scores points for the player, but destroys the pipes used. New pipes will fall into place for the player to begin another row.
Time for action - set up the Flood Control project
What just happened?
You have now set up a workspace for building Flood Control, and created a couple of folders for organizing game content. You have also imported the sample graphics for the Flood Control game into the project.
Introducing the Content Pipeline
The Flood ControlContent (Content) project inside Solution Explorer is a special kind of project called a Content Project. Items in your game's content project are converted into .XNB resource files by Content Importers and Content Processors.
If you right-click on one of the image files you just added to the Flood Control project and select Properties, you will see that for both the Importer and Processor, the Content Pipeline will use Texture - XNA Framework. This means that the Importer will take the file in its native format (.PNG in this case) and convert it to a format that the Processor recognizes as an image. The Processor then converts the image into an .XNB file which is a compressed binary format that XNA's content manager can read directly into a Texture2D object.
There are Content Importer/Processor pairs for several different types of content--images, audio, video, fonts, 3D models, and shader language effects files. All of these content types get converted to .XNB files which can be used at runtime.
In order to see how to use the Content Pipeline at runtime, let's go ahead and write the code to read these textures into memory when the game starts:
Time for action - reading textures into memory
- Double-click on Game1.cs in Solution Explorer to open it or bring it to the front if it is already open.
- In the Class Declarations area of Game1 (right below SpriteBatch spriteBatch;), add:
Texture2D playingPieces;
Texture2D backgroundScreen;
Texture2D titleScreen;
- Add code to load each of the Texture2D objects at the end of LoadContent():
playingPieces = Content.Load(@"Textures\Tile_Sheet");
backgroundScreen =
Content.Load(@"Textures\Background");
titleScreen = Content.Load(@"Textures\TitleScreen");
What just happened?
In order to load the textures from disk, you need an in-memory object to hold them. These are declared as instances of the Texture2D class.
A default XNA project sets up the Content instance of the ContentManager class for you automatically. The Content object's Load() method is used to read .XNB files from disk and into the Texture2D instances declared earlier.
One thing to note here is that the Load() method requires a type identifier, specified in angled brackets (), before the parameter list. Known in C# as a "Generic", many classes and methods support this kind of type specification to allow code to operate on a variety of data types. We will make more extensive use of Generics later when we need to store lists of objects in memory. The Load() method is used not only for textures, but also for all other kinds of content (sounds, 3D models, fonts, etc.) as well. It is important to let the Load() method know what kind of data you are reading so that it knows what kind of object to return.
Sprites and sprite sheets
As far as XNA and the SpriteBatch class are concerned, a sprite is a 2D bitmapped image that can be drawn either with or without transparency information to the screen.
[indent=1]Sprites vs. Textures
XNA defines a "sprite" as a 2D bitmap that is drawn directly to the screen. While these bitmaps are stored in Texture2D objects, the term "texture" is used when a 2D image is mapped onto a 3D object, providing a visual representation of the surface of the object. In practice, all XNA graphics are actually performed in 3D, with 2D sprites being rendered via special configurations of the XNA rendering engine. - Double-click on Game1.cs in Solution Explorer to open it or bring it to the front if it is already open.