Wednesday, June 17, 2009

Achievements/Awards - trivial?

I'm currently stuck on figuring out how to model the AI (implementing the behavior tree was only 50%^h^h^h20%^h^h10%? of the work - now I have to write and compose those behaviors into something sensible).

So I began working on something I had motivation for instead: some sort of achievement component (they can't actually be called achievements). I figured it would take a few hours at best, or maybe a day. That was 3 days ago. In total, I've probably spent about 15 hours on it. There's a lot to think about.

First, the UI:

  • The award notification that pops up/animates at the bottom of the screen
  • An awards screen that lets you see all your awards, and the ones you haven't received yet.
  • An awards summary on the player selection screen (so online players can see your awards)

Other than the standard tedious pixel-pushing, that's all pretty straightforward. I considered trying out one of the ready-made XNA achievement components found on the web. But the implementation was fairly minimal - just UI. Another one, "Goal Component", was more complete but lacked some features I wanted and didn't include source code (so if there were deal-breaking bugs, I was out of luck).




My main concern was making sure I don't block the UI thread. I don't have any background threads in my game at the moment other than some content preloading at startup. So I thought about implementing a task scheduler of some sort, until I found one made by jwatte on the XNA forums. It seemed solid (and so far so good).

I wanted the process to be as transparent as possible for the rest of my game. So here's how it works.

There is a class that describes all the awards, along with the icon that goes with them. This class also holds other persistent player data such as flags that - when combined together - may yield an award (these flags may be set across play sessions, so they need to be persisted). The class also contains the smarts for figuring out when particular flags turn into awards. I'm kind of breaking OOP principles here - the award class is doing double duty (I've lumped other persistent player data in here).

There is a DrawableGameComponent that shows the animated notifications. It's always around, so it also serves as the logic for responding to "new award" requests, and scheduling load/save tasks (IAwardService).

When a player signs in, the following happens:

  • A component is responsible for showing the StorageDevice selector for this player. It has a queue, since multiple players may get signed in at once (the device selector will be shown sequentially in this case). Having a StorageDevice connected is a precondition for doing anything awards-related.
  • The IAwardService monitors SignedInGamers until it sees a StorageDevice has been selected for one. At that point, it schedules an award LoadTask (to load persisted awards from disk)
  • At some point later, the LoadTask completes and communicates the information back to the main thread.
  • Up until this point, any "receive an award" requests have just been queued up. Before starting a SaveTask for them, we need to wait until we have completed our first LoadTask. This way the awards we know about at runtime can't stomp the awards saved on disk. They are merged the proper way.

This seems to work so far.




Next up are the other places in the UI where awards are shown. These are the two screenshots you see here. Originally I based the awards system on my PlayerProfile class. But then I realized this only exists in the context of a NetworkSession (which I use for local games too). But I want awards to be visible before you have entered the lobby. So I had to change everything to be based off of SignedInGamer (which makes much more sense).

Finally, I had to transfer award information to other network players. This was pretty straightforward - just an extra int in the "player info" I send around in the lobby.

I still need to do a little UI polish. And implement some of the remaining awards.

Thursday, June 11, 2009

Making the AI imperfect.

Once I got the basic "capture flag" AI working, I started trying to play against it. It was clearly way too perfect to even have a chance to beat. For example:

  1. It's aim was perfect, it rarely missed a shot
  2. It knew exactly when to stop shooting bullets due to overheating, so it was achieving the theoretical maximum fire power


The second point was the first one I tried to fine tune. I added a parameter on the Actor that is "ChanceOfCheckingForOverheat". Every time the AI fires a bullet, this gives us the possibility that it won't check for overheat (and thus may actually overheat and not be able to shoot for a while).

The second one was a little harder. I wanted to introduce a random offset to the angle to which the AI turned. However, my aiming behavior was constantly aiming towards the target on every update cycle. So I introduced a timer that made the AI re-aim only every once in a while (once a second). I think this more accurately models how a human aims.

So now it re-aims every second, and the Actor has a property that indicates how bad its aim is. So for more difficult AI opponents, I can give them better aim (I can also make them check for overheating more reliably).

Here is a video that demonstrates this a little bit. The gameplay is still not fun at all (which increases my worry that playing against the computer just won't be very fun). But at least the AI is less-than-perfect in an intentional way (there are still some path-finding issues that are problematic, so it's less-than-perfect in an unintentional way too).



Next I will start adding AI for the skills. This will require the notion of parallel behaviors, which I haven't yet implemented in the tree.

Monday, June 8, 2009

Behavior Trees

Over the past few weeks I've been digesting behavior trees - trying to learn all I can about them.

I finally decided I knew enough to start implementing my own. I'll go into more detail in future posts, but I'm happy with how things are coming along so far. Once I had the basic building blocks in place, it was pretty easy to cobble together a test behavior that does the following:

If the flag is available, go to it, pick it up, and bring it back home (and drop it). If someone else has the flag, try to kill them.

Once you've got the building blocks in place, you basically have a "language" through which you can build behavior. Kind of neat to see it coming together.

I quickly realized that assembling these trees in code was way to complicated though. After toying around with various options for UI, I settled on a small Winforms app in which I manually bind the UI to the behavior tree hierarchy. There is a little bit of tedious UI work to get this up and running, but I decided it was a more prudent option at this point than learning about WPF databinding.

The result is what you see in the linked photo (that screenshot is the behavior for the AI I described above). I'm able to add/remove/re-arrange the nodes, set parameters on them, and save this out to an XML file which can be deserialized by the game.

I haven't done this yet, but it should be straightforward to have the game "hot load" the AI as I make changes in the editor.

Now *all* I need to do is write the AI, and fix all the design issues I haven't forseen.

I need to think about/implement:
  • target selection
  • memory
  • behavior vtables to aid in the re-use of certain subtrees


Sunday, June 7, 2009

More game reviews

Just some more notes on what I liked or didn't like for some games that caught my eye.

Project Alpha
  • No music during the intro
  • Trial mode makes me choose a storage device even though you can't save games
  • I am confronted with a big screen of controls
  • The font is hard to read in places
  • Text appears on top of each other in places
  • The sound levels are very inconsistent
  • A few bugs (when I try to resume the game (with no saved game), things flash and I get the same error message back.

I looks like there may be some deep gameplay here, but the game is a bit confusing and doesn't feel very polished.

Spy Chameleon

  • Trial mode makes me choose a storage device
  • It is very bright and cheery
  • The art is basic - definitely "dev art", like my game.
  • Fairly clever gameplay mechanic
  • Introduces you gradually, which is nice

Overall I liked this simple game. For what it is, it seems fairly polished, though it isn't really the kind of game I would play.

Fittest

  • Made me choose a storage device
  • The difficulty ramps up nicely
  • Graphics are basic but good
  • The music is a little annoying

It lacks a little polish. The main menu, however, is fairly slick. This just makes the rest of the game feel under-polished.