CCG programming — a state machine nightmare!
So, at the moment we’re working on a CCG. That’s “Collectible Card Game”, if you’re not familiar. Think Magic the Gathering, Paranoia, Legend of the Five Rings, etc. It’s always a genre I’d wanted to tackle, having been a huge MTG player in college. And, I originally was thinking that it’d be a relatively easy coding job. I mean, what’s there to do? Some cards? Some effects? Make them attack and block? Piece of cake.
Well, I was sorely mistaken. 234K and 100-something ActionScript files later, I’ve realized why it took Wizards of the Coast so long to get Magic Online to work right. How do you describe cards in data? How do you describe how and when cards affect each other? How do you write AI for a card game with a huge variety of potential play options? All of these are non-trivial questions, and require careful data and rule management to get to work right.
In the course of solving these problems, I’ve already discovered a few key concepts:
- Cards have effects. Both cards and their effects have cost. Cost is the use of resources. Resources are things like power/mana, life, or other cards (sacrifice).
- Cards have attributes. Some attributes are fixed, and some are dynamic. Attributes can be changed by other attached cards (children), or by global effects (”All Creatures are unblockable.”)
- AI is a lot easier if you have some solid functions which answer these questions: “What is the set of cards that I am allowed to play right now? (”Allowed to play” means having resources, valid turn phase, at least one valid target, etc)”, “What are all the possible valid targets for this card?”, “If I can play this card, what is the best time to play it, in terms of: how far we are into the match, how strong we are compared to our opponent, how many things populate the game board… etc.”
More on all of this in a future post.
AS3 - a few minor quibbles
For anyone that’s tried to write complicated games in Flash, Actionscript 3.0 is a godsend. Real classes and inheritance! Object-oriented programming! Display lists! Optimized bytecode! Those of us who come from a more traditional C++ background feel right at home.
However, there’s a few lingering bits of weirdness that have bothered me for a bit, and today I feel like complaining about them!
#1 Preloading
Preloading in AS3 is a nightmare. If you have to deal with assets from a Flash file it’s even worse. If you’re able to have 2 separate SWF’s, you can simply have one load the other as binary data and everything works fine. But in my line of work, we have to cram everything into one SWF file. This causes problems because your preloader code has to start running before the entire SWF is downloaded. This can create all sorts of linkage problems when trying to refer to library assets. In the Flash 9 IDE, anything that doesn’t exist in the first frame isn’t accessible via Actionscript. And anything that does exist in the first frame gets automatically loaded, before your preloader can execute. So the solution is to do a number of confusing steps: Make sure “export in first frame” is turned off for all library assets. Then, put them on the timeline, after the first frame, but don’t play that frame! Just skip over it. Then, make sure any referencing code executes after that frame you skipped, because Flash won’t find the assets via Actionscript until it’s already “seen” them on the timeline. Ugh. This is one of the reasons I’m moving to Flex.
#2 Class paths
Let’s say you want to make a class called “MyClass”. Well, it has to reside in a file called “MyClass.as”. And, the only (externally visible) class that’s allowed to be in that file is… you guessed it, “MyClass”. While this is nice for the compiler, from my experiences it increases the number of necessary files by at least 50%. It’s rather often that I’ll have a class with only a few variables in it — typically a structure for returning information from a function. Having to explicitly make new files for this sort of thing bloats the workspaceand makes it harder to group related classes together.
#3 Enums
No enums? What were they thinking? Yes, they are just fancy renamed integers — but they give you compile-time error checking. You can approximate them by typing things like “public static const ER_OK : int = 1″, but that’s just a workaround.
#4 Arrays
You have arrays, which are nice… but they can’t be typed. This is fine as long as you’re very careful to always typecast the results properly, but it’s caused me quite a few bugs. Flash 10 is supposed to add a new fixed-type (and optionally fixed-size!) array called Vector, using a slightly ungainly syntax: “var vec:Vector.<type> = new Vector.<type>();”
All that being said, it’s a very usable language, and it’s great for writing web-enabled games…
Next steps
Subterfuge is, of course, out! It has been getting positive feedback, although the general consensus is that it’s a big short and some unit upgrades would extend the gameplay. I agree with both points, and will integrate these (and other!) ideas in the sequel. It’s gotten around half a million plays so far — which, funnily enough, is about equal to the number of copies my last AAA boxed title sold. The difference is that the flash game didn’t cost $25 million to make.
Next up is a concept I’ve always wanted to do - make my own CCG. I played quite a lot of Magic: The Gathering during my college years, and was constantly amazed at its depth of gameplay. I’m going to revisit some of its core concepts (such as “land”, which adds too much of a random luck element), and take it in a more sci-fi/mystical direction. It won’t technically be CCG, since it’s not “collectible”, but who cares. At the moment I’m trying to generalize card and effect structures so that the card database can be completely expressed in XML. Hopefully I should be able to get to a beta state sometime around the end of the month.
Papervision 3D
We’re working on a new game called “Subterfuge”. It’s like Chess meets Stratego, with a sci-fi theme. The gameboard is a grid, with “buildings” which represent blocked squares. Originally it was 2D, with white squares to designate the buildings. However, I realized that it’d be cooler to to represent the gameboard in 3D, which would allow you to give a bit of parallax to the buildings. I could also do a nifty little fly-in! This all required finally getting around to examining something I’d wanted to check out for a while: Papervision 3D . It’s open-source, AS3, and reasonably mature.
The results: 3D in Flash is a clever hack. What Papervision does is essentially to use Flash’s geometry fill functions, add their own math libraries, projection and camera systems, some scene management, and then wrap it up with some object importation and material management. Sounds great! Unfortunately, due to the restrictions of Flash, it lacks a lot of the modern comforts of traditional DirectX hardware programming.
Such as — perspective texture mapping! It’s 1992 all over again! Large polygons have to be subdivided to avoid linear mapping artifacts. Oh, and there’s no z-buffer. Back to bounding-sphere sorting! And since there’s no z-buffer, you don’t get any z-testing or pixel early-out like most hardware cards today perform. Thus, overdraw matters, in a big way.
Nevertheless, what they’ve done is pretty neat. Depth of field can be faked using the Flash 9 blur shader. They’ve implemented bump mapping (!). All in all, a bit limited, and slow — but it has it’s uses. (Such as the grid in our game!)
Speaking of which, we’re just waiting on some art at the moment, and we hope to get a private beta out to sponsors next week. More news to come!
- andrew