v0.95 RC1 Paku Paku - Commodore 64 VersionMenu Screen
Version 0.95 RC 1 released
see the Revisions page for details on what's new.
Here it is, my 'port' of Paku Paku to the Commodore 64. This is released to the public as Cardware -- if you enjoy the game, please just send me a postcard as payment, preferably one that has a local photograph of where you are from. Apart from that consider all enclosed code to be released to the public domain -- that's just how I roll.
Send your postcards to:Jason M. Knight
233 Baker Street
Keene, NH 03421
- Based on original PacMan map reduced to use 3x3 tiles instead of 8x8. This preserves the aspect ratio, map and scoring of the original game.
- Familiar WASD keyboard mapping for those used to modern games, and the old IJKM mapping for those more comfortable with a 'classic' C64 arrow layout.
- Support for either joystick port, though to use port A you must start the game with it's button.
- No cross-talk between active joystick and keyboard. (a common issue with C64 games)
Improvements over DOS Version
- 160x200 color graphics for text and background -- double the vertical resolution.
- 12x12 player sprite, double the resolution of the PC version
- 6x14 ghost sprites, double the vertical resolution
- Slightly smoother gameplay due to higher resolution, particurly when ghosts are 'slowed' due to power pellet or tunnel.
- Due to the complexity and unpredictability of C64 disk systems, and the possibility that this could be run from TAPE if so desired, I did not implement a multiple high score system with auto-saving. I don't consider this a deal breaker given the number of C64 games that bother with it. As such this version only tracks the high score and last score.
When I wrote the last version of this game for DOS, I didn't think I'd be revisiting it again for quite some time -- but then someone said to me "It's too big to port to the 64 without losing things, that's why the 64 Pacman games are all mediocre." -- I agree with the mediocre part for what was released back in the day. The official game being a overnight port of the Atari 400/800 version, and the other attempts not quite delivering a true 'pac man' experience... but in terms of system capabilities, with hardware sprites, the SID sound chip, and being far, FAR more 'game friendly' than DOS, I argued back that there's no reason it couldn't fit with room to spare -- despite the fraction of clock speed (1 mhz vs. 4.77mhz), half the register width (8 bit vs. 16 bit), and a fraction the available memory.
I had thought the memory would be my undoing on this, particularly when I started learning about how video memory was laid out on the '64. Most C64 games use the 'character graphics' mode to kind-of 'cheat' at making the map. Building it from reprogrammable characters uses very little ram compared to the 8k true graphics modes would... The problem with that is the map I'm using is based on 3x3 tiles not 4x4 or 8x8, and as such wouldn't work in character mode worth a flying purple fish. Multicolor bitmap mode was my only choice, but that's 8k of RAM out the door. Figure in that I'd need at least 56 sprite tiles, which on the '64 are fixed at 64 bytes apiece, the 1k chewed up by the character RAM (used for color tiles in multicolor bitmap mode) and I was looking at 12k gone before I even started coding. WORSE, that 12k wasn't gonna fit in the normal video location, so I had to move it up to the second 16k RAM page... this left me with around 23k above video and 12k below it to work with.
Much like with the PC version I decided that what I could do with a high level language like C I would, reserving assembly for where I REALLY needed it. I chose as my compiler set CC65 becuase it seemed decent enough a C compiler, came with a fairly robust assembler, and provided some tools for manipulating memory.
"Back in the day" I never had a Commodore 64. Prior to '82 I was mostly a TRS-80 guy... I owned a VIC-20 for all of six months and never really got past BASIC on it, and by the time the '64 came around I had already gone on ot the 8088 world of doing things. Add to this that I never knew ANYONE who actually owned an Apple II, and never even saw one in person until sometime around '88 to '89, and my experience with 6502 machine language was effectively nonexistant. As such not only is this the first thing I've ever written for a Commodore 64, it's also the first time I've ever done any 6502 machine language.
As I started coding the game I realized that as good as CC65's linker was, it just wasn't going to build the files in the way I needed. I also figured it would be easier if I could just use a modern paint program to make the graphics and have some sort of import, as well as having some way to port much of the existing data like the theme and tile layout from the DOS version. I ended up writing a dozen or so programs in Free Pascal to handle the transitions, as well as build some 'define' files to let me automatically load the new data and pass all the memory locations to the program. I end up using around two-thirds of the bottom 14k that's free after the Zero page, stack, video and BASIC loader are taken into account for much of the 'static' information like a RLE encoded copy of the playfield, menu texts and colors, etc, etc... One of the largest chunks is the font, which consumes 5.6k! It was just too slow doing all the shifts to allow for kerning and multiple character widths, so I ended up storing four copies of the font pre-shifted.
Timing proved an interesting learning experience. There's a lot of information and not a lot of what I'd call 'practical advice' out there for it. The original synced itself internally to 120hz, which is then used to do my own timeslicing -- slower levels adding 'do nothing' slices so that the 'slow' levels work out to 20 FPS, medium speed is 24 FPS, and the fastest levels run at 30fps (6, 5 and 4 slices per frame respectively). Rather than get all fancy with it, in the end I simply hooked into the user interrupt at 0x0314 and then every other call hand off to the default of 0xEA31. This means despite firing interrupts twice as often, the system handler is still called at a normal rate. I really wasted too much time trying to hijack the ISR completely and/or override it, when keeping it simple was all I needed.My first time programming the SID sound chip was interesting. I've dealt with ADSR based systems having done plenty of Yamaha FM programming for things like the FB-01 Synth module and the Adlib, but the SID really is a whole different game. There are... quirks in how notes are played and how the waveforms are put together that aren't just limiting, they're outright annoying at times. In particular I repeatedly was banging my head against the wall with sounds not playing becuase I was toggling the playback gate too quickly. Took a while but I think I came up with a decent sound set that while not 'perfect', sounds pretty good given the hardware. It surely sounds better than the official Atari port. Like that's hard...
This was also my first time using a system that provides hardware sprites... well, unless you count DirectX and OpenGL. For a system of this era I can see why these made such an impact for the machines that had them. On the DOS version a good three quarters of my code is devoted to maintaining a backbuffer, updating and drawing sprites to the backbuffer, and copying the modified bits of the backbuffer to the display. That's two thirds of the code-base that wasn't even needed here, as the video chip handles it for you. Once I got enough RAM to hold all my tiles it very quickly started to feel like cheating -- even more so since with the game map ending at 172 pixels across the screen, I never even need to touch the high bit for the x coordinate. Moving them becomes a simple matter of putting the X and Y coordinates into the sprite memory locations... Mind-blowingly easy.
Which is why I started enhancing the graphics. I knew from the start I was going to make the ghosts taller and make use of the doubled vertical resolution. In multicolor mode the 6x14 ghost sprites were a no-brainer. The player though being monochromatic immediately made me realize I could make that 12x12 -- double the PC version's detail... Even so that's 5 sprites, and the C64 supports 8. For 'lives left' I wanted a high res pacman there, so using a sprite for that with a number instead of multiple pacmen pulled that off... that still left two sprites free, and I HATE the idea of leaving resources unused...
So I used them to add anti-aliasing to Herr Paku. The 64's orange color makes a passable anti-aliasing color to help 'smooth out' the jagged edges. All I had to do was overlay the unused sprites over the player and life counter, and poof, 2 color instead of 1 color sprites.
The bonus items/fruit proved more challenging. Originally I was going to use multicolor sprites, but with the need to display a LOT of them on the menu and during late gameplay that idea was tossed right quick. That they only would have had a single unique color and then had to 'share' with the other multi-color sprites was a further deal breaker, so I had to put them on the bitmap.
The problem with trying to do things like the fruit on the bitmap is that even in multi-color mode, a 8x8 'tile' of video can only contain four colors -- a foreground color, a background color, and two unique colors. To make the fruit look 'good' -- or at least more recognizable than the little 'blobs' used in most home computer pac-ports -- I needed at LEAST 4 colors, maybe more.
The trick I used involves where they are placed on the screen. I put them 'center' of the junction of a 2x2 block of those 8x8 color areas. By straddling the intersection I can use 2 unique colors in each of the four resulting quadrants. The cherry for example uses brown in the top two quadrants, bright red and red in the lower left one, brown and red in the lower right. That's three unique colors where I normally would only have had access to two. I avoided using the foreground color, and instead use that for the blue map borders. As the fruit do not go where the pellets are, there's no risk of them interfering with each-other.
Rendering the map itself was tricky too -- 3x3 grids don't usually work well on video memory built around multiples of 8. Getting the colors to line up even in multicolor mode took some trickery, and erasing the pellets as eaten took a bit of thinking to get fast enough.
Though on the subject of speed, the HARDEST part was the score. An 8 digit long number by definition means a 32 bit integer, and 8 bit computers are PAINFULLY slow at working with those. Combined with my kerned font routine the result was it took as long to draw the score update on screen as it did to process the logic for all four ghosts. Since I only needed 8 digits the natural answer was to use BCD -- Binary coded decimal -- which means there's no overhead in converting it to show as decimal on screen. Since C doesn't have facilities for BCD handling I ended up writing my own BCD addition routine. To further speed things along I also wrote a optimized blitter just for realtime score display with it's own 10 character font that's 16 byte aligned - and then forced the scanline location to be fixed. These changes all worked together to speed it up by a factor of six!
Net result, a fast, smooth playing pakuman experience on the 64. It is also PAL/NTSC aware so it should run at near identical speeds with near identical sounds on either platform.