Tuesday, September 22, 2009

Fun RPG Combat

see also: fun rpg combat part 2

I'm working on a retro, 2D RPG, so RPG mechanics are on my mind. I'll go into my plan and the game a bit more at some other time, but today I wanted to explore combat mechanics, and what makes for a fun RPG. But first, I want to talk about fun in general.

Fun

What makes for a fun game? What is fun? This is a big issue that game designers love talking about, but I'm not really sure why -- I think the issues are fairly straightforward. I'll lay out my thoughts and you can be the judge. :)

Let's look at boring first. Boring is when you've got nothing to do, nothing to think about. Mindless repetition is fun; the 'repetition' means you've figured out how to do a task and you're just mindlessly repeating it. Boring is mowing the grass, stuffing envelopes, fighting the same random creature encounter for the hundredth time. There's nothing about the task that's challenging. Maybe the first time, but now that you've figured it out you're just going through the motions. There's no mental or emotional commitment to the process.

Fun is the opposite of boring. But first let's ask: are there activities that aren't boring, but aren't fun? Some activities aren't boring because they require some problem-solving and/or careful attention, but aren't fun. Fun implies a positive emotional response; busy-work activities don't have that. You don't have time to let your mind wander and get bored, but there's something missing. Busy-work activities include writing uninteresting code, building uninteresting 3D models, doing your taxes. Not boring (you're too engaged to get bored), but definitely not fun.

This is pushing us towards fun, obviously. We know what sort of activities aren't fun, and in describing them it's obvious what they're missing. Intellectual interest, or emotional drive. Curiosity, achievement, happiness, social connection, fear, horror, thrill, suspense.... Horror movies and games push the fear and horror buttons; adventures like Indiana Jones go for thrill; mysteries and dramas often push suspense and curiosity. These movies and games like them are fun.

Interactivity

Games are different from other media in that they're interactive. Movies can't give viewers a sense of achievement, and (except for the camaraderie felt around the water cooler when you're talking about how much you love [insert favorite cult movie here]) can't give a sense of social connection either. Movies can pique curiosity, but they don't give you the tools to resolve it yourself. Games can try to hit the big emotional buttons that movies go after (like fear and thrill) or pique intellectual curiosity, but they can do more: they can provide challenges and reward achievement, let players build social bonds to achieve common goals, and let players explore play spaces and puzzles in their own time and way.

Games are also different because they're typically much longer than movies, and usually longer than books. RPGs, especially. There are short RPGs out there and very long books, but in general games provide far more hours of entertainment. This is a bit of a pickle, because games have to figure out how to be fun for longer than 90 minutes. It's hard enough to make a good movie, how do you make 15 hours of fun on a budget a tenth the size?

There are ways of filling time, of course. Grinding is a bad way. But what's the difference between grinding (boring!) and fun? Yeah, well, asking the question makes the answer obvious. We want games that have fun ways of filling time -- or at least, not boring ways.

Games often fluff themselves out with skill challenges. Some games are primarily skill challenges, like shooters and racing games. Others, such as platformers, focus on exploration or figuring out how to get somewhere or kill a boss mob but also contain (possibly extensive) skill challenges. Starcraft is an RTS that's packed with skill challenges on the multiplayer competetive level.

I've mentioned exploration, too, and this is a great way to extend a game. Even in territory you've already covered, you might explore a different aspect of the world -- in Left 4 Dead, you check nooks and crannies for hiding zombies. Once you've played through the campaigns a few times you know the rooms and the architecture, but you don't know where the enemy is. Some games provide rich mechanics that the player is constantly exploring, such as RTS games where players learn how different units behave and interact.

Puzzles and sims both fill gameplay time with puzzles. In obvious ways in puzzle games, but I lump sims in here because, to me, most sims are long series of specific puzzles. Where do I put the next building, what troops should I train, where do I put my resource fields? I view Transport Tycoon, one of my favorite sims, as a series of four puzzles: where do I put the station? How should I build the line around these terrain features? What consist should I run between these two towns? and finally how do I optimize traffic? The player is constantly shuttling between one puzzle and the next.

High Points and Engagement

I think there's two things that makes a game fun: emotional high points, and near-constant engagement. Basically: add big, cool moments, and avoid breaking the player out of play.

If the game gets boring, tedious, or punishing, it can break suspension of disbelief or add enough of a punishment that the player disengages from concern for his on-screen avatar. Failure itself isn't necessarily a bad thing; some games are built around constant failure, such as roguelikes and shooters. Counter Strike doesn't suck even though you 'fail' (get killed) once every few minutes. That 'failure' frames the game and defines the challenge. The player isn't concerned about totally avoiding that failure as much as he's interested in maximizing the experience between those moments. (It helps that Counter Strike provides a social experience for dead players.)

Games without disengaging moments can keep a player at the controls, but an interesting game without emotional high points is equally unfulfilling. It can serve as a distraction but isn't at the same level of "fun" as a game that provides those high points.

High points are the peaks of emotional engagement. Gaining a level in an RPG is a single moment that collects all of the emotional buildup of previous play and hands it to the player at one, big, emotionally-charged moment. In level-based games (ie map levels, like Doom or Starcraft or Mario), finishing a level is that big moment. In adventures, there's often a big puzzle that's solved in each step of the game. Game designers know all about these emotional high points; they make the effort to provide rewards to players at them. Because of that emotional weight, these are also often the moments that players remember most.

Fun games keep players engaged and provide periodic emotional high points. Players enjoy play, and fondly recall the "peak experiences" of games past.

Recommendations

Those, then, are my two recommendations to game designers: provide engagement without boredom, and put more oomph into your game's high points.

In fun rpg combat part 2, I talk about applying this problem specifically to RPGs.

Saturday, September 19, 2009

Game Tools with WinForms

I'm working on my RPG fairly actively this week. I've got maybe another week on the engine, and about that on the content, so it's close to being ready. As I implement more bits in the engine, I'm going back and changing the editor, too, so I'd figure I'd comment a bit on that here.

The RPG is retro, 2D, turn-based tactical combat, single-player, and single-character. Old school. I'm trying to make it not suck, but I'm using simple technology. It's called BlackThrone and it's up on the web so check it out.

The Editor

The editor was my very first WinForms app. I've been coding UIs and tools forever, and C++ since college, and Windows since the OS/2 days -- but C# for only a few years and barely much professionally until last year. So I was new to WinForms, and at the time was coming off of using C++ heavily for a couple years.

My point is, my god this app sucks. I didn't know about User Controls, so a half-dozen tabs, packed with dozens of controls each, are all in the main Form. The main form .cs file is HUGE. Blech. I didn't have any common methods of dealing with resources and graphics, so lots of the stuff was ad-hoc. It's interesting coming back to it now after having left it half-developed for a year.

There's a few things I wish I'd known and done then, and that's the point of this post.

UserControl

UserControl is your friend. It's basically a collection of other controls; checkboxes, lists, text entry fields, buttons, etc. It's great for taking a chunk of your UI (like the controls that would be on one tab of a control panel) and encapsulating them.

In my editor, each resource type is edited on a different tab of a TabControl. The main form contains a TabControl, and in each TabControl is a user control. This means that there's very little code in the main form.

At least, there's less now. I'm slowly refactoring the application, pulling each one of the tabs out of the main form and sticking them into user controls. This makes it much easier to ensure that I've got everything I need, didn't forget something; debugging is easier; etc etc.

Document Model

The editor actually started as just a map editor; the extra resources got shoved in. What I should have done (earlier, like when I added an editor for the second resource type) is added a document-type class.

The editor works on a set of files. The "document" is really a directory; each different type of resource is stored in a different file. One file for the world map, one file for all the towns and cities, one for dungeons, one for conversations, one for items, etc.

The main reason to pull all these in is interaction between the resources. For example, cities can contain treasure chests which can contain items. Hence, the city editor wants to get access to the list of items so that it can present that to the user. I started out hacking into the main form (which is where everything was stored) to get the item list, but even while writing that code I knew that was a fragile, ugly way to do it. I'm slowly refactoring each resource type out of that main form into the Document class.

Small Parts

This is really a generic Agile practice. Classes shouldn't be big.

One of the common functions I do is grab a tile (a 16x16 block of pixels) from my sprite sheet (which is a 256x256 image), create a Bitmap from that, and set it as the Image in a PictureBox. This is "instant feedback" that makes it easier to see which object I'm dealing with. Bad coding practice is to copy and paste these few lines of code from here to there.

My refactor was to create a TileSheet class, and add a method to that to pull a Bitmap out -- and another method to draw a tile into the current Graphics object (eg in an OnPaint event). The TileSheet itself is small -- it's a small part.

Recommendations

If you're building an indie game, I really recommend using WinForms and C# to build data editors. If you're just starting out with WinForms, I recommend reading a book first -- having an idea of the things you can do makes it easier to choose the right thing to do. I started coding first, hacking together sample code from the net. The book I eventually bought, and one I really liked, is _Pro .Net 2.0 Windows Forms and Custom Controls in C#_ by MacDonald, on Apress.

And when you do start coding, think about putting together a document model. In my day job, having a good doc model is critical for good, clean architecture, and it's the same for my home projects.

Wednesday, September 16, 2009

Loading XML data from a config file using XmlDocument

Part 1: where to save application config data under Vista
Part 2: how to save data in an XML file using XmlDocument
Part 3: this part, how to load (parse) an XML file using XmlDocument

All code samples in C#, cuz it's my drug of choice.

In the previous two parts, I covered where to save data to, and provided some sample code for creating an XmlDocument that can then be written to disk. The idea here is loading and saving application config data. For games, stuff like the user's preferred screen resolution -- which is the specific purpose I had when I dug up this code.

So let me just get straight to the code. That's why you're here, right?
const string kIntId = "ints";
const string kStrId = "strs";
const string kConfigFile = "config.xml";
private void LoadData()
{
string myAppFile = GetConfigPath() + "/" + kConfigFile;
if (!File.Exists(myAppFile))
return;

try
{
XmlDocument doc = new XmlDocument();
doc.Load(myAppFile);
XmlNode root = doc.DocumentElement;

XmlNode intsNode = root.SelectSingleNode(kIntId);
foreach (XmlNode child in intsNode.ChildNodes)
{
string key = child.LocalName;
int value = Convert.ToInt32(child.Attributes["value"].Value);
_intList[key] = value;
}

XmlNode strsNode = root.SelectSingleNode(kStrId);
foreach (XmlNode child in strsNode.ChildNodes)
{
string key = child.LocalName;
string value = child.Attributes["value"].Value;
_stringList[key] = value;
}
}
catch
{
// feh
}
}
The try/catch is there cuz you should be worried about your users being dumbasses and manually editing your config files. And/or you being a dumbass and screwing it up. Cuz that's what I did. Plus, when I changed formats, some of this stopped working.

Note that I'm using a couple constants to specify the names of the groups that I'm looking for. I do that because of Once and Only Once: mostly to keep myself from mistyping data.

I covered a way to obtain the name for the directory in which to store application data back in part 1, but here's the relevant snippet here:
private static string GetConfigPath()
{
string appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string myAppData = appData + "/MyAppName";
return myAppData;
}
This is for per-user app config data, as opposed to shared (common) config data -- both described back there in part 1.

How to save config data into an XML file

Part 1: where to save application config data
Part 2: this part, how to save data in an XML file (using XmlDocument)
Part 3: how to load (parse) an XML file

There are many different ways of working with XML files under .NET. You can hand-roll your own code, use XmlReader, use XmlDocument, use someone's third-party library, and who knows what else. I find using XmlDocument the most sensible approach -- why write my own code? I'll let someone else worry about that.

I'll just dump the code here:
public void SaveData()
{
XmlDocument doc = CreateSaveDoc();
string myAppPath = GetConfigPath();
string myAppFile = myAppPath + "/" + kConfigFile;
if (!File.Exists(myAppFile))
{
Directory.CreateDirectory(myAppPath);
}
doc.Save(myAppFile);
}

private XmlDocument CreateSaveDoc()
{
XmlDocument doc = new XmlDocument();
XmlElement root = doc.CreateElement("root");
XmlElement ints = doc.CreateElement(kIntId);
int idNum = 0;
foreach (KeyValuePair kvp in _intList)
{
string id = "int" + idNum.ToString();
++idNum;
XmlElement node = doc.CreateElement(id);
node.SetAttribute("key", kvp.Key);
node.SetAttribute("value", kvp.Value.ToString());
ints.AppendChild(node);
}
root.AppendChild(ints);
XmlElement strs = doc.CreateElement(kStrId);
int strNum = 0;
foreach (KeyValuePair kvp in _stringList)
{
string id = "str" + strNum.ToString();
++strNum;
XmlElement node = doc.CreateElement(id);
node.SetAttribute("key", kvp.Key);
node.SetAttribute("value", kvp.Value);
strs.AppendChild(node);
}
root.AppendChild(strs);
doc.AppendChild(root);
return doc;
}
I used attributes to store info, and ignored the tag names for the contained data. I think the whole 6bytes part of XML is poopy. Yes, I said it, poopy. Attributes work better for me, cuz then you get XML that looks like:

This could be shortened to:

but, well, I got it working and I stopped caring. If you implement this yourself, feel free to take that extra step.

Hmm, I say that now... ok, I went back and changed my code. This complicates loading a bit, because I now care about tags, but you'll see that in the next section. For completeness, those inner loops are now:
{
string id = kvp.Key;
XmlElement node = doc.CreateElement(id);
node.SetAttribute("value", kvp.Value);
strs.AppendChild(node);
}
Much cleaner!

Saving application config data under Vista

Part 1: this part, where to save application config data
Part 2: how to save config data in an XML file using XmlDocument
Part 3: how to load (parse) XML-based config data using XmlDocument

I was a bit frustrated at finding this info on the net. It required a bunch of searches to pull it all together. I finally got what I needed, but, you know, bitch/moan/whine and all that. So here's everything in one place!

I'm assuming you're coding in C# (or at least can read it), and using .NET. And, like, Windows? Yeah.

So, part 1 of a 3-part series: where do I put my config data?

In the olden days (ie, under XP), you could just create a "config.ini" file in the current directory, ie with no path info, and it would save it in the same location that your application's exe was located. Under Vista and User Access Control (UAC), applications by default do not have write access to the Program Files folder. Plus, that folder might not be on the C: drive, and it might not be called "Program Files". So where do you save stuff now?

The correct location is in the AppData folder for the current user -- or, if you don't want to store user-specific data, in the common AppData folder. You can get these paths using the following code:
string userAppData = Environment.GetFolderPath(
Environment.SpecialFolder.ApplicationData);
string commonAppData = Envrionment.GetFolderPath(
Environment.SpecialFolder.CommonApplicationData);
You can also hunt for the environment variable %AppData% if you want. The above is .NET friendly, so it's what I used.

I encapsulated the above into a function, which I use a couple places in my config save/load code:
private static string GetConfigPath()
{
string appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string myAppData = appData + "/MyAppName";
return myAppData;
}
Loading it requires the following:
string myAppFile = GetConfigPath() + "/" + kConfigFile;
if (!File.Exists(myAppFile))
return;
XmlDocument doc = new XmlDocument();
doc.Load(myAppFile);
// insert parsing here, see part 3
and saving it requires just a bit more work:
public void SaveData()
{
XmlDocument doc = CreateSaveDoc();
string myAppPath = GetConfigPath();
string myAppFile = myAppPath + "/" + kConfigFile;
if (!File.Exists(myAppFile))
{
Directory.CreateDirectory(myAppPath);
}
doc.Save(myAppFile);
}
In part 2, I cover storing data in an XmlDocument, and in part 3 I cover parsing data back out of an XmlDocument and into some local format.

(Apologies for the poor code formatting. Me and Blogger don't get along.)

Monday, September 14, 2009

DRM, Piracy, and Indie Games

"OMG! teh pirates stoled my gaem!!!1!"

DRM tends to suck. Whether it's the inability to transfer Kindle books (or the fact they costs the same) or the registration hassles with PC software, I think users have a dim view of it. I'm with you there. That's not my point.

On the producer side, complaints about piracy are rampant. "We lost $3 gajillion in sales last quarter due to pirates!" I hate those kinds of complaints. There might be a billion copies of your product out there, and if one does the math that comes out to $3 gajillion, but there's no way those people would have spent that much money on your product if they hadn't found a way to pirate it.

But there is an opportunity cost involved. If pirates couldn't get their warez for free, they'd wind up buying some of those products. They'd spend less on beer, pizza, and auto parts. Minors would spend less on ... what do kids do with spare cash these days? iPods and iTunes? Big Macs and funny t-shirts?

I think piracy has killed off single-player PC games. What remains is the big boys -- The Sims, perhaps. Games that require online registration get hacked, but I think the low price point of Steam titles reduces it. Diablo, although often played single-player, is still played online; that's how you get to compare your epeen to the next guy's.

What's gone are middle-market titles. Everyone and their brother bought Doom 3, but who buys those other shooters? Not the mass-market; just the diehards. The guys more likely to have a bittorrent running in the background 24/7.

That means that successful titles are online (with all the expense that brings), or so popular that they reach out beyond those comfortable with bittorrents, which again means expensive. Niche titles fight for a living and are pirated like crazy. Consoles are grossly expensive to develop for, too.

Are games getting less innovative? Yes. The market sucks. A game designer, a programmer, and an artist can't save up some spare cash and develop a game in their spare time, throw it out on the PC, and profit from it. There's not enough of a market willing to pay for something they could steal instead. Buyers save their money for the console and online titles that they have to pay for. Have a cool idea? You need to convince someone to give you $15M to develop it. Otherwise, you're SOL. Or, just building it in your spare time.

Pros aren't often hobbyists on the side. Once you've done a few years of the crazy game dev rat race, 100-hour weeks and all, you think: screw that noise. I'm working 9-5 and then going home to spend time with my family and friends.

My point is that if it were possible to make money as an indie, more people would do it.

And it is possible, just ... grossly constrained. Next time, I explore revenue possibilities.