Step #1 - Setting Up VIC Layout and Main Loop

A simple base for a game. It provides a Basic start (10 SYS 2064), sets up the VIC relocation and shows a simple synchronized game loop.

To show the loop running the border color is flashed and the top left char is rotating throughout all characters.

The not too eye-popping result looks like this:



step1.zip

Step #2 - Setting Up Custom Charset and Display "Hello"

In the first part we prepared everything for the VIC, now we set up our modified charset. Note that I used a selfmade tool (similar to CharPad). The file J.CHR contains the charset and is included into the source as binary. Since the C64 can't load files to locations after $C000 we have to copy the charset to the target memory at $f000 (and switch off the ROM therefore).

The current step should display "HELLO". The rest of the screen depends on the current memory setup of your emulator/C64.



step2.zip

Step #3 - Setting Up Custom Sprites and Display

Quite similar to step 2 this time we set up sprites. Note that I used another selfmade tool (similar to SpritePad). The file J.SPR contains the sprites and is included into the source as binary. Since the C64 can't load files to locations after $C000 we have to copy the charset to the target memory at $D000 (and switch off the ROM therefore). The position the sprites are now positioned is otherwise unused RAM that is "hidden" by ROM. The VIC however can read the RAM below. This makes that location quite convenient for sprites or charsets.

And another note: Since I'm lazy I built the sprite copy loop to always copy packages of 4 sprites (1 sprite comes as 63 + 1 byte, so 4 make nice 256 bytes).

The current step should display charset garbage and "HELLO" as before, but also display a elegantly handicrafted sprite.



step3.zip

Step #4 - Moving Sprite With Joystick

