Archive for October, 2012

XNA Arcade tutorial (3 of 5) – Creating the hosting game and selecting a game to play

Wednesday, October 24th, 2012

What we will cover

In this tutorial we will look at how to use the ArcadeGamesManager to inspect external DLLs for games, how to get information about them and how to instantiate a selected game and run it.

Information about what games are available (name and icon)

All games for the Xna Arcade are loaded from DLL files (Assemblies) from the game's folder or subfolders.

files

Here you can see the main (hosting) game "XnaArcadeTutorial.exe" which relies on the "ArcadeLibrary.dll" (with the ArcadeGamesManager class) for inspecting DLL files with games in them: "SampleGamesPack.dll".

For this tutorial all you need to know is that code in .net is hosted in Assemblies (often .exe or .dll files)which are self-contained units that have both code and a description of the contents. Sometimes the assemblies also contain further resources (text files/images/sound/etc..). For finding games in external assemblies, loading them and getting their icons, I've coded a helperclass, the ArcadeGamesManager.

The ArcadeGamesManager class

arcadegamesmanager

The ArcadeGamesManager assists in all the boring housekeeping and let's you concentrate on the fun stuff: Coding Games! Smiley. The short version is: the ArcadeGamesManager uses a method called Reflection to inspect an assembly (the dll file with games in) and find out which classes are subclasses of the AbstractGame class, information about these games are returned in a Type object. Type objects contain information about a given class/object and are used as parameters to the ArcadeGamesManager.CreateGame() when you want to instantiate a specific game for playing.

ArcadeGamesManager Codesamples

First code for instantiating a ArcadeGamesManager and using it to get a list of all the playable games:

//initialize a ArcadeGamesManager by sending it a reference to the HostingGame
ArcadeGamesManager _gamesManager = new ArcadeGamesManager(this);

//get all the games in all DLL files in the executing game's folder or its subfolders
List<Type> _games = _gamesManager.GetGamesFromRunningGamesSubfolders();

GetGameThumbnail and GetGameName assist in getting games' names and icons for making a menu for example:

//Iterate through all games and get name and icon
for (int i=0; i<_games.Count(); i++)
{
//get the icon for that gametype
Texture2D _gameIcon = _gamesManager.GetGameThumbnail(_games.ElementAt(i));
//read the DisplayName attribute from the class, to show its name
string gameName = _gamesManager.GetGameName(_games.ElementAt(i));
//do something with name and icon
//...
}

After selection of a game has been made and we want to start it, we use the CreateGame() method to create an instance (object) of that Type. How we write code to make a menu and select from the menu is covered in part 4 of this tutorial.

//get the typedescription of the type of game to start
Type typeOfGameToStart = _games.ElementAt(_selectedGameIndex);

//create an instance of a specific game, and store it in _currentGame
AbstractGame _currentGame = _gamesManager.CreateGame(typeOfGameToStart, spriteBatch);

What happens when the ArcadeGamesManager creates a new game

/// <summary>
/// Creates a new object of a game from the Type and initializes it
/// </summary>
/// <param name="gametype">The type of game to instantiate (must be subclass of AbstractGame)</param>
/// <param name="game">The hostgame which will run the abstractgame</param>
/// <param name="graphics">The GraphicsDeviceManager which this game can interact with</param>
/// <param name="spriteBatch">The SpriteBatch for the game to draw to</param>
/// <returns>The new instance of the game after it has been initialized</returns>
public AbstractGame CreateGame(Type gametype, SpriteBatch spriteBatch)
{
	//make sure the type describes a subclass of AbstractGame
	if (gametype.IsSubclassOf(typeof(AbstractGame)))
	{
		//call the constructor of the class
		AbstractGame _game = (AbstractGame)Activator.CreateInstance(gametype);
		//initialize it
		_game.Initialize(this,spriteBatch);
		//and return it
		return _game;
	}
	else
	{
		throw new Exception("The type " + gametype.Name + " is not a subclass of AbstractGame");
    }
}

As you can see the ArcadeGamesManager calls the Initialize method of the game it is creating and passes a reference to itself. Here you can see the AbstractGame.Initialize method and what is made ready for your game to take over and do its thing Smiley

public virtual void Initialize(ArcadeGamesManager gamesManager, SpriteBatch batch)
{
    //store references for use in this game
    GamesManager = gamesManager;
    Game = GamesManager.Game;
    GraphicsDeviceManager =
        (GraphicsDeviceManager) Game.Services.GetService(typeof(GraphicsDeviceManager));
    Graphics = Game.GraphicsDevice;
    SpriteBatch = batch;
    //store the contentmanager which points to the main game
    HostContent = Game.Content;
    //store the contentmanager which points to the game's own assembly
    LocalContent = GamesManager.GetContentManager(this.GetType());
    Font = GamesManager.DefaultFont;
}

XNA Arcade tutorial (2 of 5) – The AbstractGame and ArcadeGamesManager

Thursday, October 18th, 2012

This is an introduction to how we will create the basis for all the games (AbstractGame)
which can be loaded and played in the XNA Arcade. We will also create a helperclass
(ArcadeGamesManager) which can load these classes and their resources from external
assemblies (DLLs).


