superiorcode.com

my quest for superior code
XNA Color Formatted Text

I recently have been working on a simple “old school” rpg game for XNA. One of the features that I want to have is scrolling text for combat and other messages that are given to the player. What I am talking about might look like this:

You swing at the goblin and hit for 8 damage.

Well, there isn’t any built in method to draw text to the screen and have the colors change in one string. Pretty much the only way (or at least the easiest way) to accomplish this is to use multiple DrawString calls on the SpriteBatch. When thinking about that I didn’t think it would be a terribly difficult task, but I decided to do a google search for any already made solutions. I found an article on the XNAWiki called Inline Color Code Processing that claims to (I haven’t tried it) do the trick. When I examined it though, I found that I couldn’t be happy with their implementation. They chose to define a set number of colors and then reference them in the string using an integer index. That to me seemed very limited, and even though my project is simple, I’d rather not hard code in a bunch of colors. What I wanted is to be able to type in a color in the string and have it parse out to the color I wanted, much like HTML or BBCODE would work. The best way I could think of to do this is using HEX values, just like HTML or CSS would work. Unfortunately, getting a color from HEX is another thing that isn’t built into XNA. So, back to google and I found this blog that had the extensions I needed already worked out! Ok, fantastic, now the final piece, I just needed to write up a function to display the text. It actually ended up being pretty easy and perhaps it’s not the best implementation, but it works perfectly. To use it, you setup your string like so: “You attack the [color:#FFFF0000]goblin[/color] and hit for [color:#FF00FF00]8[/color] damage.” Of course, just as the extension is converting the HEX to actual colors, you can convert the colors to HEX when you are making the string and use some of the built in colors like Color.Red.ToHex(true).

public static void DrawColorFormattedText(SpriteBatch spriteBatch, SpriteFont font, Vector2 position, string text)
{
    Color defaultColor = Color.White;

    // only bother if we have color commands involved
    if (text.Contains("[color:"))
    {
        // how far in x to offset from position
        int currentOffset = 0;

        // example:
        // string.Format("You attempt to hit the [color:#FFFF0000]{0}[/color] but [color:{1}]MISS[/color]!",
        // currentMonster.Name, Color.Red.ToHex(true));
        string[] splits = text.Split(new string[] { "[color:" }, StringSplitOptions.RemoveEmptyEntries);
        foreach (var str in splits)
        {
            // if this section starts with a color
            if (str.StartsWith("#"))
            {
                // #AARRGGBB
                // #FFFFFFFFF
                // #123456789
                string color = str.Substring(0, 9);

                // any subsequent msgs after the [/color] tag are defaultColor
                string[] msgs = str.Substring(10).Split(new string[] { "[/color]" }, StringSplitOptions.RemoveEmptyEntries);

                // always draw [0] there should be at least one
                spriteBatch.DrawString(font, msgs[0], position + new Vector2(currentOffset, 0), color.ToColor());
                currentOffset += (int)font.MeasureString(msgs[0]).X;

                // there should only ever be one other string or none
                if(msgs.Length == 2)
                {
                    spriteBatch.DrawString(font, msgs[1], position + new Vector2(currentOffset, 0), defaultColor);
                    currentOffset += (int)font.MeasureString(msgs[1]).X;
                }
            }
            else
            {
                spriteBatch.DrawString(font, str, position + new Vector2(currentOffset, 0), defaultColor);
                currentOffset += (int)font.MeasureString(str).X;
            }
        }
    }
    else
    {
        // just draw the string as ordered
        spriteBatch.DrawString(font, text, position, defaultColor);
    }
}

And here it is, pics or it didn’t happen :)

Colored Rpg Text

.NET 4 Optional and Named Parameters

.Net 4 has been out for a couple of weeks now and I have started to delve into the new features. Now we are up to C# version 4 as well, and one of the new features that I find really exciting is Optional and Named Parameters. Being able to use optional parameters in functions is something that is built into C++ and until now has been completely missing from C#. In the past, you basically had to override a function several times in order to give the caller more options for leaving parameters out. I am surprised really that it took this long to get them in C#, but I’m glad they are here now! Since overriding functions was the only way to do it in the past, I have to wonder if behind the scenes that is all that Microsoft is doing, generating overrides for functions, perhaps someday I’ll look into that. For now let me explain briefly how these work in C# 4.0.

