JSEDLAK » 2008 » December

Archive for December, 2008

Training Season Has Started…

Got a trainer for Christmas (see below) and got my bike setup on it. Man is training instense on this thing! It is quite different than riding on the road, really really different. It is totally intense! If you stop pedaling, the bike just slows done a ton, and it isn’t as if you are going anywhere so why stop pedaling. So I keep pedaling and man does it wear me down quickly. I also have to figure out how to get a breeze flowing through my room so I am not just breathing in stale air. But man the trainer is going to be awesome!

How Did I Miss These?

GRAW2 was a game I was always sort of seeing how it turned out because I was such a huge fan of Ghost Recon 1 and 2. But after the first GRAW came out and playing it I just didn’t feel like giving it the time of day. Well recently I was in Best Buy and saw GRAW2 on sale for mega cheap so I picked it up. WOW! Boy did I miss a lot of fun gaming! It is essentially the same game as Ghost Recon 2 in terms of game modes with the added bonus of cover system, aggressive (albeit stupid) AI, and more explosings. Furthermore, they recreated my favorite map, Embassy, for GRAW2!!!! HORRAY!

FIFA 09 was also a game on my watch list but it soon fell off after the bigger names of the season came out. I have been on an FPS rage for a year or two now, hell even Fallout 3 is an FPS (RPG). Anyways, I was playing my brother in NHL09 and getting my rear end handed to me on a silver platter so we decided to play some FIFA 09. Boy is this game fun! The best part about FIFA is its depth. With hockey I have always felt the action was too mucky and quick to be able to inject any strategy (games, not real hockey) whereas Football games have always been about the passing and setting up that one beautiful lob or pass that gets you in perfect position for striking. Well FIFA is no different. It is fast and somewhate easy to pick up but deep enough that mastering it will take awhile. Unfortunately I only have the demo because the game is still $60. Maybe Santa will be uber nice this year?

Christmas is Coming!

Horray! I love Christmas, but not for its supposed religious background but rather because of what is has morphed in. Of course I am talking about the food! Actually, although the food is good, it is always nice to see everyone in the family. Anyways, I was doing a few shots of the tree tonight, trying to figure out what settings to use and I snapped this. I thought it looked a bit trippy…

Trippy

Innovation versus Cheap Tricks

One of the biggest problems I have with the video game industry is the lack of innovation. Time and time again I see games getting awards for something that is a cheap trick, a reinvisioning of an old tactic to fool the player into thinking something deeper is happening. This happens because someone in the company, or perhaps the collective, decides that it would be cheaper and cost effective to go the simple route. Rather than drive innovation, companies employ plays from a 30 year old playbook.

For this rant I need a target to examplify my point and for many reasons I am choosing Left 4 Dead. It urks my nerves the amount of people that think this game is a divine representation of what games could be. They throw so many undeserving awards at the game it is as if it is because Valve had something to do with it. There are many cases being made for the game but I will only focus on two: cooperative play and randomized levels.

People are claiming that Left 4 Dead is the best and most innovative cooperative game to come ever. They are pointing fingers at the situations it imposes on the players which force teammates to come to the aid of others. For instance there is an enemy that can wrangle a player, pull them away from the relative safety of the group and put them in a state where self defense is impossible. This requires the other players to drop what they are doing and help the teammate being attacked. Another example is how the death and revival system is implemented. When “killed” a player is put into a last stand position that allows other players to revive them. If revival fails, the player is put into a closet in the map for retrieval, generally after a group of enemies has been slaughtered.

The problem? This has been done before! Left 4 Dead is forcing situations that would naturally arise if the AI should have. Ever play Ghost Recon (1) coop on the hardest difficulty? Ever been in a situation where you or squadmates are pinned down? I have countless times, after all it is the reason they call it cooperative play. Coming to the assistance of teammates is part of the formula! Forcing the issue through specific enemy abilities is a horribly cheap trick.

What about the randomization? Surely it is a innovative feature that hasn’t been done before! After all, both enemy locations and guns are randomized. Hell, even what enemies appear is randomized! Sadly, this has been done before and the randomization has a very low upper bound. What I mean by this is that with any sort of randomization like this has specific locations or enemies that may or may not exist. You know going into a level that a certain amount of objects in the game may or may not exist.