2012-10-18_112144

Why an AbstractGame class?

At its core, what we want 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 from the hostgame.
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.

The basic structure - Draw() and Update()

Since we are already familiar with the idea of the Game class in XNA, we will let the AbstractGame class have an Update and a Draw method as well. This simplifies running the subgame in the hostgame as the calls to Update and Draw in the hostgame will just forward the calls to Update and Draw in the whatever game is currently loaded.

updatedrawonsubgame

This effectively puts the hostgame out of the loop. So we need some way to return control when the subgame has ended. We do this by letting the hostgame read a public variable called GameOver on the subgame. The subgame can then set this variable to true when the hostgame should take control again. Here's code from the hostgame, calling the subgame's Update and Draw:

//To hold the currently running subgame
AbstractGame _currentGame;

protected override void Update(GameTime gameTime)
{
    //if we're playing a game
    if (_currentGame != null)
    {
        //if the game is over, empty the current game
        //thereby returning to the game selection screen
        if (_currentGame.GameOver)
        {
            _currentGame = null;
        }
        else
        {
            //call the update method of the game being played
            _currentGame.Update(gameTime);
        }
    }
}

protected override void Draw(GameTime gameTime)
{

    if (_currentGame != null)
    {
        //use that game's Draw
        _currentGame.Draw(gameTime);
    }
    else
    {
        //draw the hostgame's gameselection screen
    }
}

Give AbstractGame the tools it needs

Since the subgame isn't a real Game class it doesn't have access to the same variables that an ordinary Game does (e.g. ContentManager, GraphicsDevice, etc.). This means we have to supply it with these things. The way I've chosen to handle this is by making a helperclass (ArcadeGamesManager) which is instantiated using a reference to the hostgame. When you want an instance of a game you only need to tell the ArcadeGamesManager what type of game to create and give it a reference to the SpriteBatch you want it to draw on (here the "this" refers to the hostgame where the ArcadeGamesManager is created):

ArcadeGamesManager manager = new ArcadeGamesManager(this);

AbstractGame myGame = manager.CreateGame(typeof(MyChessGame), this.SpriteBatch);

What about resources?

Since we would like the subgames to be selfcontained - so just adding a new DLL to a subdirectory in the hostgame's folder will add new games - we need to be able to contain everything we need inside the DLL: code, graphics, sounds, fonts, etc. How we embed the resources will be covered in part 4, but just know for now, that the AbstractGame class has two ContentManager properties HostContent and LocalContent to be able to load content from both the hostgame and its own DLL.


contentload

The idea behind this is that you want the subgames to be able to stand on their own as well and supply all resources, but if you are developing a gamespack, you might design all subgames to load resources from the main game (fonts, textures, etc.) to give them a coherent look-and-feel.

This gives you both possibilities Smiley

Sample code

HostContent.Load("background"); //loads from the hostgame

LocalContent.Load("background"); //loads from the game's own DLL

Rolling your own subgame

Since you don't construct your own instances of your games, but leave that up to the ArcadeGamesManager, you may still want to do some intialization (load resources, set variables, etc.). The AbstractGame defines an Initialize method which you can override. Just make sure you call

base.Initialize(...)

as the first line in your own Initialize method, so the AbstractGame is initialized as well.

In my next (upcoming) blogpost I will look at how we inspect the DLL files and make it possible for the player to select a game to run:

Next chapter: Part 3 - Creating the hosting game and selecting a game to play

XNA Arcade tutorial (1 of 5) – loading games dynamically [Overview]

Thursday, October 18th, 2012

This tutorial covers how to make an XNA game which can host other games.
It is a complete tutorial based on my previous blogpost. The code is expanded significantly in this tutorial series, and explained in more detail.  You need Xna 4.0 installed to run the demo.

2 minute introduction to the XNA Arcade

What we will cover

- creating an XNA game which can act as a host to others
- creating a tool to discover games in external assemblies (DLLs)
- embedding textures and sounds inside external assemblies, and extracting those resources
- making a scrollable menu with icons and the names of the discovered games (using RenderTarget)
- creating a subgame (Tic-Tac-Toe), by coding a concrete implementation of AbstractGame
- initializing subgames and passing control to them

IMPORTANT
The code presented here does not allow you to load other standard XNA games.
The games playable using this method are based on an AbstractGame class, where you implement Draw() and Update(). If you want to load a regular XNA game, you will have to move your code into a new class inheriting the AbstractGame class, and embed your resources in the DLL.

 

 

Links to the lessons

Part 0 -  The initial blogpost which got this ball rolling (a Betaversion of this tutorial Smiley)
Part 1 - This introduction to what the XNA Arcade is and what this tutorial-series covers
Part 2 - The AbstractGame class and the ArcadeGamesManager
Part 3 - Creating the hosting game and selecting a game to play
Part 4 - Creating a scrollable menu for gameselection using RenderTarget2D
Part 5 - Coding a  new subgame  and embedding XNA resources in the DLL

The code

Complete code (you may have to build the projects individually)


Just the playable version
(no source code)

Just the ArcadeLibrary.DLL you need for making your own games

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