Now we take a bigger step: Moving the sprite with the joystick. Since we want to make a real game we also allow to move the sprite over to the right side (in other words we'll take care of the extended x bit).

Since I don't plan to allow sprites to go off screen there is no defined behaviour if you move the sprite off screen too far. It'll simply bounce back in once the coordinate wraps around.

This step shows:
- Joystick control
- Sprite extended x bit



step4.zip

Step #5 - Build Stage Screen

Our next big step: Obviously we want some play screen, and more obviously, we are not going to store full screens. Therefore there's a level build routine, that allows to build a screen with various building elements. For now we'll start out with vertical and horizontal lines. Since we always have a level border at the screen edges we'll have the border as a second screen data block (LEVEL_BORDER_DATA).

To allow faster screen building we also have a table with the precalculated char offsets of a vertical line (SCREEN_LINE_OFFSET_TABLE_LO and SCREEN_LINE_OFFSET_TABLE_HI). Note that with the C64s mnemonics the best way to get stuff done is tables, tables, tables.

The BuildScreen sub routine clears the play screen area, builds the level data and then the border. The level data is a collection of primitives which are then worked through until LD_END is hit.

This step shows:
- Clearing the screen
- Building a level from primitives



step5.zip

Step #6 - Collision With Screen

And onwards we go: Obviously we don't want the player to move through walls. In this step we check the chars in the players way to see if they are blocking.

To make this easier we store the character pos and the character delta pos (0 to 7) for x and y for every sprite. If the sprite is not at a character brink the move is allowed, if it hits the brink, check the characters at the target.

For this step any character equal or above index 128 is considered blocking, any below is free to move.

The collision code assumes that the collision box of a sprite is one char wide and two chars high.

This step shows:
- Calculating character positions while moving about
- Checking the position for blocking chars
- Calculating the required sprite position from character pos (for starting a sprite at a specific place)



step6.zip

Step #7 - Gravity/Jump

Now it's starting to resemble a game. Loosely.

We add gravity and jumping. The player will fall if there is no blocking char below. On joystick up the player jumps in a curve.

Both fall speed and jump speed are non linear and based on tables.

This step shows:
- Gravity (accelerating)
- Jumping (following a delta y curve)



step7.zip

Step #8 - Enemy Placement

Of course a game isn't a game without some challenge. Therefore we need enemies. Since we have some neat little level build code why not use it for enemies as well?

We add a new level primitive type LD_OBJECT which adds objects (= sprites). We use it for both player and enemies. A new table SPRITE_ACTIVE is added to see if a sprite is used (and which type).

One central function to this is FindEmptySpriteSlot. It iterates over the sprite active table and looks for a free slot to use. If there is a free slot we use the previously created CalcSpritePosFromCharPos to place the sprite.



step8.zip

Step #9 - Enemy Movement

What are enemies if they just sit put and don't move at all? Therefore we now add the sub routine ObjectControl. We provide a table with function pointers to the object's behaviour code (including the player).

ObjectControl takes the object type as index into the table and jumps to the object control. For now we have two enemy types (type is tied to behaviour), dumb moving up/down or left/right. For moving we reuse the previously created functions we already use for the player, namely ObjectMoveLeft/ObjectMoveRight etc.



step9.zip

Step #10 - Collision Between Objects and Player

So you found out the enemies couldn't hurt you? Well, we're working towards that goal in this step. We add collision checks. Since I'm not completely sure about later changes we are NOT relying on the VICs collision checks but roll our own. Remember the object size contraints from step #6? We apply those to the object collision checks as well.

We add a new subroutine CheckCollisions which in turn uses IsEnemyCollidingWithPlayer. We do not check for collisions between enemies. The check is not completely exact (behaves more like 9 pixel * 16 pixel), but that's good enough. If a collision occurs the border color is set to white.



step10.zip

Step #11 - Enemy Kills Player

From colliding to dying is a small step. Once the player collides with an enemy we kill him by removing the player object. A "Press Fire to Restart" message is displayed and a press on the button will revive the player object.

We add the function RemoveObject which simply removes the object from the SPRITE_ACTIVE table and disables its sprite. While we wait for the player to press the button all the rest of the game moves on.



step11.zip

Step #12 - Player Kills Enemy

One of the more complex steps. And also one I someday need to heavily optimize. The player can now shoot an enemy.

The central function for this is FireShot. We don't use a bullet but insta-shot. However walls should block the shot as well. This means, we need to take the current player direction and position, and work our way to the left/right until we hit an enemy or a wall.

Since there's no direct collision involved we take the character pos of the player, add or decrease the x pos and compare against all alive enemies pos. Rinse and repeat until done.

I've given the enemies 5 HP, and the player has a shot delay of 10 frames. Therefore it takes a while for the enemy to disappear (best tested with the box on top). If the player is purple the shot delay is active.



step12.zip

Step #13 - Item Placement

And yet again a bigger step. Of course we need lots of goodies from the killed enemies. We add items. Items are not sprites but a 2x2 block of characters. There's a new list of possible items with location added. The list also stores the original background behind the items. To get an item spawned just walk beside on of the enemies (look in their direction) and keep fire pressed until it dies.

Note that the player cannot collect the items yet (that's up for the next step).



step13.zip

Step #14 - Item Collecting

And onwards we go. Picking up items showed a new problem. When an item is picked up we want the background behind restored (plus the item characters should not cut holes into the play field). In the end I decided to have a second back buffer screen that contains the original play screen.

Now every time an item is removed the character blocks are copied from the back buffer. Also, the back buffer is now used for collision detection. I could not avoid having to redraw the still existing item images in case the removed item was overlapping.



step14.zip

Step #15 - Level Progress

Now we start with a few game essentials: Progressing to the next level.

Not too complicated. We keep a counter of enemies alive (NUMBER_ENEMIES_ALIVE) which is initially set to 0. For every enemy object it's increased. And for every killed enemy it's decreased. Once the enemy count reaches 0 the level end delay kicks in (marked with the border flashing). Once the level end delay is complete the next level is displayed.

For now there's two simple levels with the last looping back to the first.



step15.zip

Step #16 - Score/Live/Level Display

Now for some rather small addition, which however feels like a bigger step: Score/Live/Level display.

We already have a text display function, so we add a new default text for the display with initial 00000 values. Note that the score doesn't fit into a byte easily. We only update the numbers on the screen, we do not store the score in another location.

This makes it quite easy to update. For every step we start at the right most digit and increase it. If it hits the digit after '9', set to '0' again and repeat the step on char to the left. For retro sake we don't start at the right most score digit, but the second right most (making increase steps always being 10).



step16.zip

Step #17 - Player Movement and Animation

Another rather small step, but visually pleasing. We're enhancing the player sprite with animation and better jump abilities.

All the hard work is added to PlayerControl. On every movement we update the sprite while checking the player states like jumping, recoil, falling, etc. Suddenly things look more interesting ;)



step17.zip

Step #18 - Enemy Movement and Animation

This time we add some enemy animation and path based movement enemy type. The movement path is stored in a table of delta X and delta Y values. Values with the highest bit set are treated as negative.

The animation of the bat is also stored in a table (it's a simple ping pong loop).

Every objects get an animation delay, animation pos and movement pos counter.



step18.zip

Step #19 - New Enemy Type, Movement and Animation

Nothing really new this time, just constant use of existing parts. A new enemy, some sort of mummy, which slowly walks back and forth. And takes a few more hits than the bats.

It's a new behaviour added to the table and some extra code that checks for gaps before walking.



step19.zip

Step #20 - Reload and Item Effects

More refinement, this time with more impact on the gameplay. For one, the shotgun needs to be reloaded (stand still) and the collected items now also have an effect. Namely sped up reload and invincibility.



step20.zip

Step #21 - Title Screen

Now a technically more interesting step: We add a title screen with a bitmap logo. We're using a raster interrupt to show the bitmap logo in the top half of the screen and switch to text mode on the bottom half.

The bitmap data was created by a Lua script for my paint app. Then only the needed parts were cut out manually. We don't need the full 8k data for 8 lines.



step21.zip

Step #22 - Highscores

The title screen looks somewhat empty, doesn't it? Well, let's fill it with highscores! Lazy as I am I'm storing the highscore scores and names in two separate texts which are simply displayed with the common display routine.

After Game over we check for a new spot. If we manage to enter the list all lower entries are moved down. For now that happens automatically and only affects the scores. Name entry follows up next.



step22.zip

Step #23 - Highscores Name Entry

Highscore display is all nice and dandy, but we want to see our score and name in there! So this step adds name entry. For this we rely on the Kernal functions to read the pressed keys from the keyboard.

Adding to the score moving we find the spot for the name, shift all lower score names down and let the player enter his name.



step23.zip

Step #24 - Saving/Loading Highscores

What use are highscores if they aren't saved? With this step highscores are saved and loaded from your previously used medium (tape or disk). On startup the currently used medium is stored, save and load is done via bog standard kernal routines.



step24.zip

Step #25 - Title Logo

Oopsie. Step #21 wasn't actually a bitmap logo. It was plain characters. Sorry about that!

This time comes the real bitmap logo code: We add a title screen with a bitmap logo. We're using a raster interrupt to show the bitmap logo in the top half of the screen and switch to text mode on the bottom half.

The bitmap data was created by a Lua script for my paint app. Then only the needed parts were cut out manually. We don't need the full 8k data for 8 lines.

Just wait until the steps where Smila made the graphics come in ;)



step25.zip

Step #26 - Dissolving/Attacking Enemy Types

We add a new enemy, the beloved zombie. The zombie can appear from underground, walks about slowly, and if shot, dives in the ground again. And does move underground.



step26.zip

Step #27 - Dissolving/Attacking Enemy Types

And yet another new enemy. A vanishing bat. Once shot, it'll disappear and randomly attacks you.



step27.zip

Step #28 - Enhanced Level Building Types

The levels are currently rather ermm. platonic. To get things rolling a few new level building types are added:

Namely a char/color area, an alternating line horizontally and vertically (alternating means toggling the characters +1/-1) and a quad (a 2x2 tile)



step28.zip

Step #29 - Title Refinement (Color Fade)

Another cosmetic step. The highscores receive a nice color warp. Pretty easy to implement, on every frame simply exchange the color bits where the score is displayed, and voilá!



step29.zip

Step #30 - Highscore Entry Refinement

Now a new cosmetic refinement, high score name entry. Now the entry is done on a title screen like layout, with a blinking cursor as well.



step30.zip

Step #31 - More Stages

And another rather unspectacular step: Just a bunch of new stages. Things do get prettier once the editor is used. Currently stages are assembled manually ;)



