Gentle readers,
I'd like to thank you all for reading this far and assure you there is more to come shortly.
I just wanted you to know that I have not abandoned either this project or this blog. Its been a busy week as we all prepare to return to school in the fall. In addition, I am writing a new chunk of code for TwoDEngine as I wasn't happy with the first Networking implementation.
This new Networking framework will have multiple levels, with the simplest being a game session manager. This game session manager will be implemented both as a peer to peer system for LANS as well as having one or more socket server based WAN implementations. The first release will be the peer to peer driver which I am hoping to have finished by the end of this weekend.
So, please bear with me and i promise there will be much more to come!
Thank you all
Professor K
Monogamey
A blog on cross platform game development centering on C# using Monogame.
Friday, August 30, 2013
Tuesday, August 13, 2013
Bunny Hunters Online: Mode Management
Note: The mode management stuff described here requires an update to TwoDEngine now available.
A computer game typically progresses through a number of "screens" or "display modes". Each of these has a specific function. The title screen, help screen, options menu and play field are all examples of a mode.
Bunny hunters will have seven modes the player progresses though. These modes are typical of a minimal online game and are described with the "bubble diagram" below:
Another word for a mode is a "state". A machine that can be in one and only one state at a time is called a Finite State Automaton (FSA). A game is typically an FSA.
TwoDEngine is made up of a set of completely independent modules. You can use some or all of them in your game. So far, the game has used the Scenegraph module. Another module in TwoDEngine is the ModeManager. This is a simple FSA that makes writing and organizing your modes easier.
Each mode is defined in a class that implements the GameMode interface. This interface looks like a simplified version of the Monogame Game class, defining only an Update and Draw method. It also has two new methods "EnterMode()" and "ExitMode()".
When a GameMode instance first becomes active, the ModeManager calls its "EnterMode()" Method. When a different mode is set active, the previously active mode has its "ExitMode()" method called. In between the Update() and Draw() methods of only the active mode get called by the ModeManager on every game Update and Draw.
In addition to implementing the four GameMode methods (an implementation can be empty but it must still be there), an instance of a GameMode must declare a special initializer. This initializer takes two parameters. The first is a reference to an instance of the Monogame Game class, which in BHO is the instance of the Game1.cs class. The second is a string, which is the state name assigned to this mode on its creation.
The ModeManager can be used on its own, without the Scenegraph module. In this case drawing would be handled by the implementation code of the mode's Draw method. However, a utility class is provided to make it easy to use the ModeManager with the Scenegraph. This is an abstract class called AbstractScenegraphMode.
Every instance of an AbstractScenegraphMode has a field called Root. Rather then parenting that mode's scene graph to the Scenegraph object itself, the constructor of an AbstractScenegraphMode sub-class should parent its objects to the Root. The EnterMode() and ExitMode() code inside of AbstractScenegraphMode switches the Root "on" and "off" so that the Scenegraph Objects under the Root only display and update when it is the current mode.
The first mode is very simple as it just displays the title screen until it sees a button click. Create a new C# file in the shared source folder called TitleMode. Note: VS2012 will helpfully think its namespace is BHO.shared_source because it is in the shared source folder. Fix this by just deleting the .shared_source from the namespace line near the top of the file. It should look something like this:
The using block should look like this afterward:
That should leave you with a class skeleton that looks like this:
All GameMode instances must implement a constructor that takes two arguments. The first is a Game reference to the main game object. The second is a string that contains the name the ModeManager knows this mode by. This constructor must in turn pass control to the no-argument constructor of AbstractScenegraphMode. (Failure to pass control will cause the Root field to be null when you try to use it.)
Add a constructor like this:
In order to detect a de-bounced mouse-button press, it is necessary to detect first a button down, then a button up. This means it must store the fact that it has seen a button down. This is easily accomplished by adding a class field to hold that information. In general I add most class fields at the top of the class, but where a field is only relevant to a small section of the class, I will add it in that section. In this case I added a boolean right above Update called mousePressed and set it to start false like this:
The last thing needed to make this mode display is to change the code in Game1.cs for the constructor and the LoadContent method. The constructor needs to create the ModeManager the same way it created the Scenegraph, with a new. Add it to the bottom of the Game1() constructor so it looks like this:
Currently the LoadContent method loads the title screen and attaches it to the Scenegraph. In the new version of the game all it will do is create the mode and set the ModeManager. Chagge it to look like this:
This line deserves some added explanation:
This is type of method is called a generic factory method, and is a particularly unique and useful C# trick. A factory method is a method that creates and returns an instance of a class. Traditionally, the actual class of the object is contained within the factory method and what it returns as a type is an interface.
In C# however, we can access generic types at run-time. This makes possible a factory method that actually creates and returns an instance of a specific class we specify at run-time. In this method, that class can be any sub-class of GameMode. The passed in parameter is the name of this instance.
You might wonder why it doesn't just say "new TitleMode(this,"Title Mode"). This syntax would also create the same instance however the ModeManager would not be aware of it. By using a factory method on the ModeManager, the ModeManager can internally track the names of all GameMode instances created.
In the next blog a new mode will be created that handles the network login.
A computer game typically progresses through a number of "screens" or "display modes". Each of these has a specific function. The title screen, help screen, options menu and play field are all examples of a mode.
Bunny hunters will have seven modes the player progresses though. These modes are typical of a minimal online game and are described with the "bubble diagram" below:
Another word for a mode is a "state". A machine that can be in one and only one state at a time is called a Finite State Automaton (FSA). A game is typically an FSA.
TwoDEngine is made up of a set of completely independent modules. You can use some or all of them in your game. So far, the game has used the Scenegraph module. Another module in TwoDEngine is the ModeManager. This is a simple FSA that makes writing and organizing your modes easier.
Each mode is defined in a class that implements the GameMode interface. This interface looks like a simplified version of the Monogame Game class, defining only an Update and Draw method. It also has two new methods "EnterMode()" and "ExitMode()".
As explained above, the ModeManager can be in only one mode at a time. This mode is either a programmer defined instance of the GameMode interface, or null meaning "no mode."public interface GameMode{void EnterMode();void Update(GameTime gameTime);void Draw(GameTime gameTime);void ExitMode();}
When a GameMode instance first becomes active, the ModeManager calls its "EnterMode()" Method. When a different mode is set active, the previously active mode has its "ExitMode()" method called. In between the Update() and Draw() methods of only the active mode get called by the ModeManager on every game Update and Draw.
In addition to implementing the four GameMode methods (an implementation can be empty but it must still be there), an instance of a GameMode must declare a special initializer. This initializer takes two parameters. The first is a reference to an instance of the Monogame Game class, which in BHO is the instance of the Game1.cs class. The second is a string, which is the state name assigned to this mode on its creation.
The ModeManager can be used on its own, without the Scenegraph module. In this case drawing would be handled by the implementation code of the mode's Draw method. However, a utility class is provided to make it easy to use the ModeManager with the Scenegraph. This is an abstract class called AbstractScenegraphMode.
Every instance of an AbstractScenegraphMode has a field called Root. Rather then parenting that mode's scene graph to the Scenegraph object itself, the constructor of an AbstractScenegraphMode sub-class should parent its objects to the Root. The EnterMode() and ExitMode() code inside of AbstractScenegraphMode switches the Root "on" and "off" so that the Scenegraph Objects under the Root only display and update when it is the current mode.
The first mode is very simple as it just displays the title screen until it sees a button click. Create a new C# file in the shared source folder called TitleMode. Note: VS2012 will helpfully think its namespace is BHO.shared_source because it is in the shared source folder. Fix this by just deleting the .shared_source from the namespace line near the top of the file. It should look something like this:
The first thing to add is using statements for the parts of TwoDEngine TilteMode will use. These are using TwoDEngine, using TwoDEngine.Scenegraph.SceneObjects and using TwoDEngine.ModeManager. It also needs some Monongame namespaces: Microsoft.Xna.Framework, Microsoft.Xna.Framework.Graphics and Microsoft.Xna.Framework.Input.using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace BHO{class TitleMode{}}
The using block should look like this afterward:
The next thing to do is to make TitleMode a sub-class of AbstractScenegraphMode. (I assume you know enough C# to do this so I won't go into any deeper explanation.) Then you should right click on AbstractScenegraphMode and select "Implement Abstract Class". (Note: You may have to do a quick build for it to show you this options. If so then don't worry about the errors it spits out, its not done yet.)using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using Microsoft.Xna.Framework;using Microsoft.Xna.Framework.Graphics;using Microsoft.Xna.Framework.Input;using TwoDEngine;using TwoDEngine.Scenegraph.SceneObjects;using TwoDEngine.ModeManager;
That should leave you with a class skeleton that looks like this:
As generated, Draw and Update will throw an exception when called. TitleMode won't do any drawing, thats up to the Scenegraph, but it shouldn't throw an error either, so remove that line and leave Draw() empty. (I generally put a comment of //NOP in such methods just to make it clear I intended them to do nothing.) Update will respond to the mouse button, but first TitleMode needs a constructor.using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using Microsoft.Xna.Framework;using Microsoft.Xna.Framework.Graphics;using Microsoft.Xna.Framework.Input;using TwoDEngine;using TwoDEngine.Scenegraph.SceneObjects;using TwoDEngine.ModeManager;namespace BHO{class TitleMode : AbstractScenegraphMode{public override void Draw(GameTime gameTime){throw new NotImplementedException();}public override void Update(GameTime gameTime){throw new NotImplementedException();}}}
All GameMode instances must implement a constructor that takes two arguments. The first is a Game reference to the main game object. The second is a string that contains the name the ModeManager knows this mode by. This constructor must in turn pass control to the no-argument constructor of AbstractScenegraphMode. (Failure to pass control will cause the Root field to be null when you try to use it.)
Add a constructor like this:
This constructor will load the title screen and attach it to Root so it can be switched on and off.public TitleMode(Game game,string name): base(){Texture2D startScreen = game.Content.Load<Texture2D>("intro");new BasicSprite(Root, startScreen);}
In order to detect a de-bounced mouse-button press, it is necessary to detect first a button down, then a button up. This means it must store the fact that it has seen a button down. This is easily accomplished by adding a class field to hold that information. In general I add most class fields at the top of the class, but where a field is only relevant to a small section of the class, I will add it in that section. In this case I added a boolean right above Update called mousePressed and set it to start false like this:
Now the button press logic must be added to Update. When update sees a left button down, it sets mousePressed true. When it sees a left button up and mousePressed is true, it sets mousePressed back to false and change to the null mode (meaning no mode at all.) That code looks like this:private bool mousePressed = false;public override void Update(GameTime gameTime){throw new NotImplementedException();}
The completed TitleMode.cs file should now look like this:public override void Update(GameTime gameTime){MouseState mouseState = Mouse.GetState();if (!mousePressed && (mouseState.LeftButton == ButtonState.Pressed)){mousePressed = true;}if (mousePressed && (mouseState.LeftButton == ButtonState.Released)){mousePressed = false;Registry.Lookup<ModeManager>().ChangeMode((GameMode)null);}}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using TwoDEngine;
using TwoDEngine.Scenegraph.SceneObjects;
using TwoDEngine.ModeManager;
namespace BHO
{
class TitleMode : AbstractScenegraphMode
{
public TitleMode(Game game,string name): base()
{
Texture2D startScreen = game.Content.Load<Texture2D>("intro");
new BasicSprite(Root, startScreen);
}
public override void Draw(GameTime gameTime)
{
//NOP
}
private bool mousePressed = false;
public override void Update(GameTime gameTime)
{
MouseState mouseState = Mouse.GetState();
if (!mousePressed && (mouseState.LeftButton == ButtonState.Pressed))
{
mousePressed = true;
}
if (mousePressed && (mouseState.LeftButton == ButtonState.Released))
{
mousePressed = false;
Registry.Lookup<ModeManager>().ChangeMode((GameMode)null);
}
}
}
}
The last thing needed to make this mode display is to change the code in Game1.cs for the constructor and the LoadContent method. The constructor needs to create the ModeManager the same way it created the Scenegraph, with a new. Add it to the bottom of the Game1() constructor so it looks like this:
public Game1(){Content.RootDirectory = "Content";Scenegraph sg = new Scenegraph(this);sg.SetBackgroundColor(Color.Aquamarine);//sg.SetBackgroundEnabled(false);GraphicsDeviceManager _graphics = Registry.Lookup<GraphicsDeviceManager>();_graphics.PreferredBackBufferHeight = 600;_graphics.PreferredBackBufferWidth = 800;new ModeManager(this);}
Currently the LoadContent method loads the title screen and attaches it to the Scenegraph. In the new version of the game all it will do is create the mode and set the ModeManager. Chagge it to look like this:
Now build and run the game. You should see the title screen. When you click your mouse on the title screen, it should change to black.protected override void LoadContent(){// TODO: use this.Content to load your game content hereModeManager mgr = Registry.Lookup<ModeManager>();mgr.NewMode<TitleMode>("Title Mode");mgr.ChangeMode("Title Mode");}
This line deserves some added explanation:
mgr.NewMode<TitleMode>("Title Mode");
This is type of method is called a generic factory method, and is a particularly unique and useful C# trick. A factory method is a method that creates and returns an instance of a class. Traditionally, the actual class of the object is contained within the factory method and what it returns as a type is an interface.
In C# however, we can access generic types at run-time. This makes possible a factory method that actually creates and returns an instance of a specific class we specify at run-time. In this method, that class can be any sub-class of GameMode. The passed in parameter is the name of this instance.
You might wonder why it doesn't just say "new TitleMode(this,"Title Mode"). This syntax would also create the same instance however the ModeManager would not be aware of it. By using a factory method on the ModeManager, the ModeManager can internally track the names of all GameMode instances created.
In the next blog a new mode will be created that handles the network login.
Saturday, August 10, 2013
Bunny Hunters Online: Introducing TwoDEngine
In the last blog, Monogame was used directly to display an individual image. That works great for simple situations but a game can quickly grow beyond such simple graphics needs. In particular, complex multi-sprite objects need a way to move objects in relation to each other. A Scenegraph is a very common way to handle this.
The global _graphics no longer exists, so remove the first line entirely. Instead, you need to create a Scenegraph. The Scenegraph will actually create a GraphicsDeviceManager for you. To create the Scenegraph you add the line new Scenegraph(this) at the top. (The Scenegraph constructor has a whole bunch of optional parameters that follow the Game parameter but you can ignore them for now.
You still need to set the PreferredBackBuffer size. To do that you need access to the GraphicsDeviceManager that the Scenegraph created. Conveniently, the Scenegraph registers the GraphicsDeviceManager in the TwoDEngine registry. You can ask the registry for the registered object that implements a given class or interface with the Registry.Lookup command. Add this line just after the line Content.RootDirectory = "Content" :
GraphicsDeviceManager _graphics = Registry.Lookup<GraphicsDeviceManager>()
When you are done modifying the constructor it should look like this:
A scene graph is simply a tree of graphical objects where position and orientation of children are all in reference to their parent. In such a system a single graphical object is often called a Sprite.
In a side scroller, when the background is moved the rest of the sprites should move along with it so they stay in the same place relative to the background. This is accomplished with a Scenegraph by making the background the parent of the other sprites.
Another example of how a Scenegraph might be used is in a top down tank battle game. The tank body is one sprite but its turret is another. The turret has to be rotatable in relation to the body, but has to move and rotate with the body when the body moves and rotates. This is accomplished by making the turret sprite a child of the body sprite.
In general Scenegraphs simplify the organization of objects in an environment. They are common in 3D systems such as Unity3D. TwoDEngine is, at its heart, a 2.5D Scenegraph. The 2D part is positions in x and y. The .5 refers to draw priority, which is not full 3D but does provide a relative "depth" to the objects.
Although the actual hierarchical needs of BHO are minimal, TwoDEngine also contains useful animation, motion and collision detection code as well as some other features that will make implementing BHO much simpler.
In order to use TwoDEngine the first thing to do is to download it. It is available in both source code and pre-compiled library form. For this project the pre-compield libraries are simpler to use. You can download them from The Unseen University by clicking the Download button on this page:
Unzip the downloaded zip file and copy it to your Bunny Hunters Online Project folder. The folder should look like this afterward:
Now go back into VS2012 and add the proper TwoDEngine lib as a reference. To do this, right click on "references" in the project explorer and select "add reference".
When the add reference dialog pops up, select "Browse" on the left and then click the Browse button on the bottom right.
Navigate to your Bunny Hunters Online folder and then down into the TwoDEngine directory. Beneath that you will see a list of platforms, navigate down into Windows 8 Store.
Form here, navigate down to bin->Windows 8->Debug. Select TwoDEngine.dll and press Add in the lower right of the dialog. (Don't worry about the other DLLs you already have them as part of your monogame Windows 8 Store project.)
Your project should look like this now. Note that TwoDEngine (Windows Store) is now in your references list.
The next step is to modify Game1.cs to use TwoDEngine. This will actually simplify the Game1.cs file a bit.
To start with, you will need to include 3 namespaces from TwoDEngine. Go to the top of Game1.CS and add using TwoDEngine, using TwoDEngine.Scenegraph and using TwoDEngine.Scenegraph.SceneObjects. When you are done it should look like this.
using Microsoft.Xna.Framework;using Microsoft.Xna.Framework.Graphics;using TwoDEngine;using TwoDEngine.Scenegraph;using TwoDEngine.Scenegraph.SceneObjects;
Next, the global variables at the top of the Game1.cs class should be removed as they are no longer necessary. It currently looks like this.
Remove all 3 field declarations so all that is left at the top is the class declaration like this.
Next, change the constructor. It currently looks like thispublic class Game1 : Game{
The global _graphics no longer exists, so remove the first line entirely. Instead, you need to create a Scenegraph. The Scenegraph will actually create a GraphicsDeviceManager for you. To create the Scenegraph you add the line new Scenegraph(this) at the top. (The Scenegraph constructor has a whole bunch of optional parameters that follow the Game parameter but you can ignore them for now.
You still need to set the PreferredBackBuffer size. To do that you need access to the GraphicsDeviceManager that the Scenegraph created. Conveniently, the Scenegraph registers the GraphicsDeviceManager in the TwoDEngine registry. You can ask the registry for the registered object that implements a given class or interface with the Registry.Lookup command. Add this line just after the line Content.RootDirectory = "Content" :
GraphicsDeviceManager _graphics = Registry.Lookup<GraphicsDeviceManager>()
When you are done modifying the constructor it should look like this:
public Game1(){new Scenegraph(this);Content.RootDirectory = "Content";GraphicsDeviceManager _graphics = Registry.Lookup<GraphicsDeviceManager>();_graphics.PreferredBackBufferHeight = 600;_graphics.PreferredBackBufferWidth = 800;}
The next thing that needs to be modified is the LoadContent method. It will still need to load the Texture2D but instead of storing it in a global for use in Draw(), it will use it locally to create a Sprite to display.
As mentioned earlier, Sprites can have other Sprites as parents. They can also have the Scenegraph object itself as a parent. The Scenegraph object is the root of the displayed scene. In order to be displayed, a Sprite must be able to trace its parentage back to the Scenegraph.
Since all the code does so far is display a single image, that image can be made into a BasicSprite whose parent is the Scenegraph itself. You get the Scenegraph the same way you got the GraphicsDeviceManager, by looking it up in the Registry.
Replace all of the code currently in LoadContent with this code in order to do that:
Finally, since the Scenegraph is managing the actual drawing of its sprites, we no longer need or want any game specific code in the Draw method Game1.cs. Return it to its originally generated state like this:protected override void LoadContent(){// TODO: use this.Content to load your game content hereTexture2D startScreen = Content.Load<Texture2D>("intro");Scenegraph sg = Registry.Lookup<Scenegraph>();new BasicSprite(sg, startScreen);}
Build and run this code and you should see the same title screen you saw before. Next blog will take this much and create a "game mode" from it in order to start enabling other game displays.protected override void Draw(GameTime gameTime){base.Draw(gameTime);}
Tuesday, August 6, 2013
Bunny Hunters Online: The First Image
My college degree is both Computer Science and Film Production, and we have a rule in film. Its called "the rule of ten."
Refactoring is an idea that has been around software practically since the beginning, but was formalized as part of the Agile development lexicon. This project is being done is steps, much like an agile project. In an agile project you work on one thing, get it working, and then stop and clean it up before going on to the next thing. This cleanup is called refactoring. This first refactor is some additional organization to make going to other platforms easier.
As I mentioned above, the Game1.cs class, and all the classes that will be written later on, will be shared between projects. However, if you look at the top of the Game1.cs file you will see this:
This is because Program.cs needs to use Game.cs, but they are no longer in the same namespace. While this could be fixed by changing the namespace of Program.cs, that would be wrong because, again as mentioned above, Program.cs is specific to the BHO Windows Store project.
Instead, this is solved by adding a using statement to Program.cs. Right now, the top of Program.cs looks like:
Right now, if we created a new class, it would get the namespace BHO_Windows_Store and we would have to edit it. This could get tedious. Since all the code to be written from here out will be in the BHO namespace, it would be convenient to change the default. This is easily done in VS2012.
Start by right clicking the BHO Windows Store project and select "properties" from the pop up context menu.
==
Voilla! You are all set up to start some serious cross platform development!
Next blog will introduce the TwoDEngine scenegraph, and game state management with a simple Finite State Machine.
Every dollar you spend preparing for your project, in what is called "pre-production" in film, saves ten dollars you would otherwise have to expend in shooting the movie or what we call "production."
Furthermore, every dollar you spend in production, saves you ten dollars you would otherwise have to spend in editing and special effects and such, what is called "post-production."
Proper, efficient movie making is front-loaded. You spend the most time where you get the most return, which is in that preparation before a frame of film (or video, these days) is shot. Game making has very similar economics. Preparation and planning are key. For that reason, we have spent a number of blogs setting up the development environment for our game. There will be a bit more fiddling with it a bit further on, but for now, we are finally ready to actually get something on screen.
To begin with, we are going to put the title screen up so we can see it display. Although deeper into the project we will be using a scene graph engine (more on that later), for now we can just use Monogame directly.
If you look at the BHO Windows Store project generated by VisualStudio, you will see that there are two c-sharp files already generated for you. Program.cs and Game.cs.
Program.cs is the "main" file. It is the one that invoked by the operating system to start your game. Although there will be a Program.cs file in every platform project we create for BHO, it may contain different code depending on the needs of the particular platform. It is the "glue" that connects Monogame code to the platform. For the most part, we are going to leave that as it is.
The second file, Game.cs, is the actual Monogame game. It will be exactly the same across all of the platforms BHO will be ported to. In fact, there will be only one real Game.cs file which every platform's project will link to, just like the assets.
Game.cs begins as an empty shell of a program. All it does is display the blue screen that we saw when we tested the project in the previous blog. In this blog it will be modified to display the title screen. As this is not intended to be a full course in C# programming, I am not going to explain all the syntax but just call out the key areas that need to be changed to create BHO.
In order to display the title screen, we need the title screen image. In Monogame images are stored in a Texture2D object. At the top of the Game class in Game.cs there is a small global variables block that looks like this:
public class Game1 : Game {
GraphicsDeviceManager _graphics; SpriteBatch _spriteBatch;
Add a Texture2D object to it, so it looks like this:
public class Game1 : Game{
GraphicsDeviceManager _graphics; SpriteBatch _spriteBatch;
Texture2D startScreen;
All the art for BHO was produced for a game screen that is 800 pixels wide and 600 pixels tall. Monogame needs to be instructed to set the display window to that resolution. This can be done in the constructor method of Game.cs. It currently looks like this:
public Game1() {
_graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
Adding these two lines sets the height and the width:
public Game1()
{
_graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
_graphics.PreferredBackBufferHeight = 600;
_graphics.PreferredBackBufferWidth = 800;
}
The next task is to load the title screen. This is done in the LoadContent method. As generated, it looks 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
}
The template already has a place marked in comments for us to add the load code. Adding this will load the title screen:
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
startScreen = Content.Load<Texture2D>("intro");
}
The final step is to display the title screen. Monogame implemenst a classic Update/Render game loop. Every frame, first the game's Update method is called to calculate the new game state and then the Render method is called to display it. For the moment, there is no game state so Update can be ignored. The render method however must have the code to draw the title screen added to it. It currently looks like this:
protected override void Draw(GameTime gameTime){
GraphicsDevice.Clear(Color.CornflowerBlue);
// TODO: Add your drawing code here
base.Draw(gameTime);
}
Once again the template has already marked where the code must be added. Add the following code between the TODO and base.Draw(gameTime) to draw the screen:
protected override void Draw(GameTime gameTime){
GraphicsDevice.Clear(Color.CornflowerBlue);
// TODO: Add your drawing code here
_spriteBatch.Begin();
_spriteBatch.Draw(startScreen, new Vector2(0, 0), Color.White);
_spriteBatch.End();
base.Draw(gameTime);
}
Build and run the project. You should see the grey screen with the icon in the center for a moment, followed by this:
To quote Kermit the frog, "Yayyyyy!" You have the first screen of the game being displayed. Take a moment to pat yourself on the back. But it isn't done. This has led directly to our first refactor.
As I mentioned above, the Game1.cs class, and all the classes that will be written later on, will be shared between projects. However, if you look at the top of the Game1.cs file you will see this:
namespace BHO_Windows_Store
This is because every project has a default name space that it creates new classes in and, when a project is initially created, it is based on the name of the project. This name however is misleading. We want this code to be shared between all BHO projects. So change that name space to just BHO like so.
namespace BHO
If you try to build the code now, you will get the following build error:
Error 2 The type or namespace name 'Game1' could not be found (are you missing a using directive or an assembly reference?) Z:\Google Drive\Projects\Cross Platform\BHO\Bunny Hunters Online\BHO Windows Store\Program.cs 15 74 BHO Windows Store
Instead, this is solved by adding a using statement to Program.cs. Right now, the top of Program.cs looks like:
using System;
namespace BHO_Windows_Store;
Add using BHO; so it looks like this:
using System;
using BHO;
namespace BHO_Windows_Store
Build and run it again and you should get the title screen once more.
Start by right clicking the BHO Windows Store project and select "properties" from the pop up context menu.
This will open the properties editor in the main edit window. Click on Applications and you will see this form.
In the middle there is a field marked "Default namespace:" that contains BHO_Windows_Store. Change that field to just BHO, save and close the properties editor. Now all new classes will be created in the BHO namespace.
The last bit of refactoring is just to create a folder called "shared source" and move Game1.cs into it. All new game code will go in this directory too in order to make it easy to move to a shared location later.
The last bit of refactoring is just to create a folder called "shared source" and move Game1.cs into it. All new game code will go in this directory too in order to make it easy to move to a shared location later.
==
Edit Important:
On further experimentation, I have determined that the linked source directory strategy originally given here doesn't quite work the way I'd hoped. Although the initial Game1.cs file does end up in the externally linked directory, new classes you create from inside of VS2012 does not. Accordingly I am removing this step. We will do it later after the source base for Windows Store is complete.==
Next blog will introduce the TwoDEngine scenegraph, and game state management with a simple Finite State Machine.
Sunday, August 4, 2013
Bunny Hunters Online: The Windows Store Project
The next step is to create a project for the first platform. When writing a cross-platform piece of code you need to write to the common denominator. The easiest way to do that is to start with the most restricted platforms. For monogame, those are Windows 8 Store and Windows 8 Phone.
Right click on the Solution "Bunny Hunters Online" and chose "Add->New Project". The new project dialog should be a familiar sight. Choose MonoGame Windows Store Project. Enter "BHO Windows Store" and click OK.
You many see another annoying warning pop up. This too can be safely ignored.
This should result in the creation of a new project in the solution. This will be the actual application so it should be set as the startup project. This is done by right clicking on the project in the solution explorer and selecting "Set As Startup Project".
This project will use the xnb files created by the asset project. Unfortunately I have found no easy way to get VisualStudio2012 to do this through a reference. (If someone figures out how to add a content reference to a Monogame Windows Store project, please post it in comments.) As an alternative, what I do instead is to add links to the xnb files as content.
To do this start by right clicking on the project and selecting Add->New Folder. Name the folder Content. Now, right click on the folder and chose Add->Existing Item...
In the dialog that pops up, navigate to the BHO Solution Folder->BHO Assets->bin->Windows->Content. Group select all the files with shift-click. Then click on the arrow to the right of the ADD button at the bottom of the dialog and select Add Link.
This will add all the selected files as links in the Content folder you just created. There is one more step, however. As is, VS2012 doesn't know what to do with these files and will ignore them. We need to tell that this is game content. We do that by shift-click selecting the xnb files and then using the properties dialog beneath to set the Build Action field to Content.
Now build the entire project. This should be successful, however for a Windows Store app this is only part of the process. You need to deploy to finish it. The easiest way is to run it using the green arrow next to the wordS "Local Machine"at the top of the screen.
If all goes well you should see a grey screen with an icon in the center for a few seconds, followed by an empty blue screen.
It is possible, depending on your configuration, that deployment may fail and you may get a dialog like this instead.
Right click on the Solution "Bunny Hunters Online" and chose "Add->New Project". The new project dialog should be a familiar sight. Choose MonoGame Windows Store Project. Enter "BHO Windows Store" and click OK.
You many see another annoying warning pop up. This too can be safely ignored.
This should result in the creation of a new project in the solution. This will be the actual application so it should be set as the startup project. This is done by right clicking on the project in the solution explorer and selecting "Set As Startup Project".
This project will use the xnb files created by the asset project. Unfortunately I have found no easy way to get VisualStudio2012 to do this through a reference. (If someone figures out how to add a content reference to a Monogame Windows Store project, please post it in comments.) As an alternative, what I do instead is to add links to the xnb files as content.
To do this start by right clicking on the project and selecting Add->New Folder. Name the folder Content. Now, right click on the folder and chose Add->Existing Item...
In the dialog that pops up, navigate to the BHO Solution Folder->BHO Assets->bin->Windows->Content. Group select all the files with shift-click. Then click on the arrow to the right of the ADD button at the bottom of the dialog and select Add Link.
Now build the entire project. This should be successful, however for a Windows Store app this is only part of the process. You need to deploy to finish it. The easiest way is to run it using the green arrow next to the wordS "Local Machine"at the top of the screen.
If all goes well you should see a grey screen with an icon in the center for a few seconds, followed by an empty blue screen.
It is possible, depending on your configuration, that deployment may fail and you may get a dialog like this instead.
For security reasons, you cannot run a Metro app from a network drive. If you are doing your development on a volume shared with OSX (not a bad idea for eventual OSX project development) then Windows sees it as a network drive.
You can fix this by editing the BHO WIndows Store csproj file. One little hitch, this file is loaded when you start the project and saved back out by the system when you quit the project. So, any editing of the csproj file you do while the project is open has no effect.
You can fix this by editing the BHO WIndows Store csproj file. One little hitch, this file is loaded when you start the project and saved back out by the system when you quit the project. So, any editing of the csproj file you do while the project is open has no effect.
To properly edit a csproj file you must first unload the associated project. You do this by right-clicking on the project and selecting Unload Project from the context menu.
Next, you right click on the now unloaded project again and you will get a context menu with only a few options. Select Edit BHO Windows Store Project csproj.
This will open the csproj in the editor. Add the following lines just before the </Project> closing tag:
<PropertyGroup> <LayoutDir>C:\WorkingFolder\$(MSBuildProjectName)\$(Configuration)</LayoutDir> </PropertyGroup>
The bottom of the edited file should look something like this:
Save the edited file and right click the project again. Select "reload project" to reopen it with the new csproj. You will need to right click the project one more time and reset it as the startup project. Once this is done, click run and you should get the results described above.
Next Blog: Initializing the graphics system and bringing up the start screen.
Bunny Hunters Online: The Asset Project
The Bunny Hunters code will be organized into a set of projects. There will be one shared Asset project that all platforms references, and an individual project for each platform. All these projects will be contained in a single master Solution.
After spinning up Visual Studio 2012, the first thing to do is create the solution. You do this by clicking "new project" on the left which will bring up this dialog:
Open "other project types" on the left and select Visual Studio Solution. In the center, click on Blank Solution. Give it a name in the "Name:" field below, make sure the location is where you want your project to be (default is the standard VS2012 project directory), and click OK.
You should now see the VS2012 workbecnh, on the right side will be the Bunny Hunters Online solution:
This will contain all the projects. To begin with, we need to create a Content Project for the Assets. Right click on the solution and select add->New Project.
This will take you back to the new project dialog. This time select MonoGame and MonoGame Content Project. Give it a name of BHO Assets and click OK.
From time to time you will see this warning dialog for VS2012. Its a bit of silliness on the part of the VS2012 developers and is safe to ignore, so click OK.
You should now see two projects in your solution: BHO Assets and BHO AssetsContent (Content). If you open the "Content References" in BHOAssets you should see a reference to BHO_AssetsContent.
Unfortunately, the template doesn't create this reference quite correctly (note the little yellow icon to the left.) Trying to build assets with this project as is can be immensely frustrating as it silently fails. To fix this, first right click on the BHO_AssetsContent reference and select "remove". Then, right click on the Content References folder itself and select "Add Content Reference". A dialog will pop up with BHO AssetsContent already selected. Just click OK.
If you did all that properly your solution should now look like this. (Note that there is no longer a little yellow symbol to the left of the BHO AssetsContent reference):
The next thing to do is to add the assets. The assets can be downloaded as a zip file from BHOAssets.zip. Download them and unzip them in a temporary directory. Then go back to VisualStudio2012. Right click the BHO AssetContent project and select add->existing item.
In the dialog that comes up, navigate to where you unzipped the assets, select them all, and click Add.
Your content project should now contain all the assets and look something like this:
Its almost ready to test. However, by default the content project comes up set to build for Android.
As a convenience, lets reset it for windows. You do this by clicking the arrow to the right of the word Android and selecting Windows on the drop down.
Now its ready to test. Go to the Build option on the menu bar and select Build Solution.
It should crank for a bit, then say "Build succeeded" in the bottom left corner of the VS2012 window. To see the results, first navigate to where you created your Bunny Hunters Online solution. (If you didn't change it, its in the default VS2012 projects directory.)
Now, drill down to BHO Assets->BHO Assets->bin->Windows->Content. In that directory you should see a list of files with the extension xnb. These are the processed assets that the game will actually use. They are compressed to make better use of space on limited memory devices.
Thats it! You know have a working, cross platform asset project. Next blog, we will make use of it to start creating a Windows Store 8 game.
After spinning up Visual Studio 2012, the first thing to do is create the solution. You do this by clicking "new project" on the left which will bring up this dialog:
Open "other project types" on the left and select Visual Studio Solution. In the center, click on Blank Solution. Give it a name in the "Name:" field below, make sure the location is where you want your project to be (default is the standard VS2012 project directory), and click OK.
You should now see the VS2012 workbecnh, on the right side will be the Bunny Hunters Online solution:
This will contain all the projects. To begin with, we need to create a Content Project for the Assets. Right click on the solution and select add->New Project.
This will take you back to the new project dialog. This time select MonoGame and MonoGame Content Project. Give it a name of BHO Assets and click OK.
From time to time you will see this warning dialog for VS2012. Its a bit of silliness on the part of the VS2012 developers and is safe to ignore, so click OK.
You should now see two projects in your solution: BHO Assets and BHO AssetsContent (Content). If you open the "Content References" in BHOAssets you should see a reference to BHO_AssetsContent.
Unfortunately, the template doesn't create this reference quite correctly (note the little yellow icon to the left.) Trying to build assets with this project as is can be immensely frustrating as it silently fails. To fix this, first right click on the BHO_AssetsContent reference and select "remove". Then, right click on the Content References folder itself and select "Add Content Reference". A dialog will pop up with BHO AssetsContent already selected. Just click OK.
If you did all that properly your solution should now look like this. (Note that there is no longer a little yellow symbol to the left of the BHO AssetsContent reference):
The next thing to do is to add the assets. The assets can be downloaded as a zip file from BHOAssets.zip. Download them and unzip them in a temporary directory. Then go back to VisualStudio2012. Right click the BHO AssetContent project and select add->existing item.
Your content project should now contain all the assets and look something like this:
Its almost ready to test. However, by default the content project comes up set to build for Android.
As a convenience, lets reset it for windows. You do this by clicking the arrow to the right of the word Android and selecting Windows on the drop down.
Now its ready to test. Go to the Build option on the menu bar and select Build Solution.
It should crank for a bit, then say "Build succeeded" in the bottom left corner of the VS2012 window. To see the results, first navigate to where you created your Bunny Hunters Online solution. (If you didn't change it, its in the default VS2012 projects directory.)
Now, drill down to BHO Assets->BHO Assets->bin->Windows->Content. In that directory you should see a list of files with the extension xnb. These are the processed assets that the game will actually use. They are compressed to make better use of space on limited memory devices.
Thats it! You know have a working, cross platform asset project. Next blog, we will make use of it to start creating a Windows Store 8 game.
Subscribe to:
Posts (Atom)