Much like in C++ optional parameters must come after required parameters in the parameter list:

void PrintCustomer(string name, string state, string salutation="n/a", string city="", int sales=100)

As you can see, it’s pretty simple. Just create the parameter as usual, but add the default value to it. So now you can call the function with ONLY the name and state parameters if you want to.

PrintCustomer("Bob Smith", "AZ");

Pretty cool! Previously you have had to have 4 different overrides of that function in order to accommodate all 3 of those optional parameter configurations. So just like in C++ you can call the function with or without any of the optional parameters, but in C++ you would have to go through each of them in order, you wouldn’t for example be able to define city without defining a value for salutation. This is where Named Parameters come into play. With named parameters you can specify the parameter that you want, like this:

PrintCustomer("Bob Smith", "AZ", city: "Phoenix");

Awesome! Now we have bypassed the need to have a value for salutation! Also it is good to note that you can use named parameters even for the required parameters. That way you can provide parameters to functions in any order that you want, and provide even greater readability in code. Perhaps you have 2 similarly named parameters like state and salesState, with named parameters it would be easy to understand which is which from the call of the function (though it wouldn’t be too often you’d be using string literals in your function calls).

Here is a complete VS2010 console application demonstrating this new functionality:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Net4Tests
{
    class Program
    {
        static void Main(string[] args)
        {
            PrintCustomer("Tech Co", "AZ");
            PrintCustomer("ABC Engineering", "CA", "San Diego");
            PrintCustomer("SwizzleSoft", "AZ", zip: "12345");
            PrintCustomer("Bob Smith", city: "Phoenix", state: "AZ");

            Console.ReadLine();
        }

        static void PrintCustomer(string name, string state, string city = "", string zip = "")
        {
            Console.WriteLine("{0}\t{1},{2} {3}", name, city, state, zip);
        }
    }
}
Silverlight Experiments

I haven’t stopped working on XNA game development, but I have had to take some time recently to further hone my Silverlight skills. Silverlight 4 RC was recently released and the full version should be out in a month or so, so I decided that I better start playing with it now (in reality, I should have been playing with it since the beta…).

One of the new controls that I was most excited about is the WebBrowser control. You would think that already being in a web browser, having the ability to render HTML wouldn’t be that important within Silverlight, but it is. The good news is, this will help make that much easier. The bad news is, it only works in Out of Browser mode. I assume this is per the usual security concerns that really hinder development on the web IMHO. But, once it becomes a trusted application that the user has chosen to install, then you can use it.

The following properties are the most important ones when working with the WebBrowser control:

  • Source: gets or sets the URI that should be rendered in the WebBrowser control
  • Navigate: specifies the URI that should be loaded in the control (works identical to the Source property)
  • NavigateToString: you can also display an on-the-fly generated string of HTML. This can be done using this method.

Another great new control is the RichTextBox.

This new control includes clipboard support, text formatting and BiDi (Bidirectional) text support for input and output. The control also enables applications to show rich text and allows users to input formatted text (Bold, Italic, Underline, Font family, Font size and Font color), highlighting of text, and embedded elements such as Hyperlinks and Images.

Another useful feature is Silverlight’s Drop Target API. This feature allows end users to drag & drop word documents directly in to the RichTextBox control. The control also can return Xaml allowing the format of rich text to easily be stored and retrieved.

I have created a section on this site for Silverlight Demos that I will be posting various experiments to. At the moment, there is only one, and it is Silverlight 3, but soon I will post more.

Neat Mandelbrot and Shaders

In my surfing around to learn various things for XNA I started looking into procedural textures. Of course, anything that can be generated by the computer instead of my art is great :)