step31.zip

Step #32 - Bug Fixing

A complete unspectacular step, but necessary every now and then anyhow: Bug fixing.

During the last few steps several bugs cropped up that are being addressed now:
- Items could appear outside the play area (in the border)
- On respawn/restart the shells are filled to the max
- On respawn the player now appears at the level start pos
- Autofire on game restart is now blocked
- All active items are removed when the player gets killed



step32.zip

Step #33 - Enemy Refinement

More refinement: Zombies are now better animated and jump randomly. Mummies attack now if they see the player. And the bat gets a new diagonal movement.



step33.zip

Step #34 - New Item + Item Drop Rate

And another refinement step:

A new item for faster reload has appeared and not every kill is getting you an item to collect.



step34.zip

Step #35 - Enemy Annoyed State and New Enemy

And onwards we go. Enemies now have an annoyed state once they got hit. For some annoyance is even increasing.

And to top it off, a new jumping spider enemy.



step35.zip

Step #36 - Enemy Shot and Dying Effect

I called this one "Satisfaction Refinement". Enemies when shot are hit back for a few steps, it's a shotgun, dammit!

On their final blow enemies now burst in smoke.



step36.zip

Step #37 - Player Dying Effect

The player is simply vanishing when getting killed. Kinda looks odd, doesn't it? We add a nice new animation and then send the player back in.



