Archive for the ‘Codesamples’ Category

XNA Arcade with dynamically loaded games

Sunday, October 7th, 2012

This is a post inspired by a question asked at the XNA forums.

"I am planning to write an application for Windows with different modules. There should be a basic version and different addons which should extend this basic version. Imagine it as a collection of games. You'll have the basic pack with 5 games and should be able to extend it with more games.
Can this be realized with XNA?"

The answer is YES! Smiley  ...let's code it!

image

(If you'd rather download the code and figure it out on your own, the complete code is here)

What we are going to make

- a gamecenter which is the visual interface for loading and playing small games
- the functionality required to dynamically present all the games that come with the gamecenter
- functionality to load compatible games from DLLs in subfolders of the gamecenter

Before we begin

What we want here is to have something (a small game) behave differently depending on which game it is - but we should be able to load them all in the same way.
So our coder-mindset says: "Different things which should appear alike in code - AHA, WE NEED AN INTERFACE!!". Next our coder-mindset says "...but wait - we can probably implement some of the code in a superclass, to avoid having to code everthing again whenever we make a new game - AHA, WE CAN MAKE AN ABSTRACT SUPERCLASS!!! Smiley med åben mund Basically, an abstract class is a class which you can't "new up" (instantiate) and it is often used to write code to reuse in subclasses.

What we will need

The small games will need access to the GraphicsManager, a SpriteBatch, the ContentManager, and a reference to the Game class which is currently running, plus a couple of other things, for one thing a SpriteFont for ease of coding. The Update and Draw methods must be implemented differently in each game, so these methods are not coded in the abstract class (which is the reason it is abstract Smiley, der blinker).

Finally, we will add an Initialize method to store necessary variables. This Initialize method should then be called by the main Game when the minigame is ready to play.

The AbstractGame class

/// <summary>
/// This class is the basis for all the games that can be loaded in the main game
/// You have to implement Draw and Update like in a normal Game class.
/// Abstract means it isn't finished yet, and can't be "new'ed up"
/// </summary>
public abstract class AbstractGame  
{
    //helperproperties, to store stuff you need to make a game
    public GraphicsDeviceManager GraphicsDeviceManager { get; protected set; }
    public GraphicsDevice Graphics { get; protected set; }
    public SpriteBatch SpriteBatch { get; protected set; }
    public ContentManager Content { get; protected set; }
    public Game Game { get; protected set; }
    public SpriteFont Font { get; protected set; }
    public bool GameOver { get; protected set; }

    //initializes a new game
    public void Initialize(Game game, GraphicsDeviceManager manager, SpriteBatch batch)
    {
        this.GraphicsDeviceManager = manager;
        this.Graphics = game.GraphicsDevice;
        this.SpriteBatch = batch;
        this.Content = game.Content;
        Font = Content.Load<SpriteFont>("DefaultFont");
    }

    //these methods must be implemented by your game
    public abstract void Draw(GameTime gameTime);
    public abstract void Update(GameTime gameTime);

}

Note - I've used the DisplayName attribute on the subclasses to be able to add a name to display for a minigame. I could have used a property, but then I would have to create a constructor on each minigame which set the variable. I thought this was cleaner Smiley

A concrete minigame implementation sample

[DisplayName("Tic-Tac-Toe, a classic for all ages")]
public class TicTacToeGame : AbstractGame
{
    public override void Draw(GameTime gameTime)
    {
        Graphics.Clear(Color.Yellow);
        SpriteBatch.Begin();
        SpriteBatch.DrawString(Font, "Tic-tac-toe - Q to quit", Vector2.One * 200, Color.Black);
        SpriteBatch.End();
    }

    public override void Update(GameTime gameTime)
    {
        GameOver = Keyboard.GetState().IsKeyDown(Keys.Q);
    }
}

In your Game class, make a variable of this type

AbstractGame _currentGame;

In your main game's Update and Draw methods you check whether the _currentGame variable is null. If it is you present a game selection screen where a user can select the possible games.

When a game is selected, you instantiate a concrete implementation (subclass) of the AbstractClass (Pong/Pacman/etc.), assign it the variables it needs and set the _currentGame to this.

//if game was selected (in this case Pong)
AbstractGame game = new PongGame();
game.Initialize(this, graphics, spriteBatch);
_currentGame = game;

In your main game's Update and Draw you call the Update and Draw of the game the player has chosen.

protected override void Update(GameTime gameTime) 
{ 
    //if we're playing a specific game 
    if (_currentGame != null) 
    { 
        //...call the update method of the game being played 
        _currentGame.Update(gameTime); 
    } 
    else 
    { 
        //take input in gameselectionmenu 
        //... 
 
        //if game was selected (in this case Pong): 
        AbstractGame game = new PongGame(); 
        game.Initialize(this, graphics, spriteBatch); 
        _currentGame = game; 
    } 
 
    base.Update(gameTime); 
} 
 
protected override void Draw(GameTime gameTime) 
{ 
    //if we're playing a specific game 
    if (_currentGame != null) 
    { 
        //...call the update method of the game being played 
        _currentGame.Draw(gameTime); 
    } 
    else 
    { 
        //draw gameselection menu 
    } 
 
    base.Draw(gameTime); 
}

The GamesPackManager class

This class will inspect EXE files or DLL files (popularly named Assemblies in .net) and return a list of all the subclasses of AbstractGame in them.
In the sample code (download link at the bottom of this post) I've created a project "GamePackExtension" (Windows Game Library), with ChessGame and ShooterGame, both of which inherit from AbstractGame. The DLL from this project I have then copied manually to a subfolder in the main project's BIN/x86/DEBUG folder where it can be discovered by the GamesPackManager.

/// <summary>
/// This class makes it easier to load AbstractGame subclass types from DLLs 
/// </summary>
public class GamesPackManager
{
    //Get all the AbstractGame subclasses from an assembly
    public List<Type> GetGames(Assembly assemblyToExplore)
    {
        return assemblyToExplore.GetExportedTypes().Where(aType => aType.IsSubclassOf(typeof(AbstractGame))).ToList();
    }

    //find the AbstractGame subclasses from DLLs in all the running game's subfolders
    public List<Type> GetGamesFromRunningGamesSubfolders()
    {
        //find out where the currently running game (the EXE) is located
        FileInfo gameExe = new FileInfo(Assembly.GetExecutingAssembly().Location);
            
        //get info about the containing folder
        DirectoryInfo executingGameDir = new DirectoryInfo( gameExe.DirectoryName);
            
        //find all *.DLL files in all subfolders of the game
        FileInfo[] dlls = executingGameDir.GetFiles("*.dll", SearchOption.AllDirectories);
            
        //make a list to hold all the games
        List<Type> listOfGameTypes = new List<Type>();

        //iterate through all DLL files and add the assemblies
        foreach (var item in dlls)
        {
            //load the assembly
            Assembly a = Assembly.LoadFrom(item.FullName);
            //get the games of the correct type
            listOfGameTypes.AddRange(GetGames(a));
        }

        return listOfGameTypes;
    }
}

Class diagram

classdiagram

What else is in the code

- code to select a game by using the arrow and ENTER keys
- code to primitively highlight a menuitem by blinking, based on the time
Here's a small demo to show you what's going on in the democode.

I hope this is of use to you :)