One thing that I found is the Mandelbrot. After a combination of techniques from Shawn Hargreaves’ Blog and Mike’s Code Blog I was able to get something up and running. It uses HLSL shaders and does all the “rendering” on the GPU. I have yet to try it on the Xbox 360, but I think it will work. It’s pretty interesting and I’ve already learned a bunch about how Pixel Shaders work from it (which they have been a complete mystery to me before).

Here I’ll post the shader file to demonstrate my changes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#define Iterations 128

float2 Pan;
float Zoom;
float Aspect;
float2 JuliaSeed = float2(0.39, -0.2);
float2 RandomSeed = float2(0.88, 1);
float3 ColorScale = float3(4, 5, 6);

float ComputeValue(float2 v, float2 offset)
{
   float vxsquare = 0;
   float vysquare = 0;
 
   int iteration = 0;
   int lastIteration = Iterations;

   do
   {
       vxsquare = v.x * v.x;
       vysquare = v.y * v.y;
 
       v = float2(vxsquare - vysquare, v.x * v.y * 2) + offset;

       iteration++;

       if ((lastIteration == Iterations) && (vxsquare + vysquare) > 4.0)
       {
           lastIteration = iteration + 1;
       }
   }
   while (iteration < lastIteration);
     
   return (float(iteration) - (log(log(sqrt(vxsquare + vysquare))) / log(2.0))) / float(Iterations);
}

float4 Mandelbrot_PixelShader(float2 texCoord : TEXCOORD0) : COLOR0
{
   float2 v = (texCoord - 0.5) * Zoom * float2(1, Aspect) - Pan;
 
   float val = ComputeValue(v, v);

   return float4(sin(val * ColorScale.x), sin(val * ColorScale.y), sin(val * ColorScale.z), 1);
}

float4 Julia_PixelShader(float2 texCoord : TEXCOORD0) : COLOR0
{
   float2 v = (texCoord - 0.5) * Zoom * float2(1, Aspect) - Pan;
 
   float val = ComputeValue(v, JuliaSeed);

   return float4(sin(val * ColorScale.x), sin(val * ColorScale.y), sin(val * ColorScale.z), 1);
}

float4 Random_PixelShader(float2 texCoord : TEXCOORD0) : COLOR0
{
   float2 v = (texCoord - 0.5) * Zoom * float2(1, Aspect) - Pan;
 
   float val = ComputeValue(v, RandomSeed);

   return float4(sin(val * ColorScale.x), sin(val * ColorScale.y), sin(val * ColorScale.z), 1);
}

technique Mandelbrot
{
    pass
    {
        PixelShader = compile ps_3_0 Mandelbrot_PixelShader();
    }
}

technique Julia
{
   pass
   {
       PixelShader = compile ps_3_0 Julia_PixelShader();
   }
}

technique Random
{
   pass
   {
       PixelShader = compile ps_3_0 Random_PixelShader();
   }
}

As you can see, all I really did is add a RandomSeed and a new technique. In the Xna code I setup a timer so that the random seed will generate every 30 seconds, and in between that the seed will increment so you can see how it flows. I also added some keys to view the various techniques.