step37.zip

Step #38 - Second Player

Now's one huge step that took me a week to implement: A second player. Can't have Supernatural with only Dean, now there's Sam as well.

In the title screen, press up to toggle game modes (single Dean, single Sam, coop). Note that Sam does not use a shot gun, he uses his dark powers.



step38.zip

Step #39 - Music

And a rather small step, but with huge impact: Music.

For now we're using a demo song from GoatTracker.



step39.zip

Step #40 - Spawn Spots

And onwards we go. This time we add spawn spots. These are a different kind of object which spawn a number of one specific enemy type. The level is clear once all enemies are killed and the spawn spots are empty.



step40.zip

Step #41 - New Sprites and More Enemies

Now the step you've all been waiting for: Smilas spritery inserted. What a difference this makes.

To celebrate there's also a slew of new enemies:
-Wolfman
-Eye
-Jumping toad
-Ghost skeleton

Have fun!



step41.zip

Step #42 - More Enemies

Smila delivered a slew of new monster sprites, so here's more:
-New enemy floating ghost
-New enemy fly



step42.zip

Step #43 - More Enemies

And there's even more, this time the good old monster of Frankenstein.



step43.zip

Step #44 - More Enemies

And more enemies: An underground hand and a devil skeleton.



step44.zip

Step #45 - Level Editor

Introduced in this version: The level editor (not in the game though). This makes setting up pretty stages way easier. Expect lots of touchups soon.

There's a bug in this version that makes Frankie take ages to appear, it does happen however.



step45.zip

Step #46 - Introduction Page

What's a game without a story? Unless it doesn't need one that is ;)

We add a introduction page that will be shown for every chapter of the game. And a neat image of an Impala.



step46.zip

Step #47 - Sam Force Range Improvement Extra and Cheat Keys

Poor Sam got nerfed. Now his force range starts out really low (about 5 characters), but can be improved by picking the proper extra.

And finally cheat keys appear. Press 1 to advance to the next stage.



step47.zip

Step #48 - Chapter 1 Complete

And the 10 stages for chapter 1 are complete. Have fun!



step48.zip

Step #49 - Bug Fixing

Fixed the hit-back behaviour for all monsters. Also added sprite offsets, now sprites are properly aligned to the floor.



step49.zip

Step #50 - Permanent Powerup

In this step the powerups for range increase and decrease reload delay are made permanent. You can also collect up to five extras to reach the maximum. And the powerup stays even when you get killed. (Don't you hate it when you die in Bubble Bobble and you're slow again).



step50.zip

Step #51 - Experimental Cooperative Feature

More cooperative hodge podge. An experimental feature, both players are needed to kill an enemy. Sam must hold the enemy, so Dean can shoot it.



step51.zip

Step #52 - Friendly Spawns

To make spawning enemies a bit more player friendly spawns are now shown before the enemy actually appears.



step52.zip

Step #53 - First Boss

Here comes our first boss. Nothing too difficult, but different. Let's see what this works out to :)



step53.zip

Step #54 - Bug Fixing

