|Click to Play Starship!|
Look, I'm early for my annual blog post! I suppose I've always preferred coding to writing. But here I hope to share some of my experiences in building this game with you.
While I hope this game is fun for at least 3 - 5 minutes, this is more of a tech demo. This is what I do for fun, and I promised myself I would finish it before opening Skyrim, which is sitting next to my XBox 360 unopened as I write this.
Edit: I've added a section on CPU usage.
Edit: Made asteroids cause damage on impact.
Edit: Allowed asteroids to be destroyed while only the first (red ship) exists while waiting, to celebrate Ed Logg's recent award: http://www.wired.com/gamelife/2011/11/ed-logg-pioneer-award/
Why Flash? Isn't it dead?
First and foremost... why Flash in this HTML5 era? Isn't Flash dead? Well, I don't want to get too political, but I'll just say it isn't yet. I'm pretty certain that HTML5 will eventually evolve into a platform that allows for pretty much everything Flash can do, and possibly more, and maybe even better. With the momentum behind HTML5, it's hard to bet against it. But it's not there yet.
This game is Flash. I actually believe it would be quite a challenge to build this game in HTML5 today due to some of the unique characteristics... see below for more (in particular the graphics and sound sections).
The Game: "Starship" (super original)
- You play the role of a starship, which is probably actually manned by a crew of 2 - 4.
- It is armed with a combination of a "phaser-like" energy weapon and projectiles.
- Your defenses include both shields and thick armor.
- Energy weapons do more damage to shields, and projectiles do more damage to armor. Effective use of both is required to defeat the other starships.
- You fly around at pretty rapid speeds using thrusters, retro-thrusters and maneuvering jets.
- The galaxy is endless... not like Asteroids endless where it just wraps around the screen... this is a massive pixelspace that you fly around in a spherical route. A math savvy friend of mine tells me that it's actually a torus, but I don't believe so. Not exactly. It's not a true sphere, but given how this is implemented it's not a torus either... some simple origami will settle the debate! Regardless... you won't find boundaries here.
- The galaxy is riddled with
indestructibleasteroids! But worry not, your Starship is equipped with advanced equipment to keep you from slamming into them. In other words, I couldn't decide on an adequate game mechanic: Should asteroids be ultimately deadly, destructible, or what? So I went with "galactic nuisance".I've now upgraded the asteroids from galactic nuisance to legitimate danger. They will damage your shields and armor, large ones do more damage. Asteroids can be destroyed with projectiles while only the first (red) ship is active (while you're waiting for opponents -- to give you something to do). :-)
- Up to four other players man Starships of equal power, but different in color.
- Even though I just described the galaxy as massive and endless, it's not big enough for the five of you.
- So shoot them.
- Or you can bump into them to disrupt them, which will trigger their ships collision avoidance system and you'll "bounce" around a bit.
- When you destroy an enemy (or are destroyed yourself), along comes your backup in the form of a respawned ship, good as new (which reminds me, I should probably reset the shields and armor on the winner's ship)
- The controls are laptop friendly and for lefties and normal people. :-)
- WASD -or- OKL; -or- Arrow Keys will move you.
- Up and Down control your thrusters.
- Right and left rotate the ship with your maneuvering jets.
- Space Bar or either Control (CTRL) key will fire your energy weapons.
- Either Shift key will fire your projectiles.
- Your HUD encircles your ship
- The blue circle represents your shield status
- The red circle represents your armor status
- Your HUD also includes a radar that surrounds the game window. Asteroids are tracked as grey semi-circles, and ships are tracked as larger colored semi-circles that match the ship.
- Upon opening the game, or if the flash player or browser loses focus, these instructions will appear on the title screen.
- If the controls aren't responding, just click in the Flash Player to give it focus.
The Game Lifecycle
- The game will fill up "rooms" with people as they arrive. I'm sure there will be millions of people playing this game, so you shouldn't have problems finding an opponent.... but really you should BYOF (Bring Your Own Friends).
- If you're the first person to arrive, the game will wait indefinitely (well actually 30 minutes... but if you stick around for longer than 30 minutes shooting at indestructible asteroids....).
- Once at least one more ship joins, then the room will only wait for another 30 seconds before closing the doors to new opponents.
- Currently this approach might make it hard to get together a party if this does become popular, but I was erring on the side of it not becoming the next Angry Birds.
- If you really have no friends, you can just refresh your browser a couple of times and you'll see the room spawn a new ship each time in the room you're in. So you have some orphaned ships to shoot at (note: IE9 doesn't refresh Flash state -- which is actually good if you're watching a video -- but for gaming, you'll want to close the browser and reopen it).
Okay, now that you know how the game works and have spent 23 seconds playing it... here's what makes it cool IMHO...
This is pretty responsive, real-time-ish, PVP multiplayer in a browser via HTTP. Now for a lot of my friends who are really good at what they do, this may not seem too impressive.
"Pffft. Some comet, some streaming, and some other stuff etc." ~friend
But really... how many real-time-ish (not turn based) in-browser, HTTP based, PVP combat games have you seen online? I was really curious myself to see how well it would work out. With HTML5 and WebSockets, this world should get a lot better. But right now, this game employs some pretty heavy abuse of plain old HTTP. A persistent HTTP connection is used for receiving the remote game states, while individual requests are used for updating the status.
I didn't use any frameworks for this. I really wanted to learn how this stuff works. So the client connector, protocol and server are all hand-coded.
Each player's ship sends its commands (intentions) and current state (according to this one client) to the server. I didn't go too crazy with anti-cheat detection. That part seemed relatively easy to me, since the entire set of game logic could be run on the server side, to ensure nobody is warping their ships around etc. Until people start playing this for real money (or virtual Zynga goods), I don't think I'll worry too much (but more on this later in the collisions discussion).
The asteroids are synced differently, based on a simple time protocol. Every asteroid you see in one game window should be in relatively the same place as any other game window in that same room. But each asteroid's starting position, speed and direction are all randomly set. The server simply sends back the age of the room, and the current location of the asteroid is calculated based on that synced time, so even latecomers to the room will see asteroids in the proper position.
Visually, every single star, asteroid, and ship should be placed exactly with only minor errors for latency -- but even that is predicted and calculated out as best as I could. Projectiles are not synced, but given that everything else is, it's a pretty safe bet. There's a remote possibility of the odd extra projectile slipping by, and if there were more serious consequences (like if you had paid real money for your Starship), I would probably sync those too.
Latency is tested and used to help avoid too much stuttering in the game, which I think worked out pretty well. During regular game play, there's next to no jittering (except on collisions... but more on that later).
Remember, this is HTTP syncing... not UDP over a dedicated socket.
Collisions: Detection vs. Reaction
Flash has built-in support for collision detection, but according to many, it's entry level at best. It may have been good enough for this game, but I figured I might as well invest in it a bit. So in invested 30 seconds in Google Search and came up with Corey O'Neil's cool little MIT Licensed Collision Detection Kit (CDK). It had a pretty nice API for detecting collisions in a field of potential objects (like ships, asteroids, projectiles and energy weapons). So collision detection became fairly simple.
Projectiles, energy weapons, damage and all that stuff was easy.
However, I soon learned that I should have attended a few more of Mr. Lajoie's Physics classes -- because ship-to-ship and ship-to-asteroid collisions were difficult. The detection was easy, but the reaction to a collision detection became a bit of a challenge.
For smoothness the game has to predict events and play them through, potentially before it receives such state from the server. For general movement this isn't too bad. But collisions have so much going on, and there can even be multiple parties involved in the collision -- all with different state arriving at different times. So the net result of the collision reactions was absolute chaos.
Looking at just one screen at a time, it's only moderately bad. But if you watch more than one at a time (DON'T -- okay now you will), you will witness a total sync meltdown. If people are shooting and such during these events, I'm sure those phantom projectiles will not be so uncommon anymore.
I'm sure the big game studios know exactly what to do and how to deal with this. Short of having the server decide upon it all, and just send the state to the client, I can't think of a magical solution. Since I have not implemented the server-side physics, you will see these anomalies.
Unfortunately the asteroids were one of the last things I added, and the problem was not so severe without them. In hindsight, if I were to ever do this again, I'd go 100% server side "decision", with only client side "intention" -- which is probably the "right" way to do all of this anyway. My learning experience was more client focused though, so the server side is light (I've been doing server side for 13 years-ish).
I don't own Flash Professional, nor do I know how to use it, nor am I an artist. I used the free Adobe MXML compiler that comes with the Flex SDK -- but there is no Flex here... The main class is just a Sprite, and it's all Sprites and domain classes from there.
All of the animation and movement is hand-coded. It worked out pretty smooth and clean... but network latency and syncing can make it jitter from time to time (not usually noticeable with regular game play).
The game uses a combination of vector and bitmap graphics. Vector is used for the stars, radar, projectiles and energy weapons. Bitmaps (PNG sourced) are used for the ship, asteroids, explosions.
This is one area I wonder about with HTML5. The ability to use both bitmap and vector graphics was important here. I wanted bitmap style artwork (although the current ship art doesn't warrant it, the asteroids and explosions totally do). In HTML5 you have SVG and Canvas. Two completely separate specs, standards and APIs... Can the canvas be transparent and on top of an SVG container? Or vice versa? I used vector for projectiles and bitmap for ships though... and collision detection works great between them. I hardly doubt the same will be true in HTML5.
So why use vector graphics at all? Well... The equivalent size of the starfield in this game is the effective equivalent of 225,000,000 pixels. With a 32 bit pixel (4 bytes), that's 900MB of bitmap data -- a little too much to be working with in a browser or across a wire. But vector graphics don't need to store all of that. They are what is called a "retained mode" format, which means it just knows where stuff should be and what it should look like based on some instructions, calculations, filters and rules (to put it simply).
Why use bitmap graphics at all? Well, pure vector graphics lack detail that bitmap can provide. While it may not show in the ship in this game, it certainly shows in the asteroids and the explosions. I'll try to find a better ship to show it off.
The combination of both was indeed powerful. Of course it's not impossible to make this work purely with bitmaps using a tile-based approach (think Google Maps), it will certainly be far more work and still more memory intensive. Plus, remember that the star field itself is randomly generated and parallaxing. So with bitmap you'd actually need to generate (on the fly) two layers of bitmaps, doubling the data size.
My favorite part of how this game turned out is the music. Sure, it would be simple to play MP3 in Flash or even with the audio tag in HTML5 (when it works... many HTML5 games -- including Google Pac-Man and the more recent Google guitar fall back to Flash for audio).
But this entire game is 686KB. That includes all of the code, art assets AND the music. If you sit with the game open for a bit, you'll find that there's about 8 minutes of music made up of 5 tracks, randomly ordered each time you play. So the music doesn't get too repetitive. 8 minutes of MP3 even at a low quality would be many times the size of the entire game.
Sure, we all have broadband, and we can stream the MP3 to avoid having to download it all at once. But this entire game is smaller than the Facebook homepage (just the HTML). Am I the only one that finds that awesome? Maybe I'm just old and remember floppy disks that couldn't store the Facebook homepage and a time when screenshots of a game were larger than the game. :-)
In any case, for the music I use something I found in the trash bin of one famous and fully respect-worthy Andre Michelle. If you don't know who he is, Google him. This guy's trash was my treasure in the form of one 8BitBoy MOD player.
If you're unfamiliar with MOD and related formats... see The Mod Archive.
One of the biggest criticisms of Flash is that it is a CPU hog. This is largely due to the fact that Flash doesn't use the graphics card. The reason is that by limiting it to CPU, Flash can ensure a more consistent user experience (not different depending on your graphics hardware), but this comes at the cost of performance. Adobe has released Stage3D which has hardware accelleration support, and it's pretty impressive. I have not tried it yet.
In a nutshell though, on my i5 that I developed this on, it uses about 30% of one core (Flash is also single threaded). On my wife's ultra-portable, which has an Intel SU7300 - a 10W ULV processor slower than the old Macbook Airs - it uses about 60%. Both of these tests were done with Chrome.
Interestingly, Firefox utilizes a little more more CPU, because it seems like its HTTP client is less efficient than Chromes. More surprisingly is that Internet Explorer 9 uses even less than Chrome, because its HTTP client is even faster than that of Chrome. But the Flash cost is about the same in all three.
These were quick smoke tests though, nothing too scientific. If you test yourself, be sure to have a CPU monitor to ensure that your CPU isn't underclocking itself (stepping down). For example, if your laptop steps down your CPU to half its normal speed, then the process may be registered as using a higher percentage of CPU cycles than it actually is. My computer is a laptop so it often steps down from 2700 to 2000 MHz, and thus the usage jumps up to around 40% (this usually happens only when the window doesn't have focus).
The use of vector graphics as well as the MOD format music contribute to a bit more CPU usage in exchange for a small package. MP3 would (surprisingly) be faster as would pure bitmaps -- depending upon an adequate implementation to achieve the same effect as I mentioned above.
Overall this was a great development experience. I'd really like to go back and refactor the code and rethink some of the natural designs that emerged... which weren't always great. This experience, along with the retro RPG engine has convinced me that game development is both awesome and hard. It has to be one of the most rewarding kinds of development. It's a mixture of art, science and engineering at its best.
I'm currently reading through four books related to various HTML5 topics, and I look forward to seeing what it can do. It has big shoes to fill though, as Flash is a hard act to follow. Simply being "not a plug-in" won't cut it!
Game Design and Programming
- Clinton Begin
- The original ship is from Devian Art under a CC license by Aquilar Nava.
- The explosion sprite sheet was created using a generator by Positech Games.
- The asteroids are from Mr Booth, and a forum post, but not sure of the source (if you know it or own it, let me know).
- All sound effects for thrusters, energy weapons, projectiles and explosions are from Freesound.org.