Here is the game code that makes all that go:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace MandlebrotTest
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;

        Effect mandelbrot;
        SpriteBatch spriteBatch;
        Texture2D dummyTexture;
        string tech = "Mandelbrot";

        Vector2 pan = new Vector2(0.25f, 0);
        float zoom = 3;

        Random rand = new Random();

        double[] speeds = { 1 / 10f, 1 / 25f, 1 / 50f, 1 / 100f, 1 / 200f, 1 / 500f, 1 / 1000f };//{1 / 100f, 1 / 50f, 1 / 25f, 1 / 10f, 1 / 5f, 1 };
        int speedIndex = 3;

        float cycleTimer = 0f;
        Vector2 randomSeed = Vector2.Zero;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            IsFixedTimeStep = true;
            TargetElapsedTime = TimeSpan.FromSeconds( speeds[speedIndex] );
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            mandelbrot = Content.Load<Effect>("Mandelbrot");

            int w = graphics.GraphicsDevice.Viewport.Width;
            int h = graphics.GraphicsDevice.Viewport.Height;

            dummyTexture = new Texture2D(graphics.GraphicsDevice, w, h, 1,
                                         TextureUsage.None, SurfaceFormat.Color);
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed ||
                Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Escape))
                this.Exit();

            GamePadState pad = GamePad.GetState(PlayerIndex.One);
            KeyboardState kb = Keyboard.GetState(PlayerIndex.One);

            // swap techniques
            if (kb.IsKeyDown(Keys.T))
                tech = "Julia";
            if (kb.IsKeyDown(Keys.R))
                tech = "Mandelbrot";
            if (kb.IsKeyDown(Keys.E))
                tech = "Random";

            cycleTimer += (float)gameTime.ElapsedGameTime.TotalMilliseconds;

            // start new random every 30 secs
            if (cycleTimer > 30000f)
            {
                randomSeed = new Vector2((float)rand.NextDouble(), -(float)rand.NextDouble());

                cycleTimer = 0.0f;
            }

            mandelbrot.Parameters["RandomSeed"].SetValue(randomSeed);

            // update seed
            randomSeed += new Vector2(-0.00075f, 0.00075f);

            if (pad.Buttons.A == ButtonState.Pressed || kb.IsKeyDown(Keys.Z))
                zoom /= 1.05f;

            if (pad.Buttons.B == ButtonState.Pressed || kb.IsKeyDown(Keys.X))
                zoom *= 1.05f;

            float panSensitivity = 0.01f * (float)Math.Log(zoom + 1);

            pan += new Vector2(pad.ThumbSticks.Left.X, -pad.ThumbSticks.Left.Y) * panSensitivity;

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            GraphicsDevice device = graphics.GraphicsDevice;

            float aspectRatio = (float)device.Viewport.Height / (float)device.Viewport.Width;

            mandelbrot.Parameters["Pan"].SetValue(pan);
            mandelbrot.Parameters["Zoom"].SetValue(zoom);
            mandelbrot.Parameters["Aspect"].SetValue(aspectRatio);

            spriteBatch.Begin(SpriteBlendMode.None, SpriteSortMode.Immediate, SaveStateMode.None);

            mandelbrot.CurrentTechnique = mandelbrot.Techniques[tech];

            mandelbrot.Begin();
            mandelbrot.CurrentTechnique.Passes[0].Begin();

            spriteBatch.Draw(dummyTexture, Vector2.Zero, Color.White);

            spriteBatch.End();
            mandelbrot.CurrentTechnique.Passes[0].End();
            mandelbrot.End();

            base.Draw(gameTime);
        }
    }
}

Of course another reason besides art that I am interested in all this is that it can be helpful for random map generation in my project (which is still under way). I’ve made some improvements on that front, and I’ll post an update on it soon.

New Project

So I’ve decided that my new focus will be on creating (and finishing!) an Xbox Live Indie Game. Since the launch of the XNA Game Studio, Microsoft has made vast improvements. When I first heard about it long ago, I didn’t really think much of it. From what I had heard you were very limited on what was actually possible to create. Now however, you can create almost full arcade games. You can use networking, 2d or 3d, and even the Xbox Live Avatars. You can create games for Windows, Zune, and Xbox. In order to deploy your project onto the Xbox360 you have to join the Creators Club. This comes with a $99/yr price tag, but since you can actually publish and sell your games, it’s worth it. So without too much hesitation, I joined.

So now the task of deciding what I should create first. I want to create something simple; as simple of a game as I can bare to do. It’s always difficult to keep things from becoming epic grand scale games. The battle against feature creep is a great one :) . The Xbox Live Indie games scene is sort of known already for “games” that are just fireplace/screensavers or massaging programs (they use the rumble feature of the controller) so I definitely want to go beyond that level. Looking at the list of games, there are a lot on there that are pretty bad. Not just in graphics, but gameplay as well (of course gameplay matters most). There are quite a few “diamonds in the rough” though, and that is what I would hope to create. I took the time to play some of the highly rated ones, such as Miner Dig DeepI MAED A GAM3 W1TH Z0MB1ES!!!1, and Solar. I was pretty impressed with them, they are all simple, but end up being very fun with their unique gameplay. I ended up purchasing Miner Dig Deep and Solar, as they are priced at 80 pts (about 1 dollar). With the audience available to the Xbox (about 10 million Live customers) even having a game that sells for 1 dollar has the potential to make quite a bit of money.