Spawn count bug fixed
Major slowdown when playing with Samfixed
Car sprite error in story page
Left over char N in mode choice
Other player spawing although no lives left



step54.zip

Step #55 - 10 More Stages

And here's the next 10 stages. Lots of nasty spiders should give you quite a bit to do.



step55.zip

Step #56 - Another Boss

And another boss. Who looks remarkably similar to our first boss. Hmm...



step56.zip

Step #57 - Enhancements

Some smaller enhancements. For one, levels can now be configured to have no border. And we allow for a second charset. The latter required a few code and table rearranges but now works properly.



step57.zip

Step #58 - New Music

Richard came, saw and made some awesome music! Thanks again!



step58.zip

Step #59 - 10 More Stages

And the next 10 stages, most of them using the new non-border layout. Have fun!



step59.zip

Step #60 - Third Boss

Phew, almost didn't make it. Here's Boss #3. Good luck!



step60.zip

Step #61 - Black Sewage

A little gimmick: Did you notice the black sewage in some of the stages? Now it affects everything that's inside, as it's slowing down enemies and the players.



step61.zip

Step #62 - New Get Ready

And a new Get Ready display!



step62.zip

Step #63 - Music Stuck Fix

An onwards we stumble! Noticed how the music gets stuck when the next stage is built up? Especially notable if you use '1' to skip through stages.

That's amended in this step. It boils down to having a raster interrupt which calls the music player.



step63.zip

Step #64 - Sprite Flicker Fix

Note how the sprites would flicker about before/after Get Ready?
Fixed. Also, Sam got borked again, esp. during a boss fight. Now that's also fixed.



step64.zip

Step #65 - Shotgun Flash Effect

Following a recent hint, here's a flash effect for the shotgun. Does look better than nothing ;)



step65.zip

Step #66 - More Stages

And finally, the next batch of stages!



step66.zip

Step #67 - New Game Over

And per Richards request, a game over display, even with (a little bit of) animation.



step67.zip

Step #68 - Visualize Dark Force

Added an idea I had floating around for quite some while, visualise Sam's dark force. It's currently not exactly like I wanted it to look like, but it's the start.



step68.zip

Step #69 - More Stages

And more stages, this time a deserty area.



step69.zip

Step #70 - New Boss

And a new boss. Quite similar to the first actually, but supposed to be a bit more aggressive.



step70.zip

Step #71 - Better Dark Force

And a better version of Sams dark force (which doesn't look too dark anymore).



step71.zip

Step #72 - Remember The Story Screen

A rather simple step, remember the story page? Now the next chapter text has been put in place, as well as a cool off text after beating the first boss.



step72.zip

Step #73 - Packing

Nothing new code wise this time, but something necessary: Packing. The normal file now hits the 40Kb mark, and it's slowly getting too big.

Here comes Exomizer to the rescue. It's a cross plattform packer tool targetting old computers with little memory. It compiles code parts, unpacks them to specific memory locations and even takes care of the ROM/RAM settings. Terrific!

In the .zip file there's the executable and a changed .c64 project file. In C64 Studio you'll now find a new build config "Default Crunched". This builds the file as normal and as a post build step calls Exomizer:

$(BuildTargetPath)/exomizer sfx 2064 $(BuildTargetFilename) -t64 -n -o $(BuildTargetPath)/gamecrunched.bin

..and copies over to the original output file name:
copy $(BuildTargetPath)\gamecrunched.bin $(BuildTargetPath)\jmain.prg /Y

The latter step allows us to still debug through the code as usual.

step73.zip

Step #74 - Another Boss

And another boss!



step74.zip

Step #75 - New Waterfall Char

And more! Now the executable hit the load barrier, so Exomizer is the only way to go onwards. Added a new waterfall char with the same effect as low water.



step75.zip

Step #76 - Another 10 Stages

And yet another 10 stages. A few animation bugs show up with the water, in general there seems to be another fixing step coming up.



step76.zip

Step #77 - Another Boss

And yet another boss. Clearly inspired by the previous one, but now only vulnerable if he spawns bats.



step77.zip

Step #78 - Story Pages

Added and streamlined all story pages. Now we have locations (mentioned) and a crude "story arc". Plus a little animation on the last two bosses.



step78.zip

Step #79 - New Feature

Almost a new feature. For the final level range the enemies spawn in waves. In this level, after beating the wolfmen two more waves of other enemies come in. And all without any more memory in the level data!



step79.zip

Step #80 - Portal To Hell

Far we wandered. See the big door in step 79. It's a portal, a portal to hell. And it's opening now...



step80.zip

Step #81 - New Extra

A new extra! Oooh, shiny!
From time to time you may find a blue bullet icon, one of the wondrous bullets for the famous colt from Samuel Colt. One bullet that kills instantly, even bosses.



step81.zip

Step #82 - New Hell Portal

Going slower now towards the end, the next portal to hell.



step82.zip

Step #83 - New Extra

And here's a new extra for Sam. It works similar to the super bullet. For every demon blood picked Sam can destroy an enemy with one touch.



step83.zip

Step #84 - Next Portal

And here's the next portal. Hope you don't mind the slower pace, I'm working on a bigger step in the background.



step84.zip

Step #85 - Yet Another Portal

And yet another portal stage!



step85.zip

Step #86 - Neater Story Pages

And something different for a change: Added road side stones to the story pages to make it look a bit neater. Looks better in motion :)



