I have to admit it, I like good code. By good code, I mean event models, design patterns, Hungarian Notation and all that assorted zarjazz (a Jeff Minterism for all you old schoolers). I like it especially as it applies to game programming. I wasn't always like this, and I completely understand that good game code and optimized game code are more than often not diametrically opposed. So, I have made many efforts to create optimized game rendering engines (optimized game code) while implementing these good code practices. It has taken me a long time to get here, and now that I am, I'm not completely convinced I should or need to be here. So, I have decided to do a speed test with my preferred rendering engine using good code practices against a stripped down model. I am sure this down and dirty model is going to win, but by how much? I don't know, but I really want to find out. For some reason, I need to do this, and if you are interested, read further for the results.
I started making games in basic on the Apple IIe and Atari 800 in 1980. I was only 10 years old and admittedly, I had no fucking idea what I was doing. There were no user created functions other than the use of gosub and goto statements in the Apple and Atari versions of basic,. All of my game code resembled the over used, but accurate term, spaghetti. When I started to program in GFA Basic and STOS on the Atari ST, I was introduced to better procedural coding structures, but I was too uneducated to understand exactly how to properly implement the new tools in my arsenal. My code improved, but I am sure if I looked at it today, I would be horrified. At the same time I was learning Cobol, Object Vision, and object oriented design in some advanced college classes, but I never thought to apply those principles to my micro computer game programming.
After college, I fumbled around making games in C and Perl in Unix, and C++ on the PC, but all of these games were just slightly more organized and sophisticated than my earlier efforts. In 1996, I started making some real money coding early ASP in vbscript, and Perl 5 in Unix. I had to set games aside for a few years (I did do a couple in pure HTML and ASP Tic Tac Toe like games - ouch!) Client projects were coming at such a rapid rate that I never had a chance to take advantage of the formal coding structures (those that existed at least) in Microsoft's early web development system. I did write procedural code with methods, etc, but formal design patterns were beyond my sphere of interest or knowledge. Even when I was forced into Java, C#, and early Actionscript 1.0, I shied away from anything too sophisticated because time was of the essence. At that time, no one had any experience, and we were all fumbling our way into this. Iinexperienced designers always delivered late, unorganized assets and truly awful .fla files. Because of this, fast and easy code became the order of the day. Plus, clients had deadlines - realistic or unrealistic - and those needed to be met.
In 2000, I began to collect and read as many books on game design and programming as I could get my hands on. The best ones were written with C++ or Java in mind (with the exception of the excellent Jobe Makar Actionscript books). They all had discussions of design patterns and good object oriented practices (See Game Programming Gems). With those fresh in my mind, I decided to finally get up on that horse and make my games and apps with at least a subset of formal design patterns and object oriented practices. I designed a couple game engines and found that I really like the State Machine pattern when applied to games and AI. I have also found that an event driven message and update model can really save time and creates some very elegant code. You know what? I loved it, and my code started to become good, not great, but pretty good. When I opened up my source code files, they were filled with great comments, properly named variables, and simple methods that accomplished a single task. I also had class files and packages full of inheritance, polymorphism and abstraction. I was not an expert, but I was getting to be at least a knowledgable hacker. Still, Flash games don't necessarily lend themselves to this type of code, and very few examples of games with good code were available for the novice / intermediate level game programmer to look at.
Ever since, I have been searching for the RIGHT way to program a game. What I have found it that there really is no RIGHT way. There are a lot of good ways, but there are also trade offs at every corner. If I want to have good code, it might run slightly slower than code optimized for games. So what? Well, in Flash, we need every millisecond and every Frame Per Second squeezed out to make games fun to play with nice AI, physics, collision detection, and difficulty. Plus, we want them to be rendered fast. What to do?
When I began my efforts to create optimized arcade game clones and updates in Flash, it because necessary for me to create optimized bitmap rendering techniques well before any were documented on web sites, etc. Since I was entering uncharted Flash waters, I referenced some of my books written for other languages, and all of them used sprite sheets and even arrays of bitmap data for quickly updating sprite surfaces to do animation. With the Flash vector engine being so slow to update all of the points necessary to re-created 80's action games, I transported some of the Java and C++ ideas to my game, Retro Blaster. In that game, while I had a new, pretty sophisticated rendering engine, I still used loops and method calls instead of a formal event model. I implemented a formal objected oriented structure though. This made the game code clean and easy to follow and update. I found that I lost some sheer horsepower with this formal class structure. But, I decided not to go back because I wanted good code. The game came out fine, but it was slightly slower in some places than I would have wanted. When I decided to make a new game engine in AS3, I wanted to implement everything I had left out of the AS2 version - Event Models, State machines, and an even better, improved rendering engine. With AS3 supposedly 10-100X faster in execution (not rendering) speed than AS2, I assumed that adding all of my favorite formal coding structures wouldn't hurt, would it?
I few days ago, I published a speed test article where I timed execution speed and frame rate counts for a number of different Actionscript 3 rendering practices. I segmented the test between event and looping method call models and found that the looping method call model was slightly faster. I was able to get 15,000 game objects on the screen with both models, using an array to hold the BitmapData frames of animation for each object (using a shared reference for each of the 15,000). All of the objects render themselves with copyPixels to a single display object canvas. At lower object counts (1000 and under), the single display object canvas took much more time to process and execute than the rendering models where each object is responsible for rendering its own sprite to the screen. But, the models that render objects to the screen with individual sprites also crapped out at anything over 5000 on screen objects. While the SLOWER to execute, single canvas render models could with 15000 and beyond. What does this tell me? That execution speed and frame rate are not as tied as I once thought, also, there isn't one RIGHT choice if my game is going have fewer than 1000 objects on the screen. Although higher frame rates are possible with some models, they also use up precious cycles that might be used for other game activities.
One test I left out completely, was a speed test where I run the stripped down code. This is where the entire process runs from a single class without classes for other objects. No getters. no setters, only generic objects and functions that take objects as parameters and work on them as a reference. I have not created a game like this in years, so I completely forgot to test this one. So, here it is, Good Code vs. Optimized Code, I am almost certain the optimized version will have a higher frame rate, lower memory usage, and faster execution times, but how much faster? Is my good code worth doing at all?
|Model - Stripped down|
|A single class||Number of objects|
|Render (frame rate) Peak||125||125||102||27||14||10|
|Render (frame rate) Avg||124||124||101||26||13||9|
|Model Times Peak|
|Model Times Avg|
The best frame rate I was able to achieve using the same render engine, but with an more formal object oriented structure was 8 FP. With the stripped down model I am able to squeeze out one more frame and get an average of 9 FPS. So, it seems that I cannot squeeze out too many more frames because the rendering engine is pretty solid already. At this low a frame rate though, every frame counts and this is an 11% improvement.
My previous best average execution time for updating and rendering 15000 objects was 123 milliseconds. With this stripped down engine, my average is 107.936. This is a 12% improvement.
Object Creation Time
My previous best one time object creation time for 15,000 objects was 402 milliseconds. AS you can see above, this is where the stripped down model really shines. It takes only 161 milliseconds to create and initialize 15,000 generic objects. This is a a 249% improvement!
Memory usage is also a place where the stripped down version clearly outshines the object oriented version. Previously, 17211 KBytes was the least amount memory used for 15,000 objects. With the new stripped down engine, I use only 7356 KBytes. This is a 233% improvement.
Overall winner: Optimized Code (Stripped Down engine)
What does this all mean?
Well, the rendering performance difference is not enough to make my feel I have to switch away from my Good Code to more efficient game code. I do like the improvements in execution time, and especially memory usage and object creation time though. I guess it all depends on the type of game I am going to make. I love Object Oriented Design Pattern code and how reusable and time efficient it is (from a development standpoint). I can't imagine making a game with absolutely no events or formal object structure because to me it would become a spaghetti mess very soon. Once the engine demo is done, all of the necessary evils in actually making a real game would get in the way. To me, there is no better way to handle things like sounds and music than with a singleton Sound manager class. The same goes for in-game rendered messages, screens, level data, tile data, etc. But, with this new information,when I start to design my GameLoop, I will think twice before I make formal classes for games objects that need high speed rendering.
If you want to test out Speedtest2 on your machine, be my guest. In the browser you can run the test below (your FPS will max out at about 60), and the swf file is available below for you to try from your desktop.
You can download the .swf file here