download code Complete code

Simple drag and drop with snap-to-tiles in XNA

Saturday, July 14th, 2012

If you need to create a tile-based editor, or for some other reason need to show selected tiles based on the mouseposition – here’s some code to help you do that Smile.

The most basic part of the code is figuring out what tile you are over by doing an integer division using the tile size. Let’s say your mouse is at (x=432,y=197) and each tile is 64x64 pixels. Which square is the mouse over?

well 432 / 64 = 6.75, but if this is done using two integers (int in C#), the decimal part is removed and we’re left with 6. The same with the y-part 197 / 64 = 3.078125 which is  3 without the decimal part.

Often however, you don’t want the map to start in the upper lefthand corner of the screen, so we need to subtract the position of the map from the coordinates.

This gives us something like this:

calculation

… where you subtract the top and left from the mouse’s coordinates before doing the integer division to find the square’s coordinates.

Here's the code above as a method which given the coordinates of the mouse, returns the row and column in the map:

//get the column/row on the board for a given coordinate
Vector2 GetSquareFromPosition(Vector2 position)
{
    //adjust for the boards offset (_boardPosition) and do an integerdivision
    return new Vector2(
    (int)(_mousePosition.X - _boardPosition.X) / _tileSize,
    (int)(_mousePosition.Y - _boardPosition.Y) / _tileSize);
}

Another noteworthy codesample

Making a “chessboard” out of the same Texture2D by alternating based on whether the column + row of a square is even or odd (by using the modulus “%” operator).

The modulus operator gives what is left after an integer division, so if you take an even number modulo 2 the remainder is zero, the remainder of an odd number modulo 2 is one.

float opacity = 1f;

//if we add the x and y value of the tile
//and it is even, we make it one third opaque
if ((x + y) % 2 == 0)
{
    opacity = .33f;
}
else
{
    //otherwise it is one tenth opaque
    opacity = .1f;
}

//draw the white square at the given position,
//offset by the x- and y-offset, in the opacity desired
spriteBatch.Draw(_whiteSquare, squareToDrawPosition, Color.White * opacity);

You can find the code here

Maze creation in C#

Saturday, March 17th, 2012

maze_19x19

A small maze generator for use in .net.

I am currently in the process of learning how to code 3D graphics in XNA 4.0.  It’s a lot of fun – and I’ve gotten pretty far with just boxes covered by different textures. However I thought that it would be fun to have a small mazegame – where you’re running around as a bewildered labrat inside the maze. For that I would need to have a random maze generated each time.
So I Googled around, found some tips, and coded a mazegenerator.

After that I took the time to comment the code  and wrap it up. So if you don’t care about the inner workings, you can just add a reference to my DLL and get mazes like this:

//get a MazeCreator ready to make 9x9 mazes that start at 1,1
MazeCreator creator = new MazeCreator(9, 9, new Point(1, 1));
byte[,] maze1 = creator.CreateMaze();
byte[,] maze2 = creator.CreateMaze();
byte[,] maze3 = creator.CreateMaze();

Update - thanks to the anonymous commenter below, you can now get the point in the maze furthest from the starting point:)