step86.zip

Step #87 - Just Another Portal

And again, just another portal stage. Getting close though!



step87.zip

Step #88 - Final Boss

And here's the final boss. Note that you can't kill the last part though :)



step88.zip

Step #89 - Final Boss Fix

Now you can kill the last part. Beware, it will fight back though!



step89.zip

Step #90 - Final Boss Polish

And the boss got a bit more lively (visually). Moving body parts and the head screams when getting hurt.



step90.zip

Step #91 - Torso Fights Back

Aaaand the torso gets to fight back too, not only sit put.



step91.zip

Step #92 - Sam Can Kill The Boss

Poor Sam was left out again. Now he can kill the boss too.



step92.zip

Step #93 - Fix Other Bosses

And also an addon to make the other bosses a bit stronger against Sam. Now you need to re-grab the boss after every hit you place.



step93.zip

Step #94 - Final Parts

And back we are for the final parts!

Now we have a real two player coop mode. It's not both players playing by themselves, but true teamwork. Sam needs to capture, and only then Dean can shoot enemies.



step94.zip

Step #95 - Zombie Wake Up Fix

Now a little update that adds a change that was long overdue: Zombies do not wake up all of a sudden, but peek out of the ground before. Now players should be able to escape if they're keeping an eye out.



step95.zip

Step #96 - SFX Mode

And a nice little update, Richard added a SFX. Now there's a SFX mode, toggle in the title screen with left/right.



step96.zip

Step #97 - Bat Movement Fix

And here's a little gameplay update, the bats. The diagonal movement was too predictable, so now there's more randomness to it.



step97.zip

Step #98 - Extro

And here's the final bit, the extro part. Never have the player play through your whole game and put "Game Over" there. At the minimum a nice message is required :)

And yes, it's symbolic at 98, since there's always some bugs left to fix. The last two steps will be mostly bug fixes.

Since it's the extro (and not even particularely impressing) I'll refrain to show the screenshot ;)

step98.zip

Step #99 - Bug Fix

And of course lots of little bugs were found and fixed :)

- Live number display was off on a new level.
- Beams would sometimes not be removed on the final boss
- Disable screen output when saving scores (IRQs go nuts if using kernal save routine)
- Cleaned up "extro" text

step99.zip

Step #100 - Game Complete

And thus this create a game series ends...

We fix the last few bugs (score was not properly reset on replay, music was stuck on saving the scores). Now the game is complete and can be enjoyed as it was meant to be!



step100.zip
Oh joy, Smila (the graphician) actually touched up the game even more for a retail release. It has been out for a few weeks now, but if you didn't know, go here:

Psytronik (for digital download, tape or disk) or to RGCD (cartridge with nifty packaging and stickers). Or simply marvel in all the nice games that are still being made for older computers.

There you can actually buy a severely enhanced version (more two player game modes, better graphic, gameplay enhancements) as either digital download for emulators, or as a real tape, disk and finally as cartridge!

Thank you for your encouragements throughout, and keep on coding ;)