It quickly turns into a game of asking “will object A be there?” rather than “what will be next?” This “innovative mechanism” has been used many times in the past, such as in Diablo II: Lord of Destruction. When you dive into the Worldstone Level 2, and 3 in Hell difficulty of D2:LoD, the enemy locations and types are randomized. The problem is the same though: there is a known set of enemy types that can or cannot exist. You will quickly run out of new, unexpected types very quickly. This isn’t innovation! This is faked non-repetitiveness, a cheap trick to make you, the player, think that the game is more than just a set of pre-defined levels.

So what is my point? Innovation should be driving new game development, not the idea of making money. Instead of the pathetic implementation of randomized objects, L4D could employ algorithms that teach the zombies to use portions of the environment as weapons. For example a tank that is spawned near metal piping learns it can use the piping as a weapon after a player accidently blows it up. It then knows that piping is a weapon and learns to rip the piping off the wall. If this is extended to a majority of the objects in the world you quickly create an environment that is completely open. Yes, the developers should be afraid of the game breaking itself but it is a risk, a necessary learning step in the name of innovation. Gamers aren’t going to care if the game originally breaks itself because they will be too frightened of what the enemies will learn next! Imagine facing a large enemy that all of a sudden sees a pile of enemies it previously disposed of, picks them up and starts chucking them at you. Now imagine facing him again; you are expecting the same thing to happen right? Except this time instead of throwing them he swings them at you because he saw you wield a bat. He has learned through example and now you are screwed. Using a gun could mean him using a gun, each tactic you use will be used against you. The world now becomes almost real…

So if you are a game developer remember immersive gameplay is created by creating deep and rich worlds, not by faking them with cheap tricks. Also remember Left 4 Dead isn’t the only case of this, I am just using it as an example because it is the perfect example. Almost every game suffers from this to a certain degree.

Managing Focus Across Different Platforms

With the upcoming release of FGF/Thrust comes the return of a more traditional GUI. One of the most problematic requirements of a large GUI system is the notion of focus. The question remains how do you efficiently determine who has focus and how do you pass focus between controls? On Windows this is incredibly easy because we have the mouse pointer. Focus is changed whenever your mouse acts on a control. What about on the Zune or the Xbox 360 though? On both of these systems their is no mouse (although Thrust supports a virtual mouse).

The answer is to look at what Thrust currently supports. What built in system supports all three systems seamlessly? (~ means some support, X means full support)

Event Zune Windows Xbox 360
Mouse   X  
Keyboard   X X
GamePad ~ X X
UniversalButton X X X

The problem is we can’t rely on each individual hardware controller being present and useable. For example we can’t rely on a keyboard being a focusing mechanism on the Xbox 360 because it isn’t a guarantee it exists. Likewise, we cannot rely on the GamePad on the Zune because of the lack of buttons.

To get to the point, the UniversalButton system was meant as a virtualization of the various hardware supported for each platform. It turns GamePad, Mouse, and Keyboard events into simple events like Up, Left, Down, Right, Select and Cancel. Because of this we can rely on it and implement a few more events.

  • TabPreviousLocal
  • TabNextLocal
  • TabPreviousGlobal
  • TabNextGlobal

You can consider local tabbing to be much like you would on a Windows form: hitting the tab key (or shift-tab) will move you from one control to another based on some order and only in the context of the global focus point (you never tab to a control in another window). The global tabbing can be considered like an Alt-Tab (or shift-alt-tab) where you can switch between windows.

So how do we implement this? We need a managing class (sorry Bjoern) to produce a bottleneck for the input events. As events are channeled through this class, it massages the data and figures out what to do. For instance if a global tab next event is received it has to switch focus to the next window in the system on the same level as the current window. If it receives a local tab event it will pass a message to the current focal point to tab to the next control.

What does this do for us? For one, it unifies the approach to focusing across all the UI subsystems. This means that a Window/Form implementation will focus in much the same way a simple screen will. Unfortunately it also means a complexity requirement for implementation developers. The age of the simple StateManager class is coming to an end. Elements on the screen now need to have a basic state for animation as well as a state for focus (or lack thereof). While it may still be possible to simply unload an element through the StateManager, the reality is that UI elements will have to do a little more management under the hood. Whether this is exposed to the user / developer is still to be decided.