If you want to know where the position in the maze that is furthest from the starting point is, you can ask the MazeCreator object after you have created the maze:

//get a MazeCreator ready to make 9x9 mazes that start at 1,1
MazeCreator creator = new MazeCreator(9, 9, new Point(1, 1));
byte[,] maze1 = creator.CreateMaze();
Point furthestPosition = creator.FurthestPoint;

Basics of maze creation

The basic algorithm of creating a maze is as follows (pseudocode)

Start at a valid starting point in the maze - then:
as long as there are still tiles to try
{
  excavate the square we are on
  get all valid neighbors for the curent tile
  if there are any interesting looking neighbors to branch off to(*)
  {
    remember the current tile, by putting it in a list of potential branch-offs (stack)
    move on to a random of the neighboring tiles
  }
  else
  {
    we are at a dead-end
    toss this tile out, thereby returning to the previous tile in the stack
  }
}

 

(*) and they are valid for whatever rules you have for your maze

(Longer writeup here: http://en.wikipedia.org/wiki/Maze_generation_algorithm)

Take a look at the animated gifs on this page, and try to follow along with the steps. I have chosen to use complete tiles for walls, but you could as well have neighboring tiles with a thin wall between in your own implementation.

The MazeCreator also has a MazeChanged event that signals every time a new tile has been excavated. This makes it easy to monitor the progress, either by inspecting the Maze property (byte[,]) or by calling the maze’s ToString representation:

image

LEGEND

X = wall

.  = tile which still needs to be checked

0 = tile being excavated

* = the point furthest from the beginning

[space] = tile which is done (no more neighbors to check)

The animated gif above was created by using gOODiDEA’s NGif component – here you can see that I subscribe to the event MazeChanged and add a new Bitmap to the AnimatedGifEncoder for every new tile excavated in the maze:

//create mazes of sizes 11 through 22
for (int size = 10; size < 12; size ++ )
{

    //make a new mazecreator
    _creator = new MazeCreator(size, size, new Point(1, 1));

    //figure out a savepath with a logical name containing width and height
    string gifPath = string.Format("c:\\maze_{0:00}x{0:00}.gif", size);

    //output status to console
    Console.WriteLine("Creating " + gifPath);

    //subscribe to the mazechanged event
    //to get a fresh bitmap on every new tile excavated
    _creator.MazeChanged += new EventHandler<PointEventArgs>(CreatorMazeChanged);

    //create the animated GIF
    _gifEncoder = new AnimatedGifEncoder();
    _gifEncoder.SetDelay(100);  //in milliseconds
    _gifEncoder.SetRepeat(0);   //yes - repeat (-1 is NO)
    _gifEncoder.SetQuality(1); //for generating palette - 1 is best, but slowest
    _gifEncoder.Start(gifPath); //where to save the maze
    var maze = _creator.CreateMaze();   //create a maze
    _gifEncoder.Finish();               //end
                
    //show the animated gif    
    Process.Start(gifPath);
    Console.WriteLine("Furthest point: " + _creator.FurthestPoint);
}

Class diagram and code

Here you can download the project which displays how to use the MazeGenerator, and see the public members of the MazeCreator. If you only want random mazes and don’t care for anything else, just grab the zipped DLL.

image

 Code with sample project

 Just the DLL

 Just the MazeCreator.cs (right-click and choose “Save as…” to save)

More sample mazes  Smiley

11 x 11 maze_11x11           13 x 13 maze_13x13          15 x 15 maze_15x15

image

Small project to show drawing items with the mouse in XNA

Wednesday, February 3rd, 2010

I saw a post today on the XNA Community Forums asking how to give a player the possibility of adding things to a game, and storing the position of the added images.

I made a Downloadlittle project to show how to do this. Basically it adds a Vector2 to a generic List when the left mouse button is pressed and removes a Vector2 when the right mousebutton is pressed.

Here's a small demo:

using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace SmallXNADrawingGame
{
    /// <summary>
    /// Small class to show how to be able to draw and store objects in XNA.
    /// 
    /// Jakob "XNAFAN" Krarup - February 2010
    /// http://www.xnafan.net
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        //a list to store the dots in
        List<Vector2> positionOfDots = new List<Vector2>();

        //the dot to use for drawing
        Texture2D textureDot;

        //stores half the size of the dot for centering the texture
        Vector2 halfSizeOfDot;

        //stores the current and previous states of the mouse
        //they are used to compare in Update() to make sure
        //a mouseclick is a new one and not just the button being held
        MouseState currentMouse, oldMouse;

        //font for writing instructions
        SpriteFont defaultFont;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            //set size of screen
            graphics.PreferredBackBufferHeight = 600;
            graphics.PreferredBackBufferWidth = 800;
            Content.RootDirectory = "Content";

            //make sure to display mouse cursor
            this.IsMouseVisible = true;
        }

        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            textureDot = Content.Load<Texture2D>("dot");
            //calculate half the size of a dot and store it 
            //for drawing the dot centered on the mouseclick (se Draw())
            halfSizeOfDot = new Vector2(textureDot.Width / 2, textureDot.Height / 2);

            //load the font
            defaultFont = Content.Load<SpriteFont>("DefaultFont");
        }

        protected override void Update(GameTime gameTime)
        {
            //store the current state of the mouse (buttons, position, etc.)
            currentMouse = Mouse.GetState();

            //if the mousebutton was pressed between this and last update...
            //this check makes certain that one click doesn't create multiple dots because the button is held down
            if (currentMouse.LeftButton == ButtonState.Pressed && oldMouse.LeftButton == ButtonState.Released)
            {
                positionOfDots.Add(new Vector2(currentMouse.X, currentMouse.Y));
            }

            //if right mousebutton was pressed
            if (currentMouse.RightButton == ButtonState.Pressed && oldMouse.RightButton == ButtonState.Released)
            {
                //and there are still dots left
                if (positionOfDots.Count > 0)
                {
                    //remove the last
                    //"-1" is because the list i zero-indexed,
                    //so a count of 1 would remove the dot at position 1-1 (zero).
                    positionOfDots.RemoveAt(positionOfDots.Count - 1);
                }
            }

            base.Update(gameTime);

            //store the current state in oldMouse 
            //to be able to determine when buttons have JUST been pressed 
            //by comparing the two states in an update
            oldMouse = currentMouse;
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);
            spriteBatch.Begin();

            //write instructions
            spriteBatch.DrawString(defaultFont, "Left mousebutton to draw dot", new Vector2(20, 20), Color.White);
            spriteBatch.DrawString(defaultFont, "Right mousebutton to delete dots", new Vector2(20, 40), Color.White);

            foreach (Vector2 position in positionOfDots)
            {
                //draw the dot centered on the position of the mouse
                //by subtracting the Vector 
                //which has half the textures width for X and half the textures height for Y
                //from the position stored.
                spriteBatch.Draw(textureDot, position - halfSizeOfDot, Color.White);

                //draw the dot's position
                spriteBatch.DrawString(defaultFont, position.ToString(), position, Color.White);
            }
            base.Draw(gameTime);
            spriteBatch.End();
        }
    }
}

