Pixel Man Post Mortem #3
Once I had an idea and some initial levels, I needed to start rendering them out. My levels were all built to be 18×10 tiles per screen. My guy is 6×12 pixels. So I decided that each tile should ultimately be 12×12 pixels for ease. But I drew them all out where each tile was just a single pixel. However can I fix this without redrawing the levels?
So I started writing out some classes. I won’t post all of it here because it’s not all that interesting. I’m considering posting the whole project up on CodePlex at some point, but I haven’t decided if/when that’ll happen.
Anyway, back to the levels. First thing I did was create a Level class to hold some of the necessary data and constants:
public class Level
{
public const int screenWidth = 216;
public const int screenHeight = 120;
public const int tileSize = 12;
public const int tilesPerScreenX = screenWidth / tileSize;
public const int tilesPerScreenY = screenHeight / tileSize;
public static event EventHandler CompletedLevel;
enum Cell : byte
{
Empty,
Solid,
Death,
Goal
}
private readonly Texture2D texture;
private readonly Point guyStart;
private Point screen = Point.Zero;
private readonly Cell[,] collisionMap;
private Cell this[Point p]
{
get
{
if (p.X < 0 || p.X >= collisionMap.GetLength(0) ||
p.Y < 0 || p.Y >= collisionMap.GetLength(1))
return Cell.Solid;
return collisionMap[p.X, p.Y];
}
}
}
Pretty basic type stuff. We have a starting point, what screen we’re currently on, a collision map, a property to make it easier to get at the collision map later on, and a texture we’re going to use to draw the level. So now we need to create a level.
public Level(int level, Guy guy)
{
Texture2D levelTexture =
PixelManGame.Instance.Content.Load<Texture2D>(
string.Format("Levels/{0}", (level + 1)));
texture = new Texture2D(
levelTexture.GraphicsDevice,
levelTexture.Width,
levelTexture.Height);
Color[] pixels = new Color[texture.Width * texture.Height];
levelTexture.GetData(pixels);
collisionMap = new Cell[texture.Width, texture.Height];
for (int x = 0; x < texture.Width; x++)
{
for (int y = 0; y < texture.Height; y++)
{
int i = y * texture.Width + x;
if (pixels[i] == Color.Lime)
{
guyStart = new Point(x, y);
ResetGuy(guy);
pixels[i] = Color.White;
collisionMap[x, y] = Cell.Empty;
}
else if (pixels[i] == Color.Gray)
collisionMap[x, y] = Cell.Solid;
else if (pixels[i] == Color.Red)
collisionMap[x, y] = Cell.Death;
else if (pixels[i] == Color.Yellow)
collisionMap[x, y] = Cell.Goal;
else
{
pixels[i] = Color.White;
collisionMap[x, y] = Cell.Empty;
}
}
}
texture.SetData(pixels);
}
You can see a few things here.
First, I have made my game class a singleton so I can easily get the content manager anywhere in code.
Second I’m creating a copy of the loaded texture. I do this because I need to remove the green pixel where the user starts, but if the user were to play the level again, I need to know where that green pixel is. If I modified the loaded texture directly, I’d get back the modified version next time I try to load that level because of the content manager’s caching.
But otherwise that’s pretty much it. It’s a very simple loading system. Then when I go to draw my level I just have this:
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(
texture,
new Vector2(-screen.X * 216, -screen.Y * 120),
null,
Color.White,
0,
Vector2.Zero,
tileSize,
SpriteEffects.None,
0);
}
Which you can see just offsets the texture based on the current screen and scales it up by tileSize (12) to make my tiles 12×12.
Combined with my Guy class (which is just a basic sprite class that does some input stuffs), I was able to render out my game with just this. However my game rendered out at 216×120 (18 tiles wide x 12 pixels per tile, and 10 tiles high x 12 pixels per tile). While humorous and fun to play with, it wasn’t very useful on the Xbox 360 where most users (especially on SDTVs or small HDTVs) wouldn’t be able to see it at all. This is clearly a problem.
In my next post, I’ll show how I did the scaling in the game making it easy to adjust on the fly (or at least it could be) in case you wanted to do some fun things. For instance, the first build of Pixel Man used a 4x scaling in menus so you could read text, but only a 2x scaling in game to try and retain some of that humor of being super tiny. But by the end, feedback dictated that we just leave it at 4x always.
But that’s for next time.
Possibly Related Posts
(Automatically Generated)Pixel Man Post Mortem #2
Pixel Man Post Mortem #1
Pixel Man Post Mortem #5
Scaling retro sprites at build time
Pixel Man Reception
