Sunday, February 5, 2012

Xna Platformer Update

Hey guys here is a quick update on my platformer game. I've been able to add in some decent player physics, modeled after the Platformer Starter Kit on the Xna website. I've also spent most of my time on the editor lately, getting it up to speed with my engine and designing it in such a way that I will be able to create platformer games much quicker than just hard-coding in the levels for this one game.

 

Thanks for taking the time to check up on my game. I'm really looking forward to developing the engine and editor even more. One of the things I'm in the process of adding is a dedicated object layer for the maps. Right now, the only thing on that object layer (which is loaded in from a file by the way) is the player. Most likely, the next thing I will add to the layer is an exit tile, which will load up the next level (tile map in my case). This, I feel, will make the game start to feel more like an actual game than just a level demo.

Stay tuned for more updates!

Thursday, February 2, 2012

Loading Objects from a File

Hey guys, so I just finished getting object loading to work in my platformer game and I thought I would share some code with you and explain my technique. I realize there are probably a hundred ways to do this and do it better, but this is just my first iteration for this method. As the game progresses I fully expect to go back and make this loading code more efficient.

This method is based off of Nick Gravelyn's Tile Engine series where he loads in basic Tile Layers for his map. I take his method and expand upon it to include a dedicated layer of the map for objects (i.e. players, npcs, items, chests, portals, etc). I'll show you the code first and then explain it.

private static ObjectLayer ProcessFile(ContentManager content, string fileName)
{
    ObjectLayer objectLayer;
    List<List<int>> tempLayout = new List<List<int>>();
    string playerTexture = null;

    using (StreamReader reader = new StreamReader(fileName))
    {
        bool readingLayout = false;
        bool readingPlayer = false;

        while (!reader.EndOfStream)
        {
            string line = reader.ReadLine().Trim();

            if (string.IsNullOrEmpty(line))
                continue;

            if (line.Contains("[Player]"))
            {
                readingPlayer = true;
                readingLayout = false;
            }
            if (line.Contains("[Layout]"))
            {
                readingLayout = true;
                readingPlayer = false;
            }
            else if (readingPlayer)
            {
                playerTexture = reader.ReadLine();
            }
            else if (readingLayout)
            {
                List<int> row = new List<int>();

                string[] cells = line.Split(' ');

                foreach (string c in cells)
                {
                    if (!string.IsNullOrEmpty(c))
                        row.Add(int.Parse(c));
                }

                tempLayout.Add(row);
            }
        }
    }

    int width = tempLayout[0].Count;
    int height = tempLayout.Count;

    objectLayer = new ObjectLayer(width, height);
            
    for (int y = 0; y < height; y++)
    {
        for (int x = 0; x < width; x++)
        {
            objectLayer.SetCellIndex(x, y, tempLayout[y][x]);
            switch (objectLayer.GetCellIndex(x, y))
            {
                case 1:
                    objectLayer.player = new Player(content.Load<Texture2D>(playerTexture));
                    objectLayer.player.Position = new Vector2(x * Engine.TileWidth,
                                                                y * Engine.TileHeight);
                    objectLayer.player.OriginOffset = new Vector2(32, 64); // NEED TO NOT HARDCODE THESE VALUES
                    break;
                case 0:
                    break;
            }
        }
    }

    return objectLayer;
}

The first thing we do here is declare our List<List<int>> for our tempLayout of the map layer. This will allow us to read in each cell of the map from our file. I also declare a string for the player's Texture because the constructor for the player requires a Texture2D and I can't access objectLayer.player until after objectLayer has been instantiated. After the playerTexture, we declare that we're using the StreamReader class and begin reading in our file.

First off inside the while loop we read the first line of the file with string line = reader.ReadLine().Trim();. This reads in the first line of the ObjectLayer file. Here is that file for reference:

[Player]
Sprites/playerSheet

[Layout]
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0


As you can see, the first line is "[Player]". This sets the "readingPlayer" variable to true and moves to the "if (readingPlayer)" section of the loop. We then simply read in the path to the player's texture file. Next we move onto reading in the Layout of the map.

This section is very similar to Nick's method, except that after we read in the map to the tempLayout list of list<int>, we loop through the map to do two things. The first is to set each cell index, and the second to run a switch statement on each cell, which at this point only recognizes and looks for a '1' (the player starting cell). Once we have found the player starting cell, we instantiate the objectLayer's player variable and set it's position to that of the cell where it was located in the objectLayer's map.

We use this method in our game1.cs file where we call:

tileMap.ObjectLayer = ObjectLayer.FromFile(Content, "Content/Layers/Objects.olayer");

This line of code is identical to the method used in Nick's Tile Engine, except it is a type ObjectLayer instead of TileLayer. I hope this has been fairly easy to understand, but I understand if it is a lot of code to take in. If you are confused, please read over the code a few times and really ask yourself what each piece is doing. As always, I am willing to answer basic questions about this code and will try to help you out as best I can. Please leave me a comment if you have a question you simply cannot find the answer to.

Until next time!

Wednesday, February 1, 2012

Prospectus Xna Relaunch

Hello everyone, I have exciting news to bring you today! I finally have discovered a way to make Prospectus available to everyone and utilize the ClickOnce feature which will allow for Prospectus to automatically update itself whenever a newer version is available.

My solution actually came about because I recently have been poking around on the dreamincode.net site and have become involved in a project that is hosted on CodePlex.com. Ironically enough, I was digging through their web site today and discovered that ClickOnce applications actually work on that site (my guess is because it is owned by Microsoft, but that may be incorrect).

Anyway, setting up the project was easy and I have uploaded the Alpha 1.0 version here. If you are a fan of the game, please stop by and download a copy (for free) of Prospectus, and it will update itself whenever I provide updates (pretty cool, huh?). Again, thanks for everyone who has followed along with this project and I do apologize for going so long without an update...and yes, for those of you wondering, this does mean that I'm back to using Xna for the development of Prospectus (let's face it, I love programming in C#)

Until next time!