XNA Pixel Robots library

Wednesday, January 20th, 2010

A while ago I came across Dave Bollinger's PixelRobots and PixelSpaceships:

Unfortunately his website is gone now :-(, but his work has not been in vain, as this C# version lives on :).

His website is still available on the WayBackMachine, so you can go look at the algorithm for pixel robots and pixel spaceships. In case they ever disappear, here's a zipped PDF print.

Dave, if you're out there, I hope you don't object to me storing your lost treasure for the rest of the world to enjoy your creation :)

He has invented a way of generating simple, random robot-like or spaceship-like sprites. His code will generate many different versions of the millions and millions of possible variations of robots and spaceships. I really liked the idea, and thought that it would be very nice to have an XNA implementation for anyone who needed generic spaceships or robots in a game. So I created an XNA version from his description.

You don't have to understand the internals of neither Dave's code or my API to use this code, as everything is wrapped up in simple methods. But all the helpermethods and variables are available for use if you want to create something more advanced.

It can be as simple as this:

//create two bitmaps scaled by 5 with different colors
Bitmap spaceship = PixelMaskGenerator.GetCompletedRandomSpaceshipImage(5, Color.CornflowerBlue);
Bitmap robot = PixelMaskGenerator.GetCompletedRandomRobotImage(5, Color.LightGreen);

