Learn Multi platform ARM Assembly Programming... For the Future!

SuckShoot Series

In this series we'll learn a simple game called 'Suck Shoot'... Well learn how to compile it, and run on an emulator.


Lesson SuckShoot1 - SuckShoot General Code
Suck Shoot is a little shooter game where we have to shoot bats within a short time period.

It's based on the simple series joystick example, and is meant as a 'template' for making a little game.

GBA_SuckShoot.asm

You can play SuckShoot!
Suck Shoot is a 'miniature' version of my larger "Suck Hunt' game...

Gameplay is simple, you have to shoot bats flying towards the screen... the more you shoot, the faster they get!

SuckShoot uses the BCD, Range Checking and Random number code covered in the Multiplatform series

Here we're going to take a look at the code which is pretty much the same on all systems, here we'll look at the GBA, but the NDS code is also virtually identical!
Title Screen
The Title screen shows the game name, current highscore, and an animated bat!

First we wait for fire to be released, clear the screen, and silence the sound.

We then show our text strings for the title and highscore text.

Next we show the hiscore itself, using Binary Coded Decimal

We need to show our animated bat, we need to position it, and set the scale to 48 to make the bat as big as possible.
We need to flip the enemy sprite number between 0/1 to animate the sprite,
we then wait a while, and remove the bat - the sprite is XOR inverted, meaning showing it twice will remove the first.

We read from the joystick and loop until fire is pressed.

Main Game Loop
When the game starts we need to set up the game variables.

We zero the score, and set the lives to 4...

We randomize the enemy position and show the score and lives to the screen

Next we set the Player XY pos in R8,R9 and show the starting position of the player and enemy.
At the start of the main loop we have the 'sound driver'.

We use my 'ChibiSound' driver from the Platform specific series, which takes a single byte parameter and produces tones and FX.

This has a 'timeout' after which the tone will be silenced.
We need to handle the player movement - this is based on the simple series.

We process each direction and move the player accordingly.

Fire 2 can be used to speed up movement!
When Fire 1 is pressed we need to shoot.

First we make a sound if one isn't already playing.

Next we see if the enemy is in range of the crosshair with 'RangeTest' - this was covered in the multiplatform series.


If we hit the enemy, the enemy is given a new position, and moved back to the smallest size. We also speed up the enemy for next time.

We give the player some score, and make a sound.
Next we need to update the enemy

First we increase the 'Tick'... and if this goes over 255 we toggle the frame of animation.

Next we update the 'speed'... this decides if the bat will move. if it's time for the bat to move we add 8 to the scale - this will make the bat get bigger / closer.

If the size has reached 64 then the bat has bitten the player!... in this case we reset the bat, and take one life from the player - if the player has zero lives it's game over!


Finally we have a delay, and repeat the main loop.

Game over
The Gameover screen clears the screen and shows the 'Game Over' message.

Next we check the score, and compare it to the highscore.

If we've got a highscore we show the 'new highscore message', and transfer the score into the highscore.


If we didn't we show an insulting message to the player!

Next time we'll look at the platform specific code, that is the sprite drawing routines and joystick routines which are specific to that system.



Lesson SuckShoot2 - SuckShoot GBA Graphics code
Lets take a look at the platform specific code on the GBA of SuckShoot!

GBA_SuckShoot.asm


Data Definitions
We need some bytes of RAM for the enemy data, the text cursor and a few other things.

These are defined in the RAM area of the GBA
There are two kinds of data for the sprites.

The first is the bitmap data itself in "GBA_Suckshoot.raw"

The SpriteInfo table holds 8 bytes per numbered sprite,

The first 4 are a pointer to the start of the sprite bitmap in the bitmap data block.
The next 2 are the Width and Height of the sprite in pixels.
The last 2 are unused, they are just there to space out the block to 8 bytes.
Graphics routines
At the start of our program we turn on the screen.
We have a Clear screen routine to wipe the screen memory
When we want to show a sprite, we must calculate the offset for that sprite in the SpriteInfo Table...

For the bat sprite, there are 3 scales, and 2 frames per scale.

The first sprite is the player crosshair, the next 6 are the bats, so we add 1 to the sprite number to skip the player sprite, and convert the 'scale' to a number 0/2/4
The X,Y position we draw the sprite to is the CENTER of the sprite (so the range checking works)

To facilitate this, we subtract half the width and height of the sprite, effectively centering it.

We then calculate the VRAM destination for the sprite.
We transfer all the bytes of the sprite from the source bitmap, to the VRAM destination.

Joystick routine
We read in the joystick directions from 0x4000130.

Here we're converting them to a 'common format' I use in my tutorials - 0b4321RLDU.

The first 4 bits are the directions Up,Down,Left, Right... The remaining bits are fire buttons and start buttons.

