Crazy Boulders

Boulder Dash style game is another project completely written in Commander X16 Basic with just a little help from Simplest Sound Effect Library. We wrote couple of games in Commander X16 BASIC already so many of the functionalities like reading keyboard/joystick, handling game loop, configuring tiles, etc. are similar so we will not go deep into describing them but will instead focus on three main new features:
  • Develop in two phases
  • Use of animated sprites
  • Use hardware scrolling

Project Specs

  • Emulator Version R.38
  • Low Resolution tile mode 40x30
  • Full color tiles
  • Sprite for main character
  • Introduce full color graphics mode for Title screen
  • 5 levels with easy possibility to add more later
  • Each level has time limit
  • Each level has minimum number of diamond to be collected before player can move to next level
  • Scoring system
    • Each diamond is 100 points
    • Additional 50 points for bonus diamond after the minimum is collected
  • Keyboard/Joystick controls:
    • Left arrow / Joystick left – move left
    • Right arrow / Joystick right– move right
    • Up arrow / Joystick up - move up
    • Down Arrow / Joystick down - move down
  • Basic sound effects:
    • Ping for collected diamond
    • Shoot for falling boulders
    • Zap for moving through door to next level
    • Explode for dying

Prototype

We will approach this project in two steps. Since it requires a lot of graphics, unusual screen mode (16x16 pixel tiles), scrolling, layers, transparency etc. it would be quite hard to troubleshoot.
This type of puzzle game also requires mechanics to be defined and tested to be sure our algorithms work properly before we add all the graphical overhead and polish it. And to emphasize again, it is much easier to clean up the code before we add hundreds of lines of code to support pretty graphics.

OK. Let’s define basic parameters of the game and mechanics:
  • Maze is 40 tiles wide by 22 tiles tall
  • Each type of tile has different role and related behavior
  • Each level has different set of parameters;
    • Time allowed
    • Number of diamonds that need to be collected before moving to next level
    • Points per required diamonds and points for bonus diamonds


Before we start coding, let’s precisely define the role and behavior of each tile type:

Edge and Brick wall

These two types behave in the same way. They are unmovable, they can’t be walked through and they can’t be destroyed (at least not in our simplified version). Boulders that land on them can’t slide off to the side even if there is empty space to the side.

Dirt

Dirt can be easily dug and has no effect on our hero, he can walk right through and clear it away and leave empty space behind. Very important feature of the dirt is that it keeps boulders in place.

Boulders

Boulders are key elements in this game, for that reason they have few very important behaviors. First of all if they fall on our hero they kill him! They also fall if they are not supported from below by any object except empty space. If there is empty space under they will keep falling until they hit something solid. There is one special situation. If they hit another boulder, which has a curved top surface, they have to roll to the side as long as there is empty space to the either side of the object under.

Empty space

As its name implies the empty space does not have any special behavior but beware the empty space allows boulders to fall through.

Door

The exit door behaves like a solid tile, similar to the edge or brick wall until the player collects enough diamonds. When that happens the door changes to indicate that passage is possible and allows the player to go through and to the next level.

Diamonds

Collecting diamonds is the goal of this puzzle game. When a player steps on the diamond he/she collects it and creates an empty space similar to walking over dirt.

For the prototype we will use the default screen mode and display the whole maze and instead of sprite we will just use the star character. We will use strings to define the level and use numbers that can easily be transformed to indexes to choose the characters and colors to be drawn to the screen. Let’s take a look at the prototype screen:




We have all main tiles represented using standard PETSCII characters. Let’s take a look at the most important part of the code that we develop and thoroughly test at this phase.

Data Structures and game mechanics

The game is fairly simple, especially in case of our simplified physics but we still have to introduce some interesting data structures in order to work correctly. The main feature is falling boulders. In order to track them we will create an array to keep track of all the ones that are falling at all times. We use simple arrays for that:

FX(50) - X coordinate for the falling boulders
FY(50) - Y coordinate for falling boulders
F - Number of falling boulders at any given time

This array is used to loop through during each game loop cycle and moves them down one row creating an effect of falling. In order for that function to be as fast as possible it is very important that the above double array is always sorted from higher Y to lower. That means we always move boulders that are lower on the screen so they don’t crash or overwrite each other.