The above code would generate the following two images:

If you'd rather generate SpriteSheets and then use them as Content files instead of creating the spaceships runtime there's also support for that. The spritesheet below was created with the following code:

//create spritesheet
//scaled 3 times, 10 rows and 10 columns
//using spaceships in CornFlowerBlue
Bitmap spritesheet =
PixelMaskGenerator.GenerateRandomSample(3, 10, PixelMaskType.SpaceShip, Color.CornFlowerBlue);
spritesheet.Save(@"C:\spritesheet.png");
spritesheet.Dispose();

Samples spaceships

And then if you need to convert the Bitmaps to Texture2D runtime, it can be done in XNA 4.0 with Florian Block's code:

//Converts a Bitmap to a Texture2D
//Code found here:
//<a href="http://florianblock.blogspot.com/2008/06/copying-dynamically-created-bitmap-to.html):">http://florianblock.blogspot.com/2008/06/copying-dynamically-created-bitmap-to.html):</a>

private Texture2D BitmapToTexture2D(GraphicsDevice dev, System.Drawing.Bitmap bmp)
{
    Texture2D customTexture = new Texture2D(this.GraphicsDevice, bmp.Width, bmp.Height);
    BitmapData data = bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat);

    // calculate the byte size: for PixelFormat.Format32bppArgb (standard for GDI bitmaps) it's the hight * stride
    int bufferSize = data.Height * data.Stride; // stride already incorporates 4 bytes per pixel

    // create buffer
    byte[] bytes = new byte[bufferSize];

    // copy bitmap data into buffer
    Marshal.Copy(data.Scan0, bytes, 0, bytes.Length);

    // copy our buffer to the texture
    customTexture.SetData(bytes);

    // unlock the bitmap data
    bmp.UnlockBits(data);

    return customTexture;
}

