Wool development time distribution

While developing Wool, we were measuring the time we spent working on each game part. We think it will be useful to us to help estimate better our future project development times, and the effort needed in each part of it.

Wool development time distribution

Wool development time distribution

As you can see, most of the time spent went to Betatest, Level design and Graphics Art. The only thing unexpected here was the time spent developing each level. Despite having an editor that allowed us to design one complete level from scratch in around 15 minutes, the whole process took around 1.3 hours per level (Not including playtest). That is due to level redesigns, subtle modifcations, difficulty tuning, etc.

WaaghMan November 14th, 2009 Development, Games, Wool No Comments

Little Racers networking decisions

Here are my decisions about the upcoming online mode of Little Racers.

The multiplayer section will allow players to select whether they want to play on System Link or Xbox Live. After that, the player select screen is shown (this screen will only allow profiles able to play in the selected mode: Signed In for System Link game, and Live profiles for Xbox Live game.

After this screen, there are some menu options available:

  • Host public game: Equivalent to championship mode. Each player gets points for his position at race finish, plus one extra point if he manages to get the best lap time. This mode allows the host to set some parameters, such as lap number and car class. Everyone will be able to join the game, even at mid-championship (with the handicap that it implies).
  • Host private game: Just like public game, but only friends of the host are allowed to join.
  • Quick join: This option does a search for available games and, if one or more is found, it joins to the one that offers the best network conditions. If no game is found, a game with some fixed parameters (10 races, 12 max players, random car class, no handicap) is created.
  • Find: This mode shows all created games with some info on the creation parameters, and allows the player to join one of them. I’m not implementing a search function since I don’t think there will be so many simultaneous games to make it necessary. If the online mode renders very successful and the need of a search function arises, we’ll add it.

And that’s the behaviour I’ve chosen to add for the LR online mode. I’d like to know your thoughts and suggestions about it. It’s probably too simple, other games such as Gears Of War 2 have more options and more complex quickjoin behaviour, etc. , but I think that for a game that won’t probably get more than 10 public games at the same time (that could mean around 120 players), it should be enough and there’s no need to make this section more complex.

WaaghMan April 27th, 2009 Development 4 Comments

Developing an editor (Part 1)

While Waaghman is working very hard on the Little Racers patches and updates (yes, he’s working full time on the online mode), I’m coding some tools and editors four our next games.

I already did some tools for another game that we started (and it probably won’t be finished) and it served me as a learning experience. One of the most annoying things of it was the different kind of things formed that part of a level. We had tiles, but also random geometry, player locations and some other things. The code was becoming a real mess that growed on each new iteration.

This time I’m making a generic level editor, and trying to keep the code clean. The idea is simple: a level has a size, and it can contain layers (just like in photoshop). So you can have a layer which represents a tilemap, and another one that shows the player positions, and all of them are independent.

Right now, the basic framework is done, and I’ve got some layers working. Of course, it has been designed to load and save the levels to XML. Most of the layers that are missing are just modifications of the ones I made, so it shouldn’t take long (but if I’ve learned something through the years is that everything takes more time than expected).

MilkEditor Work in Progress

MilkEditor Work in Progress

I want the editor to be easily customizable, so it can load external layer-types through dlls, so we’ll be able to use the editor on different games without compiling the full thing. It wasn’t a high priority feature, but in C# it was done in less than half an hour.

I have to say that I haven’t had much problems while developing in Windows Forms. Usually, doing this kind of app is something boring, and you end up with lots of little hacks to make the layouts work as expected. But this time, there are tiny ugly things here and there, but everything is much more clean than usual, and I’m pretty proud of it. I’m actually enjoying developing this tool.

When I finish this, there are other more ‘in-depth’ tools that I have to make. But those are really small apps to simplify some specific tasks. I’ll post about them when I have some new material to show. See you later!

Tags: ,

Soy1Bonus April 21st, 2009 Development 3 Comments

Creating 2D geometry from a line strip

During development of an old prototype that never saw the light, I found the need to create some 2D geometry from a set of points that form a line.

After searching for any algorithm that could make what I needed, with no success, I decided to develop my own.

The algorithm is very simple, it just takes a rope and a width and creates a set of vertices tha form a TriangleStrip to be rendered on screen.


        /// <summary>
        /// Triangulates a line, returning a list of vertices that form a triangle strip
        /// </summary>
        /// <param name="contour">List of points that form the line</param>
        /// <param name="width">Desired with of the geometry</param>
        /// <returns>list of vertices that form a triangle strip</returns>
        public static List<Vector2> Process(ReadOnlyCollection<Vector2> contour,float width)
        {
            List<Vector2> result = new List<Vector2>();
            Vector2 normal = Vector2.Zero ;
            // Generate vertices for each point in the line
            for (int i = 0; i < contour.Count; i++)
            {
                // First and last are special cases, the normal is calculated right away
                if (i == contour.Count - 1)
                    normal = GameMath.Normal(contour[i] - contour[i - 1]);
                else if (i == 0)
                    normal = GameMath.Normal(contour[1] - contour[0]);
                else
                {
                    // For the rest of points, determine the normal as the middle angle between the direction of the previous and next segments.
                    Vector2 delta1 = contour[i] - contour[i - 1];
                    Vector2 delta2 = contour[i + 1] - contour[i];
                    if ((delta1.Length()!=0)&amp;&amp;(delta2.Length()!=0))
                    {
                        delta1.Normalize();
                        delta2.Normalize();
                        normal = GameMath.Normal(delta1 + delta2);
                    }

                }
                // Add two vertices to the vertex list
                result.Add(contour[i] - normal * width / 2f);
                result.Add(contour[i] + normal * width / 2f);
            }
            return result;

        }
        /// <summary>
        /// Returns one normal of the 2D vector
        /// </summary>
        /// <param name="vector"></param>
        /// <returns></returns>
        public static Vector2 Normal(Vector2 line)
        {
            float x = line.X; float y = line.Y;
            Vector2 normal = new Vector2();
            if (x != 0)
            {
                normal.X = -y / x;
                normal.Y = 1 / (float)Math.Sqrt(normal.X * normal.X + 1);
                normal.Normalize();
            }
            else if (y != 0)
            {
                normal.Y = 0;
                normal.X = (line.Y<0) ? 1 : -1;
            }
            else
            {
                normal.X = 1;
                normal.Y = 0;
            }
            if (x < 0)
            {
                normal *= -1;
            }
            return normal;
        }

That code is well enough to generate a credible line in almost all situations. As for UVs, what I did was assign the even vertices the value (X,0) and odd vertices (X,1), where X is the distance elapsed since the line start.

Tags: , ,

WaaghMan March 24th, 2009 Development, XNA Programming No Comments

Problems with System.Random

Yesterday I ran a profiling tool (CLR Profiler) to see how Little Racers does with heap memory allocation, and found something strange: The log showed that class System.Random allocated around 88Mbytes of RAM during the whole execution.

The reason of this is the way the particle system works: Each particle stores only a seed to generate its random values, and a new Random is generated with that seed each time it needs to be updated (that is, on every frame). So, if we’re showing 50 particles on a frame, we’re calling new Random(seed) 50 times.

With System.Random, there was no possible workaround since it doesn’t have a method available to set the seed without recreating everything. Also, it seems to do some hard work on creation, maybe allocating the N next random numbers, I don’t know.

Anyway, I found a nice replacement called FastRandom: This class has the same interface that System.Random, so they can be easily interchanged. Also, it has a method to set the seed without having to recreate the class.

Anyway, I found a bug in the provided code, related with the methods Next(int) and Next(int,int) , it seems to store a double with the minimum value of an int and then multiply it by the desired range. It didn’t work for me, so I just replaced it with a modulus. Maybe it’s a little slower, but it works perfectly.

Tags:

WaaghMan March 11th, 2009 Development, XNA Programming No Comments

Plain XML content in XNA Content Pipeline

During the first stages of Little Racers development, I found the need of parsing XML data during the game load. The XNA Content Pipeline system includes XML Parsing, but it uses it in a very particular way. I won’t go much further in the way XNA parses XML because, to be sincere, I’ve not tried it enough to test wether it’s good or not.
My first impression was that it was too strict (probably due to optimization and type safe issues), moreover during parse I would need access to some data structures that only were available at runtime, so I preferred to store plain XML and parse it during game load.
This can be done by extending the content pipeline and adding a new type. To do this we’ll need to add two new projects to our solution.

XmlSource project

The first project we’ll create is the one which has the class that stores our xml plain text. I’ve called it XmlSource.It will have two classes in total.

XmlSource

This class is a very simple one. It simply has a string with the xml plain text:


public class XmlSource
{
public XmlSource(string xmlCode)
{
this.xmlCode = xmlCode;
}

private string xmlCode;
public string XmlCode { get { return xmlCode; } }
}

XmlSourceReader

This class extends ContentTypeReader and simply creates an XmlSource instance from its binary representation. In our case, the binary representation wil be a simple string, so the read is straightforward.


public class XmlSourceReader : ContentTypeReader<XmlSource>
{
/// <summary>
/// Loads an imported shader.
/// </summary>
protected override XmlSource Read(ContentReader input, XmlSource existingInstance)
{
string xmlData = input.ReadString();

return new XmlSource(xmlData);
}
}

With this, our first project is finished. This project is platform-independant (The Xbox needs to read the binary data) and will have to be referenced from every project that uses the XmlSource class, including the second project we’re making:

XmlSourceImporter

The second project(I called it XmlDocumentImporter) is a project of type “Content Pipeline Extension Library”. This project is referenced from the Content projects, and converts the source text file to binary data that will be saved in the .xnb files.

This project has 2 files:

XmlSourceImporter.cs

This file converts the XML source file into an XmlSource instance, that will be further converted into binary data


[ContentImporter(".xml", DisplayName = "Xml Source Importer")]
class XmlSourceImporter : ContentImporter<XmlSource>
{
public override XmlSource Import(string filename, ContentImporterContext context)
{
string sourceCode = System.IO.File.ReadAllText(filename);
return new XmlSource(sourceCode);
}
}

XmlSourceWriter.cs

This file converts an XmlSource into binary data, as opposed to XmlSourceReader


[ContentTypeWriter]
class XmlSourceWriter : ContentTypeWriter<XmlSource>
{
protected override void Write(ContentWriter output, XmlSource value)
{
/*StringWriter sw=new StringWriter();
value.Save(sw);
string content = sw.ToString();*/
output.Write(value.XmlCode);
}
public override string GetRuntimeType(TargetPlatform targetPlatform)
{
return typeof(XmlDocument).AssemblyQualifiedName;
}
public override string GetRuntimeReader(TargetPlatform targetPlatform)
{
return typeof(XmlDocumentReader).AssemblyQualifiedName;
}
}

Sample of use

Once both projects set up (remember to add reference to XmlSourceImporter from the Content project), we can add .xml files to the content project. Under “Content importer”, we’ll need to select “Xml Source importer”, instead of the default XNA one.

Once done this, the program sould compile ok. Loading XML from the program now is very easy:


XmlSource xs = Content.Load<XmlSource>(AssetName);
XmlDocument xd = new XmlDocument();
xd.LoadXml(xs.XmlCode);

I know this can be a little confusing, i’ll upload some binaries if someone asks for them.

PS: Here they are: Plain Xml Content Importer

Tags: , ,

WaaghMan March 2nd, 2009 Development, XNA Programming 3 Comments