Crazy Lander
Crazy Lander is another (mostly) BASIC game for Commander X16. We will introduce some new technologies not used before in our projects. It is a variation of Lander type games where we have to guide and land the space capsule to dedicated platforms using thrusters and navigating through natural and man-made obstacles. To make the game more challenging we have to be mindful of the fuel used and land gently. Few highlights:
- Running in bitmap mode
- It is a game of precision so we have to assure pixel perfect collision control
- Animated obstacles unique to each level
- Music and sound effects
Project Specs
- Emulator Version R.43
- Low resolution bitmap mode 320 x 240 in 16 colors on Layer 0
- Use the menu system to choose difficulty, turn music on and off, display instructions, quit and of course start the game
- Animated sprites for displaying capsule as well as thruster exhaust and explosion animation
- Tile layer 1 is used for HUD and for messages and menus
- Assembly subroutine for pixel perfect collision detection
- 4 distinct levels with flexibility to add more
- Scoring is based on the landing platform multiplier times the remaining fuel
- Keyboard/Joystick controls
- Left Arrow / Joystick Left fire left thruster pushing lander right
- Right Arrow / Joystick Right fire right thruster pushing lander left
- Space / Fire button main thruster pushing lander up
- Music in the background using Music Library for BASIC programs
- Sound effects using direct programming PSG from BASIC using VPOKE
- 256 color splash screen
Game Graphics
We will push the limits of Commander X16 graphics with this game by using all of its capabilities. We will use Tile mode, Bitmap mode for Title screen and play field and of course Sprites. In tile mode we will load a custom Font, add few custom tiles and even use VERA for playing background music and sound effects. As a result we will use almost all of 128K of Video RAM.
During the game play the setup will be as follows:
Layer 0 will be in Bitmap mode displaying the landscape against which we will be checking collisions. However, Layer 0 is not completely static, we will use BASIC to add different dynamic and animated obstacles directly into background graphics.
Sprites will be used to display the lander, thrusters and animated destruction of the lander. The Sprite sheet will be loaded as a binary file and contains the following graphics in 256 colors:
Layer 1 is a standard 40x30 tile text mode in 16 colors. To give it “space looks” we will load a custom font with some modifications so we can display the fuel and G force gauges.
Bitmap Mode
Since this is the first game we are covering that uses bitmap mode, let's summarize quickly how bitmap modes on Commander X16 work.
In short, in bitmap mode we do not use tiles but instead we draw pixels directly. Commander X16 is capable of displaying bitmaps in several different configurations. Main differences are the resolution and how many colors per pixel we want to display and those result in the memory requirements.
In our game we will use two different bitmap mode configurations:
Title Screen: 320 x 240 pixels in 256 colors
Game Screen: 320 x 240 pixels in 16 colors
Clearly for the Title Screen we use one byte per pixel and those pixels are stored in memory in sequence starting with the top left pixel, followed by one right of it and so on for 320 bytes and then we go to the second row and so on.
Game screen is more efficient and less colorful and uses 4 bits per pixel which means that each byte in memory can represent two pixels. Top four bits define the first pixel and low four bits define the second pixel next to it to the right.
One important thing to note here is that Commander X16 BASIC does not have any drawing commands and even if it did it would probably be too slow for drawing game objects in real time so we use LOAD to load graphics directly into Video RAM and then just point VERA to the correct location.
Sound
Let’s prove that even BASIC games with a little help from a music library can play music in the background and generate sound effects without much affecting the performance of the program and still remain perfectly playable.
For background music we will use the Music Player Library and the tune I chose is Blue Danube to recreate the 2001 Space Odyssey atmosphere. Ok that is a little bit optimistic but nevertheless I think it provides an interesting calm background to the stressful gameplay.
The song uses three voices and piano for all three and continuously repeats.
Of course the menu has an option to turn it off if it becomes too annoying.
Sound effects are recreated using two channels. Primarily they are used for main engine and side thrusters and since they can be used simultaneously we use two separate channels. We also use both channels for explosion.
Collision detection
This part of code is obviously the most interesting because if we want to have a really smooth and fair game we have to implement “pixel perfect” collision detection. The goal is pretty simple. We have to check every single pixel of our lander and check if any overlaps any non black pixel on the background. It really doesn’t matter if we crash into a mountain or one of the animated parts of the background.
Unfortunately BASIC simply can’t handle checking all the pixels that our lander overlaps in every cycle of game loop so we have to write a collision detection routine in assembly and call it from BASIC and then have a way to return the result back to BASIC.
Collision detection routine is about 1K bytes long and is loaded into memory starting at location $7000. So we call it from BASIC with simple call
SYS $7000
And then we check if there was collision detected by reading memory location $60 using PEEK command. In BASIC Code that simply looks like this:
590 SYS $7000:IF PEEK($60)<>0 THEN GOTO 2000
Clearly if memory location 6 contains a non zero value there was a collision and we have to handle it otherwise we continue the execution of the Game loop.
At the end of this post I included a link to all the source code, including Assembly of collision detection. The detailed description is beyond the scope of this tutorial but just a few hints if you want to determine exactly how it works here are some pointers:
- It first reads the X and Y position of the Sprite 1 and stores it in local memory
- It then calculates the VRAM location of top left byte of graphics overlapped by sprite using the following formula: $2000 + Y*160+X/2
- This is followed by copying the VRAM content to local memory. We need to copy 16x16 pixels or 8x16 bytes.
- Because each byte in Video memory contains two pixels the sprite can be aligned to top or low nibble, therefore we need to choose the correct sprite mask.
- Now that all the heavy lifting is done, we simply run a loop and perform a logical AND function between the background and sprite mask.
Memory organization
CPU Memory
Location | Description |
---|---|
$0801 | Start of Basic Program |
$8000 | Start of COL.PRG, assembly collision detection function |
$9000 | Start of PLAY.PRG, Music Player |
$9800 | Start of Music data |
Video memory
Memory range | VERA Setting | Size | Description |
---|---|---|---|
$00000 - $01FFF | $00 - MapBase | $2000 | Layer 1 HUD (128 x 2 x 32 = 8K) |
$02000 - $0B5FF | $10 - MapBase | $9600 | Layer 0 Background (320 x 240 / 2) |
$00000 - $12BFF | $5C - TileBase | $12C00 | Title Screen (320 x 240 = 75K) |
$1E800 - $1EBFF | $F4 - Tile Base | $400 | Font (128 x 8 = 1K) |
$1EC00 - $1F7FF | $60,$F - Pointer | $C00 | Sprites (16 x 16 x 12 = 3K) |
$1F800 - $1F9BF | $1C0 | Free 448 bytes |
Source Code Organization
Line | Description |
---|---|
0-100 | Setup |
Game play loops and main entry points | |
100 | Configure Graphics and Sound |
200 | Start of New Game |
300 | Set Level |
400 | New Life |
500 | Game loop start |
700 | Display main thruster |
1000 | Level 1 Custom function |
1100 | Level 2 Custom function |
1200 | Level 3 Custom function |
1300 | Level 4 Custom function |
2000 | Check landing |
2100 | Crashed |
2200 | Successfully landed |
2500 | Display Explosion animation |
3000 | Set Level 1 variables |
3100 | Set Level 2 variables |
3200 | Set Level 3 variables |
3300 | Set Level 4 variables |
Display Functions | |
5000 | Display Crash or Game Over Messages |
6000 | Game Won Message |
7000 | Display Score |
7100 | Display Descent rate |
7200 | Display Fuel gauge |
7300 | Display Message frame |
8000 | Display HUD on Layer 1 |
8500 | Display Options |
Graphics settings | |
10000 | Set Layer 0 to Game play bitmap |
10500 | Set Layer 0 to Title screen |
10800 | Redefine color palette (blues and pure yellow) |
10900 | Return to default palette (for title screen) |
11000 | Configure Sprites for Lander and Thruster flame |
Menu and Options | |
13000 | Display Options |
13100 | Process Options |
13500 | Configure Options |
Sound and Music | |
14000 | Configure Voice 0 and 1 for main engine and side thrusters |
14200 | Load Music to memory |
14500 | Music data |
14700 | Music ON |
14800 | Music OFF |
Files
Files used by the game:
Filename | Description |
---|---|
CRAZYLANDER.PRG | Main BASIC Program |
COL.PRG | Machine code function for collision detection |
PLAY.PRG | Music Library for BASIC programs |
FONT.BIN | Custom font |
LANDER.BIN | Spritesheet |
TITLE.BIN | Title Screen bitmap |
LEVEL1.BIN | Level 1 bitmap |
LEVEL2.BIN | Level 2 bitmap |
LEVEL3.BIN | Level 3 bitmap |
LEVEL4.BIN | Level 4 bitmap |
Link to all the files is available on GitHub here.
Comments
Post a Comment