A Spark of Genius?

Knowing how frameworks are designed and developed definately has its benefits. Awhile ago I spent some time looking into how DependencyObject and DependencyProperty work in WPF. Essentially, many of the properties are not simple properties but rather facades for method invocations.

Fast forward to today when I was working on Versionator, an application I am writing to help me manage my many projects’ versions. The problem is that project information files (AssemblyInfo.cs) are not straight forward in terms of parsing. They are merely text files, awkward and malformed code files in fact. To be able to support many properties so easily, I came up with a scheme to parse, manage and save the projects’ properties in the file.

What I do is parse the properties, extracting the data and storing it in a dictionary as “old values.” At the same time I create a copy of the values in a “current values” dictionary. As new values come in, I channel them through properties, then Get and Set methods which access the “current values” dictionary. When it comes time to save I have to do some management of the data based on whether or not the property was empty, non-existant or is being changed to empty. It is simple to say that it would have taken me a lot longer if I had not taken a look at WPF. So was it a spark of genius? Or just plain old learnedness?

The Code (Beware of its massive length):

?View Code CSHARP
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
using System;
using System.Collections.Generic;
using System.IO;
 
namespace FocusedGames.Versionator.Data
{
    public class ProjectInfo
    {
        public enum Properties : ushort
        {
            Title = 0,
            Description = 1,
            Company = 2,
            Product = 3,
            Copyright = 4,
            Trademark = 5,
            AssemblyVersion = 6,
            FileVersion = 7,
            Guid = 8
        }
 
        private readonly string[] lookups = new [] { "AssemblyTitle", "AssemblyDescription", "AssemblyCompany", "AssemblyProduct", "AssemblyCopyright", "AssemblyTrademark", "AssemblyVersion", "AssemblyFileVersion", "Guid" };
        private readonly Dictionary<ushort, string> propertyValues = new Dictionary<ushort, string>();
        private readonly Dictionary<ushort, string> oldValues = new Dictionary<ushort, string>();
 
        public static ProjectInfo FromFile(string filename)
        {
            return new ProjectInfo(filename);
        }
 
        public ProjectInfo()
        {
            Array enumValues = Enum.GetValues(typeof (Properties));
 
            foreach(ushort prop in enumValues)
            {
                propertyValues.Add(prop, string.Empty);
                oldValues.Add(prop, string.Empty);
            }
        }
 
        public ProjectInfo(string filename)
            : this()
        {
            Load(filename);
        }
 
        #region Getting and Setting Project Properties
        protected void SetProperty(Properties prop, string value)
        {
            propertyValues[(ushort) prop] = value;
        }
 
        protected string GetProperty(Properties prop)
        {
            string newValue = propertyValues[(ushort) prop];
 
            if(string.IsNullOrEmpty(newValue))
                return oldValues[(ushort) prop];
 
            return newValue;
        }
        #endregion
 
        #region Loading and Saving
        public void Load(string filename)
        {
            Filename = filename;
 
            string[] lines = File.ReadAllLines(Filename);
 
            Array enumValues = Enum.GetValues(typeof (Properties));
 
            foreach(ushort prop in enumValues)
            {
                Load(lines, prop);
            }
        }
 
        private void Load(string[] lines, ushort lookup)
        {
            for(int i = 0; i < lines.Length; i++)
            {
                string currentLine = lines[i];
                string searchTerm = lookups[lookup];
 
                // Get the first index of the search term
                int firstIndex = currentLine.IndexOf(searchTerm);
 
                // The property wasn't found, continue
                // through the file.
                if(firstIndex == -1)
                    continue;
 
                // Now we need to extract the data out of the string!
                string data = currentLine.Substring(firstIndex + searchTerm.Length).TrimFront("\"").TrimBack("\"");
 
                oldValues[lookup] = data;
                propertyValues[lookup] = data;
            }
        }
 