One genre that I noticed was lacking in title variety is Strategy. There are plenty of Tower Defense variant games, but that’s about it for Strategy. So I think that I will make a simple turn based strategy game. Something along the lines of Warlords or Heroes of Might and Magic, but to keep it even more simple, I’m going to try to just create the battle system. The battle system in those types of games is the most important part, and possibly the most complex, so only after that is done should I consider expanding to the army building world map type portion. Also, so that I don’t get too hung up on graphics (like I always do) I am going to use the free tiles from roguelike games.

example of the free tiles


With the use of the various tutorials and examples found online, I was able to get started fairly quickly. Here is a screenshot from a randomly generated “forest” map that I have working.

a randomly generated forest map using cellular automata

This idea came from a cave generation algorithm. It uses cellular automata to “carve” out the caves. Here I have used trees for the walls instead of rocks. First we randomly populate the grid with walls/trees. Then we make a few passes checking each cell and it’s neighbors and changing them to either a wall or a floor. It could still use some further refining, something to help remove the isolated areas. I also plan to cut the map in half and do a mirror on it, since battle maps are typically mirrored for “fairness”.

Here is the function that takes care of a single pass. I found that about 4 passes generates decent looking results.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public void GenerateCaves(int wallTile, int floorTile, int fillProbability, int r1, int r2)
{
    for (int y = 1; y < height - 1; y++)
    {
        for (int x = 1; x < width - 1; x++)
        {
            int adjCountR1 = 0;
            int adjCountR2 = 0;

            for (int i = -1; i <= 1; i++)
            {
                for (int j = -1; j <= 1; j++)
                {
                    if (grid[x + j][y + i] != floorTile)
                        adjCountR1++;
                }
            }

            for (int i = y - 2; i <= y + 2; i++)
            {
                for (int j = x - 2; j < x + 2; j++)
                {
                    if (Math.Abs(i - y) == 2 && Math.Abs(j - x) == 2)
                        continue;

                    if (i < 0 || j < 0 || i >= width || j >= height)
                        continue;

                    if (grid[i][j] != floorTile)
                        adjCountR2++;
                }
            }

            if (adjCountR1 >= r1 || adjCountR2 <= r2)
            {
                grid[x][y] = wallTile;
            }
            else
            {
                grid[x][y] = floorTile;
            }
        }
    }
}

I’ve also been working on dungeon generation using Binary Trees and QuadTrees. Hopefully not going too far off topic, I plan to use these to generate buildings and other important map areas (ruins). I’ll go more into that later…

Again blog, I have failed you…

Well here we are again several months have passed since my last post. This time at least I can say that I had a lot going on in my life that really caused me to lose focus on this blog. The good news is that all the bad stuff is over, and there was some very good stuff as well. I’m proud to say that my wife and I are celebrating our new son, Conan! He is great, I never would have imagined that I would have fell in love with him as I have. I knew I would like him, but I guess that I never expected how much.

For my Facebook friends, there are pictures, which I’m sure you have seen.

I’ve also kinda disappeared from Dungeon Hack, though I plan to someday return to it.

Anyway, now I’m back in the groove, working on game programming. I’ll post again soon with some information on my new projects.

Always Learning…

I am reminded recently in my work with the DungeonHack project that I am always learning. Just when I started to think that I was maybe more skilled in c++ than I would rate myself, I run into some major blocks. Basically having fun with pointers. So, for instance, I want the player to cast a ray out from his head that checks for collisions with other game objects. When it hits an object, it sets the player target to the object, and fires a callback event on the object.

The problem is: I have Class Player, it has a pointer to class GameEntity (target). If the object that the pointer points to gets deleted, there is no way to inform the Player to clear out the pointer reference. At least, not automatically.

