Back in 1983 Sirius Software released Wavy Navy by Rodney McAuley for the Apple II, C64, and Atari 800. It was an obvious Space Invaders/Galaga takeoff, but the simple mechanism of having your ship carried around by large waves completely changed the dynamics. It was great - this was one of the Apple II games I played to death (along with Dino Eggs, Boulderdash, Bolo, Choplifter, and a bunch of RPGs).
So here we are 20 years later and I'm finally motivated to write a game in Python (my favorite language for getting stuff done fast and maintainably) and Pygame. What's my first game going to be, my proof of concept? Well obviously Wavy Navy.
This was completely done in three weeks, in my spare time (I've got a day job). About a week of that was creating and futzing with art, sound, and music. Python is so easy to prototype and write games with I'm looking forward to doing more. It's really the resource side (making art and sounds) that kills me.
Version 2.0 includes 3 new skins (all provided/inspired by Michel and Xaiver de Labouret) and makes it pretty much entirely skinnable now. As a side effect I updated to PyGame 1.8.1 and removed Python 2.3 support.
See the list of known issues and recent changes.
Note: Difficulty level 1 is pretty easy, in deference to people who aren't rabid game players. If you find it boring, please try Level 3! This is settable from the main menu when you hit space to play the game.
The zip file should contain everything you need. Just unpack it somewhere then run wavy.exe from the bin\ directory or wavy.bat in the main directory.
My art skills are awful. So are my sound editing skills (my only tool is the Windows Recorder accessory). I drew the sprites painstakingly by hand, and am not overly happy with them. All sounds were scavenged from the web. Please forgive this, I think the play is still fun. If you would like to make better sprites or sounds please see Customizing below - the game is almost entirely skinnable.
Yes, my jet fighter diving sound is actually a Cessna (prop) plane.
Pygame doesn't easily support midi. I'm not going to make you install Timidity and 14 MB of patches, so all the music files are 50k ogg files instead of being 2k .mid files. D'oh!
Your ship is at the bottom of the screen, riding the large waves. The waves will lift you helpessly up and down, which means there's a vertical factor to worry about. But they can also shield you from bullets. Move left and right, fire your SAM (Surface to Air Missile), dodge things.
Idling waves of Copters and Fighters at the top of the screen will decide to make attack runs. Fighters will loop around and occasionally drop a bomb - they will crash into the waves as well. This does not get rid of them, a new one will replace it from the top! You must shoot them to keep them dead. Copters are much nastier. They'll come down, look around, and fire a stream of bullets at you. Then maybe do it again.
Enemies are worth more at higher difficulty levels, and Copters and Fighters are worth more when they're trying to attack you then when they're just idling back and forth.
On certain levels there are other enemies: Cruise Missiles, Bombers, and Mines. Mines just slowly float at the bottom of the waves. Cruise Missiles shoot across the top of the screen, then the tops of the waves. All you have to do with these is not hit them. Bombers will fly across the screen and drop a huge number of bombs - but in theory there's enough room between them for you to live!
The game never really ends, but when your rank ceases to go up you've effectively beaten that difficulty level. The game will let you know when this happens, though you can keep playing and the toughness of the enemies will keep increasing. Try a higher difficulty level! You'll get more points, and I think you'll find level 3 extremely challenging. If you beat that, I guess I'll have to add difficulty level 4.
You can configure the defaults for various menu items (Clouds, Display,
Difficulty, Skin, Music) in user_config.txt
.
You can change the ship control keys - see the [keys]
section
in user_config.txt
.
Wavy Navy is almost completely skinnable, since the colors, sprites and sounds are mostly data driven. in the skins/ directory, Each theme has a [mytheme].txt. Please see Default.txt, then Vector.txt for an example of a modified theme. Usually you'll just want to replace the sprites, so make your own [mytheme]/sprites directory (also see [mytheme]/sprites/CONFIG.txt) and in [mytheme].txt change sprites: to [mytheme]/sprites. If you wanted to make your own levels, you'd add your own [mytheme]/levels (and change the levels: line). [mytheme].txt has color settings for everything except the demo text.
I know my art is awful - please email me your better sprites/sounds, or even your entire upgraded themes if you're so motivated, and I'll put them up - with full credit given, of course.
All the sprite image files in sprites/
and wavs in
sounds/
and music/
are replacable by
your own files (or just edited versions). See
CONFIG.txt
in the sprites/
and
sounds/
for more info.
I'm considering adding C64 and Apple II skins for nostalgia factor, but have still been too lazy.
Midi Fragments arranged by: Drunken Sailor - Barry Taylor Blow the Man Down - Barry Taylor The Handsome Cabin Boy - Ron Clarke Sailor's Hornpipe - Bynum Braden Popeye the Sailor Man - Anonymous
Yo Ho Ho - http://ingeb.org/songs/fifteenm.html
Anchors Aweigh - http://www.contemplator.com/america/aweigh.html
Marine's Hymn - http://www.instantknowledgenews.com/marine.htm
The midi files for 'Row Row Row Your Boat' and 'Sailing, Sailing' were scattered anonymously all over the web (the same one or two .mids on every site) with no credit given - if I knew who to credit I would!
As I was programming this, I often compared it to what the process would be like on an Apple ][ or C64. In 6502 assembly language with about 40K of memory to play with - I've been there!
In favor of the old way, there's something to be said for the purity and economy of the assembly language. If you need to hold x/y positions for 30 planes, you just reserve that much space in the header and bang on them directly using the X register as an array index with the plane ID. Compare this to the way I do it here - A Plane class (which is a Sprite subclass ) has further Subclasses: Fighter and Copter. These objects are created as needed, positions and speeds are tuples and bounding rectangle positions, and of course all all movement is done somewhat indirectly.
Graphics were not so much an issue - when they're so crude almost anything is good enough for a small sprite; though doing larger graphics for backgrounds or title screens was still beyond me. Having more resolution and colors (and full multichannel wave sound cards) to work with for the new game is rather a bad situation for someone who's bad at making the art like I am. This definitely ate up a lot more of my time than I'd budgeted.
You didn't have to worry about writing an installer, cross-platform compatability, or much in the way of system configuration. And most humbling of all, the entire original Wavy Navy executable is smaller than one of my sound effects files!
The New WayOoooon the other hand, I wrote this game entirely from scratch (except for the Pygame/SDL libraries ) in three weeks of spare time work, including creating all the art and finding and converting sounds, writing the docs, etc. Python's a dream language for doing quick revisions, adding functionality by slowly fleshing out the framework towards your overarching design, so you always have working code of some sort. What they're calling Agile Programming now. And not having a noticable compile step is wonderful - just edit and go. I can't imagine getting this done anywhere near that fast in the old days - even Nasir didn't turn out games quite that quickly.
Furthermore, the flexibility and ease of refactoring are incredible. In the old way, if you wanted to change how the plane x/y positions were handled (as described above), you'd be in biiiig trouble. Say you decided you needed another byte per coordinate to handle subpixel positions. You now have to rewrite every section of code that looks at the x/y positions. In Python, though this isn't Python specific of course, all that was just internal to the Plane class anyhow, and is handled by switching the positions from an int to a float. And that's all done implicitly since variable types are dynamic.
PerformancePerformance was a worry - Python is interpreted bytecode and I really don't worry too much about speed when coding in Python other than not doing dumb algorithmic things. That wave sprite is huge (and there's three of them), and there are quite a few planes and bombs on screen at once.
I shouldn't have worried - it runs smooth on my 3Ghz P4 XP machine, as expected. But it also runs smooth on my cruddy ancient 250 MHz Pentium 2 Slackware box. In fact at 4-6x the resolution and 16 times as many bits per pixel (32 vs 2) to move around, the frame rate is better than it is on the original game - if you play it you'll notice he used some tricks like only updating a plane every so often if it was idling. I'm not doing anything myself to optimize it, though Pygame and SDL have a few built in boosts like using update bounding rectangles. I'm not disparaging the original game doing what it had to do to make things work at 1Mhz, just noting that if the Pygame version runs that well on a 250 MHz P2 and old graphics card that performance is not nearly the issue I had worried about.
PortabilityThis was the real corker. I developed the game entirely on Windows since it's what I have for a game/dev machine at home. I gave no consideration at all to porting other than using os.path functions to split/join path names instead of hardcoding 'foo\bar'. When v0.90 was done I copied it over to my slackware machine, installed SDL and Pygame on it, and ran the game.
It ran perfectly. And it looked and behaved exactly as it did on Windows with no changes. I didn't have to go back and add 'if unix: blah elif windows: blah' anywhere in the code. I just had to add a small package maker script. Real write once, run anywhere. Now that chokes me up. And now Python and PyGame run great on OS X.
The Hardest PartThe hardest part of writing this game was adjusting the difficulty levels. The low frame rate of the original game was an integral part of the difficulty! With a constant 30 fps, which is what I limited it to under Pygame, the Copters were no longer the awesome threat they once were.
My original version was incredibly hard starting at level 4 - the game would just switch into turbo and massacre you. So I backed it off and then it was too easy, even on difficulty 3. I knew this would be the nastiest thing to tune, so I left it till all the other issues were mostly taken care of.
Finally, I decided to leave difficulty 1 as it is (for the casual gamer) and worked on stepping up the difficulty for difficulty 3 to something that would hopefully be enjoyable even for the hardcore gamer. I increased the speed of the choppers so they were evil again, and made the probability of Copters/Fighters proportional to the square of the difficulty. And now difficulty 3 is fun for me to play, but I still have nagging doubts - real play balancing takes months, but I don't really have a cadre of testers. Oh well, as long as I sitll enjoy it!
HmmmmFor me, writing games in Python/Pygame is the way to go. I've looked at other 2D frameworks like PKT and Torque Builder, but having to revert back to some half-assed scripting language or C++ is just too painful to contemplate, even with all they do for you. This is for fun! I only ran into two real issues.
First, the lack of midi support is a bit disappointing. It'll work under *nix if you install timidity and have a Gravis Ultrasound, but that's not really acceptable. So I can't use .mids for music, which would hide my lack of skill at this and also make the music files 1/100th of the size. Perhaps I need to use the sndarray stuff to fake my own FM synth.
Finally, I am of course concerned that it takes more effort to install and run than a Flash game would (and won't just run in your browser). But again, I'm doing this for fun and ActionScript gives me hives.
I am currently contemplating writing my next game... Finally motivated again!