        public void Save()
        {
            string[] lines = File.ReadAllLines(Filename);
 
            Array enumValues = Enum.GetValues(typeof(Properties));
 
            foreach (ushort prop in enumValues)
                Save(lines, prop);
 
            StreamWriter sw = new StreamWriter(Filename, false);
 
            for(int i = 0; i < lines.Length; i++)
                sw.WriteLine(lines[i]);
 
            sw.Close();
        }
 
        private void Save(string[] lines, ushort prop)
        {
            for (int i = 0; i < lines.Length; i++)
            {
                string currentLine = lines[i];
                string searchTerm = lookups[prop];
 
                // Get the first index of the search term
                int firstIndex = currentLine.IndexOf(searchTerm);
 
                // The property wasn't found, continue
                // through the file.
                if (firstIndex == -1)
                    continue;
 
                string oldValueLocal = oldValues[prop];
                string newValueLocal = propertyValues[prop];
 
                // If the old value didn't exist, we can adjust the 
                // replacement mechanism to remove the "" and add
                // them back in.
                if (string.IsNullOrEmpty(oldValueLocal))
                {
                    oldValueLocal = "\"\"";
                    newValueLocal = string.Format("\"{0}\"", newValueLocal);
                }
 
                // We also need to catch people emptying strings out.
                // To do this we adjust the saving mechanism the same way.
                if(string.IsNullOrEmpty(newValueLocal))
                {
                    oldValueLocal = string.Format("\"{0}\"", oldValueLocal);
                    newValueLocal = "\"\"";
                }
 
                // Replace the old value with the new value
                if (!string.IsNullOrEmpty(newValueLocal))
                        lines[i] = lines[i].Replace(oldValueLocal, newValueLocal);
            }
        }
        #endregion
 
        public string Filename { get; private set; }
 
        public string AssemblyVersion
        {
            get { return GetProperty(Properties.AssemblyVersion); }
            set { SetProperty(Properties.AssemblyVersion, value); }
        }
 
        public string FileVersion
        {
            get { return GetProperty(Properties.FileVersion); }
            set { SetProperty(Properties.FileVersion, value); }
        }
 
        public string Title 
        {
            get { return GetProperty(Properties.Title); }
            set { SetProperty(Properties.Title, value); }
        }
 
        public string Description
        {
            get { return GetProperty(Properties.Description); }
            set { SetProperty(Properties.Description, value); }
        }
 
        public string Company
        {
            get { return GetProperty(Properties.Company); }
            set { SetProperty(Properties.Company, value); }
        }
 
        public string Product 
        {
            get { return GetProperty(Properties.Product); }
            set { SetProperty(Properties.Product, value); }
        }
 
        public string Copyright
        {
            get { return GetProperty(Properties.Copyright); }
            set { SetProperty(Properties.Copyright, value); }
        }
 
        public string Trademark
        {
            get { return GetProperty(Properties.Trademark); }
            set { SetProperty(Properties.Trademark, value); }
        }
 
        public string Guid
        {
            get { return GetProperty(Properties.Guid); }
            set { SetProperty(Properties.Guid, value); }
        }
    }
}

P.S. The code is not done, is not even close to being efficient or functionally complete. But it works!

The H in HDR

I have a bone to pick with game developers and graphics artists out there using the term HDR incorrectly. I understand the notion that a word can mean something different under two different contexts. For HDR, however, the idea and term are rooted in how a scene is lit. Whether you are using it to describe a scene in a game or a photograph the term means the same thing. The H in HDR stands for High, not Low.

I am sick of seeing articles that explain how a developer can equalize tones in a scene by increasing or decreasing the exposure for each rendered object only to end up with the addition of glowing and blurring the scene. Bloom has nothing to do with HDR, it is an entirely different concept used to simulate the effect of an object appearing overly shiny. This is commonly done by downsizing the scene, blurring it and then pushing each pixel towards dark or bright. This effect works great if you are attempting to render a lightsaber, but not if you are attempting to use HDR.

The point of HDR, or High Dynamic Range, is to equally expose different parts of a scene. For example let’s say you had a dark room with a desk. On the desk is a lamp that is lighting the top of the desk. To the right of the desk is a chair that is dimly lit by the ambient light. Using HDR in this case would allow an artist (game developer, photographer, etc) to brighten the chair while darkening the desk (or leaving it alone). You can think of HDR as corrective lighting surgery for an image of a scene.