Code
The Download code is available here.
The solution includes three projects:

  • PixelRobots is the main project is the project which contains all the code needed to generate SpaceShips, Robots and SpinedRobots (robots that are ensured a cohesive spine) for your game.
  • ConsoleTester is a consoleproject which goes through step-by-step what is done behind the curtains. It saves the generated images to disk and displays them in an HTML page.
  • TestingPixelRobotsInXNA is a little XNA demo which lets you generate spaceships with the left mousebutton and robots with the right mousebutton.

TestingPixelRobotsInXNA

I made a short video presenting the API in use in TestingPixelRobotsInXNA:

Hope it is of use to somebody - it was fun making :)
If you use it for something I'd love to see for what.

More links
Want your own PixelRobot Tee?
Want the code in PHP for your website?
Want to see the PixelRobot idea used in a windowsgame? (non-XNA)

MouseState ExtensionMethod

Wednesday, January 20th, 2010

Just a little helpermethod to get the mouse's position as a Vector2.

For those of you who still haven't gotten started with extension methods here's a quick writeup'n'sample

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace XNAFAN
{
public static class MouseStateExtensionMethods
{

///

/// Returns the mouseposition as a Vector2
///

/// The current MouseState /// The mouseposition as a Vector2
public static Vector2 GetPosition(this MouseState mouse)
{
return new Vector2(mouse.X, mouse.Y);
}
}
}

This way you don't have to convert x and y every time along the lines of
MouseState mouseState = Mouse.GetState();
Vector2 position = new Vector2(mouseState.X, mouseState.Y);

Instead you just add a reference to the code with the extensionmethod and this enables you to write:

Vector2 position = mouseState.GetPosition();

Nifty - eh...? :-)

BasicStarter – something to get you up and running with XNA :)

Thursday, December 17th, 2009

basicstarterscreendumpBased on the input I received from my talk at Aalborg .Net User Group yesterday, I cleaned & commented my code and created a little XNA 3.1 Windows project called BasicStarter to download.

It is a simple start-out class for use in games for beginning XNA coders, has basic keyboard movement in four directions, fullscreen setup, black background.
It is possible to pause the game with "P"
It is possible to exit the game with "Esc"
The project also shows how a class called GameSprite which subclasses DrawableGameComponent is used to store image, position and speed of an object in a game.

Here is the class diagram. I like to get the gist of other people’s code this way Smiley

basicstarterclassdiagram

Some notable pieces of code for the beginner are:

How to get a direction from multiple keypresses
//create a variable to hold which direction to move
Vector2 movement = Vector2.Zero;

//alter the direction according to the keys pressed:
if (keyState.IsKeyDown(Keys.Down)) { movement += Directions.Down; }
if (keyState.IsKeyDown(Keys.Up)) { movement += Directions.Up; }
if (keyState.IsKeyDown(Keys.Left)) { movement += Directions.Left; }
if (keyState.IsKeyDown(Keys.Right)) { movement += Directions.Right; }

//use the combined movement from the keys
//to update the position of the XNA logo
//we multiply by gamespeed to get a reasonable speed onscreen
xnaLogo.Velocity = movement * gameSpeed;
Hope you like it - and send feedback if you can think of improvements :)