So what I think I need to do, and will be working on, is have the GameEntity class track each item that references it, and when it gets deleted, notify the items that have a reference. Hopefully this won’t add too much overhead, but I think it may be the only way to really get this done.

According to wikipedia, this is a “Dangling Pointer” issue that I have run into, and as I suspected: “A popular technique to avoid dangling pointers is to use smart pointers. A smart pointer typically uses reference counting to reclaim objects.”

Interestingly, working with the DungeonHack source has greatly improved my understanding of things. I have owned the Torque game engine for many years now, yet I have never been able to wrap my head around the engine. Now that I am working with a much less complete code base I really am starting to follow it. When I run into problems like this, I look inside a working engine and see how they did it. Now I can see that they have created a smart pointer for their game entities, it tracks a list of references, and notifies them upon deletion. It just feels good to actually understand what I am looking at , and to look at a huge game engine and think “that’s really not that complex after all, it’s just a well done compilation of many simple ideas”. Anyway, just thought I’d share that it is neat to see the nuts and bolts where I could only see the whole engine before, it’s like when Neo can see the code of the matrix.

Still Hackin…

I’m still working on the DungeonHack project, and recently I’ve been given SVN commit access! Yay! This is the first open source project that I’ve ever officially been a part of. I’ve contributed several patches and actually feel like progress is being made which is always a plus. I’m glad that I’ve joined a team instead of trying to build a game by myself like I usually do.

Right now I’m working on integrating Paged Geometry grass into the engine instead of the current. This way we can use a color map to mask the grass off the roads.

Dungeon Hacking

I’ve joined the open source project DungeonHack, a FOSS game “Forged in the Spirit of Daggerfall”. Apparently at one time they planned to remake Daggerfall but are now just trying to make a modern 3D rpg game that has some of the best qualities of Daggerfall.

It took me a bit to get it all compiled, but I was able to get it up and running. They are using Python for the scripting system. I’ve never used Python before, though I’ve heard of it and seen many projects choose to use it. I was really hoping to use Google’s V8 engine for a scripting engine, but I suppose it wouldn’t hurt to learn another language. The good thing is that since it’s all open source I can mess around with it any way I like. I may even work on integrating the V8 engine in there at some point. (either on my own or convince them to use it).

My only concern with Python really is that I think that the end user has to install Python for the game to work. I suppose that isn’t really different from having to have .NET framework installed or Java or any of those, but I think that there is something that most professional games do not do. Most of the commercial titles that I play don’t need to install these, they usually have all their dependencies built in. Or maybe I just never noticed because I already had them installed.

There are several other open source libraries that the system uses: Ogre3D for graphics, Bullet for physics, OpenAL for sound, myGUI for a UI, and PagedGeometry.

Voxels!

A while ago I was really looking into Voxels and Volumetric rendering. It seemed in the research I had done at the time that this was a somewhat old technology. It didnt look like anyone was still using it, even though it still seemed to me like it was a very viable solution. Anyway, now in looking at Ogre stuff I found that someone else has created a basic Voxel engine that uses Ogre to render it. Thermite 3D is the name of the engine, using what they call PolyVox technology. Both are available via the GPL and are open source.

[youtube]qmZrdBBQThk[/youtube]

They are using it for fully destructable environments, which in themselves are very cool, but what I am thinking about is using it to create volumetric cloud systems and particle effects. Oh and the other thing that I think could become of it is actually being able to make caves. Making caves using the current standard (CSG) is one of the more challenging items. I think that there are a LOT of applications for this technology, which for some reason was usually only used for medical and scientific modelling. I think that they really have the right idea using it for games and other simulations. Plus, let’s mash-up I say, what can be created combining a 3D voxel world and the 3D browser web? Are those ridiculous early 90’s visions of the internet going to come to life?

Here are some of the voxel engines I found in the past, most from early 2000’s so that is why I thought this had died off…

http://www.advsys.net/ken/voxlap/voxlap03.htm

http://www.home.zonnet.nl/petervenis/index.htm

http://www.codermind.com/articles/Voxel-terrain-engine-building-the-terrain.html