Even Wikipedia contradicts itself on this topic:

One of the primary features of HDR is that details in a scene with a large contrast ratio are preserved. Without HDR (for the purpose of this article, low dynamic range or LDR) areas that are too dark are clipped to black and areas that are too bright are clipped to white. These are represented by the hardware as a floating point value of 0.0 and 1.0 for pure black and pure white, respectively. Graphics processor company nVIDIA summarizes one of HDRR’s features in three points[4]:

The Wiki page is stating that HDR scenes provide a mechanism for preserving the details over the entire scene regardless of current exposure. It goes on to say that without HDR, you get over and under exposure problems. The contradiction occurs in the sample image (below) which depicts HDR incorrectly. On the side that is supposedly HDR, the scene contains hot spots of over exposure, a component of a LDR (low dynamic range) scene. Fortunately the right side of the image isn’t HDR either but simply the left side without the bloom applied.

Wikipedia - HDR Comparison

It doesn’t stop there: one of the most commonly used examples is a person coming out of a tunnel. We all know the effect as we come out into the sun from being in the dark. Because our eyes adjusted to the relative darkness of the tunnel they are over compensating when they come out of the tunnel and thus it seems bright for a fraction of time. The problem is that people are attempting to use this as an example of HDR. Rather the desired effect is done through blooming (over exposing) the entire scene for a fraction of a second and then turning the exposure back down.

I am open to discussion (you will have to register to comment) to whether or not HDR means something different in terms of gaming but I will tell you right now that the term must be based on some idea. It isn’t valid for us to just use a term that has a meaning and change it because we need a word for that meaning. I am a firm believer that the term is rooted in how a scene is lit, as demonstrated by this other Wikipedia entry which actually uses 3D graphics to get the point across.

Tackling The Problem

Tackling the problem in the previous post I have decided to rely on providing more options than necessary. I have to remember that because Vodka is not client software, I have to write it as if the client software will be as simple as possible. The goal of Vodka is to give developers a way of setting up a software based CMS with great ease.

To do this, I have built in services that can be implemented and exposed via WCF as well as built in implementations of these services. If you had the binaries for Vodka, you could reference FocusedGames.Vodka.Services, create a class in a Service project and inherit from ContentService or MembershipService. After deploying the project, you can treat it like any other WCF service reference.

The original question dealt with translation services however, is it a client or server responsibility? You would generally make it client side because you may wish to get a different template for the content or change how translation is done. This is on par with most CMS software installs out there but there is a problem. Templates in the Vodka backend are treated as standard items of content. It then would require two calls to the service: one for the template and one for the content. You would also have to know how the template is extracted from the content item. This is a bad idea as it increases server load unecessarily.

The answer is simple: abstract it and keep it server side. The idea here is that the developers can plugin their own template provider into the service when setting it up. This will allow them to point to another service, a local directory or hardcoded templates. If no plugin is used, the service will continue on its standard course, grabbing the template from the standard content data store.

You may be asking why you would ever want to use a custom provider to point to a second service. Let’s say you have a ton of websites that you all want to look the same. For instance Microsoft may have microsoft.com, msdn.microsoft.com, creators.xna.com, xbox.com, et cetera and may want them to all use the same templates for items. They could use a provider to point to a single template service removing the need to change 5+ templates on 5+ servers.

Problems With Vodka

The Vodka Content Management System is a service based, multitier setup with the clients getting access to all content and member information via services. In turn, the services communicate with each other as well as their respective data stores. One of the goals of designing Vodka is to implement objects in a way that is easily extendable. To accomplish this, all content is managed in terms of the text data (XML) and its meta data (title, author, date stamps, et al).

The problem is how this data is transformed into its two main uses: HTML and .NET Objects. The question is where these transformations take place. In order to transform an XML file into HTML, the code needs access to an XSL file. The problem with this is that it too, is treated as a piece of content. It is regulated in exactly the same way with the same level of security. Thus it can be seen that this service should remain on the server. This is where it currently sits, so what is the problem?

The problem remains that it shouldn’t be a server side operation! That is slow! It requires more implementations than necessary and furthermore it builds a bad dependency on the server for specific implementation.