We've got the game working on the GBA... next time we'll port to the NDS.

There isn't actually much difference! we just need to make a few tweaks to our code to get the game running on the NDS


Lesson SuckShoot3 - SuckShoot NDS Graphics code
Lets take a look at the platform specific code on the NDS version of SuckShoot!

NDS_SuckShoot.asm


This version of the game is a port of the GBA version!
We'll take a look at what needed to change to get the game working on the NDS.

Data Definitions
We need some bytes of RAM for the enemy data, the text cursor and a few other things.

The address we need to use for the  the RAM on the NDS is different to the GBA
There are two kinds of data for the sprites.

The first is the bitmap data itself in "GBA_Suckshoot.raw"

The SpriteInfo table holds 8 bytes per numbered sprite,

The first 4 are a pointer to the start of the sprite bitmap in the bitmap data block.
The next 2 are the Width and Height of the sprite in pixels.
The last 2 are unused, they are just there to space out the block to 8 bytes.

The sprites are the same as the GBA version
Graphics routines
At the start of our program we turn on the screen.

on the NDS we also need to enable the ram and LCD
We have a Clear screen routine to wipe the screen memory

The address of the VRAM base is different on the NDS
When we want to show a sprite, we must calculate the offset for that sprite in the SpriteInfo Table...

For the bat sprite, there are 3 scales, and 2 frames per scale.

The first sprite is the player crosshair, the next 6 are the bats, so we add 1 to the sprite number to skip the player sprite, and convert the 'scale' to a number 0/2/4
The X,Y position we draw the sprite to is the CENTER of the sprite (so the range checking works)

To facilitate this, we subtract half the width and height of the sprite, effectively centering it.

We then calculate the VRAM destination for the sprite.

The address of the VRAM base, and the size of the screen is different on the NDS
We transfer all the bytes of the sprite from the source bitmap, to the VRAM destination.

The line size is different on the NDS

Joystick routine
We read in the joystick directions from 0x4000130.

Here we're converting them to a 'common format' I use in my tutorials - 0b4321RLDU.

The first 4 bits are the directions Up,Down,Left, Right... The remaining bits are fire buttons and start buttons.

This is unchanged on the NDS

Sound Routine
We're using our ChibiSound driver on the NDS too, but it has to run from the ARM7 processor on the NDS.

This is a bit of a pain, but allows us to get things working.
We've also had to change our Font drawing routines with new screen base and screen width... Also the screen width has been updated on the cursor movement and random enemy routines.



Lesson SuckShoot4 - SuckShoot RiscOS Graphics code
Lets take a look at the platform specific code on the RISCOS version of SuckShoot!

ROS_SuckShoot.asm


Unfortunately the RISCOS version does not have sound!

This is because the author hasn't written a ChibiSound driver for RiscOS yet because he's a lazy git!

Data Definitions
We need some bytes of RAM for the enemy data, the text cursor and a few other things.

These are defined at the start of the program.
There are two kinds of data for the sprites.

The first is the bitmap data itself in "ROS_Suckshoot.raw"... We're using 16 color mode in Risc OS

The SpriteInfo table holds 8 bytes per numbered sprite,

The first 4 are a pointer to the start of the sprite bitmap in the bitmap data block.
The next 2 are the Width and Height of the sprite in pixels.
The last 2 are unused, they are just there to space out the block to 8 bytes.

Graphics routines
At the start of our program we turn on the screen and set up our palette.

Please see the simple series bitmap example for more details.
We have a Clear screen routine to wipe the screen memory
When we want to show a sprite, we must calculate the offset for that sprite in the SpriteInfo Table...

For the bat sprite, there are 3 scales, and 2 frames per scale.

The first sprite is the player crosshair, the next 6 are the bats, so we add 1 to the sprite number to skip the player sprite, and convert the 'scale' to a number 0/2/4
The X,Y position we draw the sprite to is the CENTER of the sprite (so the range checking works)

To facilitate this, we subtract half the width and height of the sprite, effectively centering it.

We then calculate the VRAM destination for the sprite.
We transfer all the bytes of the sprite from the source bitmap, to the VRAM destination.

Joystick routine
We don't actually use the joystick on RiscOS, we use the keyboard,

We test UDLR and Space and enter as fire buttons, setting one bit in the returned byte for each direction

PrintChar Routine
We need to use a bitmap font to draw text on the screen.

In these tutorials we use a 1bpp font on all systems to draw characters to the screen.

We calculate the screen destination based on CursorXY pos.

Our font has no characters lower than 32, and each character uses 8 bytes, we use this to calculate the offset in the bitmapfont.

As we have 8 pixels per line, and we're in 16 color mode, we need to move 8 bits from our font into 4 destination bytes, we use a series of masks and ors to shift the bits into the destination.