As a player walks around the field he/she can dislodge boulders. The location of the dislodged boulder is stored in CX and CY and then inserted into a sorted array at the appropriate location. Because this check happens during the player movement we can add them to the array immediately. On the other hand when a falling boulder dislodges another boulder above we have to delay adding those for two reasons.
First one being that we are already in the loop processing falling boulder, adding new elements would make it more complex and it is more realistic from the physics perspective that boulders have a short delay before they start falling and follow boulder(s) below.
Therefore we introduce the Waitlist which is structured the same way as falling boulder arrays:

WX(20) - X coordinate of the boulder waiting to start falling in the next cycle
WY(20) - Y coordinate of the boulder waiting to start falling in the next cycle
W - number of boulders in the Waitlist

These arrays do not need to be sorted so we can just add them at the end and increase the counter W. 

The only remaining critical part of code that is unique to this project is the boulder movement. Let's look at the source code:


The above code has 5 sections that perform important functionality;

Lines 4000-4080 This part is responsible for moving boulders. Of course if F=0 there are no boulders falling at this time so we can just exit. If there are we have to loop through the array of all of them. Remember the arrays are sorted with boulders from bottom to the top of the screen.
Variable TB is used to hold the ID of Tile Below which of course represents location where the boulder should move next. This is in a way a collision control for the boulders that we will use to decide what happens next.
In lines 4090-4110 we check if tile above contains stationary boulder. That can only happen when we dislodge it and they are stacked one on top of another. In this case we add that boulder to waitlist.
Code in lines 4210-4290 checks the space where we are supposed to move our boulder and is not empty. It is really a collision control section for boulder and it is here that we check if the player was killed or if boulders fell to the ground or another boulder and has to fall to the side.
In the line 4310 we mark the current boulder for removal since it reached the end and has to stop falling. 
Lines 4710-4760 are responsible for removal of stationary boulders from the list and making sure that the arrays stay sorted and without gaps.
At the end in lines 4780-4830 we add boulders from the waitlist.

Release version

Now that we have prototype working we can focus on visuals and fine tuning playability and not worry about algorithms that much. Let's take a look at the fun part, graphical resources used:
  • tileset
  • spritesheet
  • title screen
  • fonts

The overall screen resolution will be 320 x 240 pixels and we will use two layers for display:
Layer 0 - scrollable maze
Layer 1 - static HUD Layer 0

Tileset

Tiles will be 16x16 pixels and since we only need a few tiles we can go with full 256 colors. The size has to be 64 tiles wide with 32 tiles tall. Layer 1 On layer 1 we will use just standard text mode but to add some more unique look we will use a custom font. Tile set I drew up tiles in Paint.net and transformed it into a binary file. This game is using 16x16 tiles which in original had to be constructed from 2x2 characters. Of course Commander X16 supports 16x16 pixel tiles which should make moving data to video memory much faster. The game requires following tiles:



Spritesheet

Our hero will be Sam we designed in the Sprite animation tutorial, we might just adjust colors a little bit because we initially designed it with black outline. With mostly black background that doesn't work, besides we have plenty of video memory available so we can just take advantage of 256 colors and use some shading for more defined character.



There is obviously some redundancy in our sprites. We could use sprite flipping functionality but that would add some small amount of complexity and speed so this time we choose to use more memory for a bit more speed simply because we abundance of memory available.

Title Screen 

At the start of program we will display full graphics title screen in 256 colors and 320 x 240 pixel resolution. It is not the most artistic drawing I have ever seen but it demonstrates the capabilities of the Commander X16 to display really very colorful graphics.



Fonts

We will use a custom font LIGHTFONT.BIN.



More about fonts can be found on my Fonts post here.

Sound

Sound effects are very important for every game and even though it is fairly easy to generate sound on the Commander X16 it is not easy to create interesting effects because those require precise timing and BASIC programs are simply not suitable for that. Therefore we will use a simple library I wrote in assembly and load it into our program. More about how it works on my blog post here.



Files

Files used by the game:

Filename Description
CRAZYBOULDERS.BAS Main BASIC program
TITLESCREEN.BIN Title screen 320x240 pixel art in 256 colors
TILESHEET.BIN Tile set graphics
SPRITE.BIN Sprite definitions for our main character
LIGHTFONT.BIN Light font used in the game for HUD and messages
EFFECTS.PRG Simplest Sounds Effect Library

Link to all the files is available on GitHub here.

Comments

Popular posts from this blog

Commander X16 Premium Keyboard

Hello VERA (BASIC vs C vs Assembly)

Default Palette