A$$emble IT - Programming tutorial

Project Housekeeping and Additional Game Programming

Project Housekeeping / Custom sprite movement / Directional Detection Movement / Game 9: Granny's Teeth (Craptastic version) / Recorded Path Movement / Timed Control Movement

Project Housekeeping

Probably the most boring subject in the Assemble It feature, but it can be a good option for you to learn from. Although there is nothing to download from this little chapter. There are some example games which also use the housekeeping method anyway. So how helpful is this part of the chapter supposed to be for you?. Let us put things this way. If you were to create a bigger game project, and use just one assembly file to program your game. There could be very long strings of code, and you can easily get yourself lost. (Like you probably are already in this part of the chapter).

Let us say for example, you are writing a new C64 game, it has a title screen, the main game, and fully animated end sequence. You should create SEPARATE assembly files in which should be linked to your project. Let us take for example, Missile Blasta (from the previous chapter) for example. The game should be split into separate assembly files: The main project code (to assemble to should be MISSILEBLASTA.ASM TITLESCREEN.ASM, GAMECODE.ASM, ENDING.ASM. (To create your own assembly source code, simply do the same as you did before when you created a new project. (ADD, NEW ASSEMBLY FILE, enter name of your assembly code). It will be placed in the project.

Now what if you wanted to link the entire source together, which you already done - placed into separate files?

Simple:

You enter !source "assemblyfile.asm"

An example for setting a Missile Blasta V2, project with additional ASM files would sort of look something like this:

;Missile Blasta - Remastered V2
;by Richard Bayliss
;For Assemble It 2018

    !to "MISSILEBLASTA.PRG",CBM

;setup basic / sys start address (since nothing
    ;is overlapping memory $0801)

    *=$0801
    !basic 2018,$3800

    *=$0c00
attribs
    !bin "bin/attributes.bin"


    ;insert the sprites
    *=$2000
    !bin "bin/sprites.bin"

    ;insert the status screen (pre-built from older build)
    *=$2700
    !bin "bin/status.prg",,2

    ;insert the game binary charset
    *=$2800
    !bin "bin/charset.bin"

    ;insert the game screen binary (made from charpad)
    *=$3000
gamematrix
    ;insert the game screen matrix (made from charpad)
    !bin "bin/screen.bin"

    *=$3400
titlematrix
    ;Insert the title screen matrix (made from charpad)               
    !bin "bin/titlescreen.bin"

;Main game code
    *=$3800
    !source "GAMECODE.ASM"
;
Insert title screen code
    !source "TITLECODE.ASM"
;
Insert end sequence code
    !source "ENDCODE.ASM"

scorebackup
    !bin "bin/status.prg",,2
    ;insert the music (,,2 prg)
    *=$8000
    !bin "bin/music.prg",,2
    ;goat tracker custom sound effects table

So remember, any time you create a new C64 project (Which you will discover in the next few chapters on this page), always organize your project into separate parts. It isn't all that hard.

BACK TO TOP



Custom Sprite Movement

There are several different ways in which you can make a custom based movement of an object. Let us say for example rather than a sprite going one specific direction, you can alter directions for each sprite.

The directional detection movement

Example: Honey Bee



There is also another method to sprite movement. Let us take for example you are writing a game, such as Honey Bee, Balloonacy or any sort of single screen dodge, collect and platform game. You would want to have objects moving in a fixed direction, then flip from one direction to another. This is probably the most simplest approach to custom sprite movement. A subroutine is called to first check the value of a pointer, for example ObjDir is set as the object direction. If the value of ObjDir is set to a specific value, called, for example 0 = Up, 1 = Down, 2 = Left, 3 = Right then the code should call the sprite object to move that specific direction. That is of course until it reaches the set limited position, from either a fixed value, or a value from a custom pointer. Then the code forces the object to change direction. The code snipped below shows an example of how to move a single sprite object using that specific method.

;Move sprite, according to direction snippet

TestObjectDirection
    lda ObjDir
    cmp #UP
    bne NotUp
    jmp MoveUp

NotUp
    cmp #DOWN
    bne NotDown
    jmp MoveDown

NotDown
    cmp #LEFT
    bne NotLeft
    jmp MoveLeft

NotLeft
    cmp #RIGHT
    bne NotRight
    jmp MoveRight

;Move sprite UP, then once set at limited position,
;switch the direction to DOWN.

MoveUp
    lda ObjPos+1    ;Grab position of object Y
    sec
    sbc #2          ;Movement speed backwards
    cmp #$32        ;Stopping position
    bcs UpdateUp    ;Not reached destination yet
    lda #DOWN       ;Force DOWN to pointer ObjDir
    sta ObjDir
    rts
UpdateUp            ;Store new position to object Y
    sta ObjPos+1
    rts

;Move sprite DOWN, then once set at limited position,
;switch the direction to UP.

MoveDown
    lda Objpos+1    ;As before, grab position of object Y
    clc
    adc #2          ;Movement speed forwards
    cmp #$f2        ;Has sprite reached the bottom?
    bcc UpdateDown  ;Not reached destination yet
    lda #UP         ;Force UP to pointer ObjDir
    sta ObjDir
    rts
UpdateDown          ;Store new position to object Y
    sta ObjPos+1
    rts

;Move sprite LEFT, then once set at limited position,
;switch the direction to RIGHT.

MoveLeft
    lda ObjPos      ;This time we are using X
    sec
    sbc #1          ;Movement speed backwards
    cmp #$0c        ;Has sprite reached left most limit
    bcs UpdateLeft  ;Not reached destination yet
    lda #RIGHT      ;Force RIGHT to pointer ObjDir
    sta ObjDir
    rts
UpdateLeft          ;Store new position to object X
    sta ObjPos
    rts

;Move sprite RIGHT, then once set at limited position
;set the direction to LEFT.

MoveRight
    lda ObjPos       ;Grab current position of sprite
    clc
    adc #1           ;Movement speed forwards
    cmp #$a2         ;Has the sprite reached right most limit?
    bcc UpdateRight  ;Not reached destination yet
    lda #LEFT        ;Force direction LEFT to pointer ObjDir
    sta ObjDir
    rts
UpdateRight           ;Store now position to object X
    sta ObjPos
    rts

This code snippet above shows only an example of moving one sprite back and forth, depending on which direction you have set the pointers. But what if you wanted to do this to ALL 8 sprites? Well, it is possible to move each sprite individually using multiple routines and macros. Simply define some pointers for direction for each sprite, also define macros correctly and call a few subroutines to test each sprite movement. Also have a play around with the example source snippet and see what you can make from it.



View source code



BACK TO TOP

  

GAME 9: Granny's Teeth (The original 4K Craptastic Compo version)

Although I have showed you an example of the code above to allow all 8 sprites move according to path/direction. We are going to show you an example game, which uses a similar approach, although it is quite an old game. Back in 2016 I entered the C64 craptastic game making compo, which was to create and develop a game that squeezed into 4K (after compression through the ALZ64 compressor). It was a platform game, inspired by one of those games creator games, from back in the early-mid 1980's. This game was made to look a bit like one of those Games Creator/Creations games, only just for fun. However, to prove that this game was NOT made with the games creator. A complete project binary+source has been provided to accompany this chapter on fixed sprite movement and changing directions.

So what's this game all about?. You play the role of Granny, who has tucked her grandchildren into bed. Locked all of the doors, and placed her teeth safely into her room and went to sleep. The next morning, Granny wakes up to find her teeth had gone missing. Also, she finds that her house has been ransacked. The floorboard had collapsed revealing that her house was built over a swimming pool. Her cat and dog are on the loose, a bird has flown in, and who the heck let that spider in?. If all was that bad? Her teeth had gone missing. The kids were playing with her teeth and thrown them into the fishbowl. It is now up to you to try and fish your teeth out.

Granny must jump from platform, to platform, avoiding contact with any tacks strewn on the floor. She cannot swim either. She has to avoid any moving objects or pets in sight and pick up her teeth. You will score bonus points and move on to the next level for every time teeth have been picked up.

This game also features an implementation of Achim Volker's useful Sprite/Background collision which calculates the X, Y position of the player sprite, and checks whether or not the lower part of the sprite is touching the pixel of the background (When using software sprite/background based collision, X and Y position of the player sprite must be accurately set to the pixel which the player object lands. This game also uses the directional control of the sprite movement, similar to very first example in this category. A software sprite/sprite collision detection is used. The project also uses the project housekeeping method which helps organize the program files and code. The active assembly file is of course Granny.asm. So this file should be marked as active source when compiling the binary data and code.



Download the full C64 Studio binary + source code to Granny's Teeth



BACK TO TOP




You are writing a space shoot 'em up. You have a player which is controlled by a joystick. The player can fire, but there are also enemies that can move around. There are two different ways in which you could create an attack movement pattern for an enemy sprite. They are as follows:

Recorded Path Movement

Example: X-Force



The recorded path movement is simply created utility based. The utility based path movement, is where you record and create the movement, according to the position of a sprite you set it. A maximum of 256 units is used for making your own alien path movement. One particular tool which can produce custom object movements, based on sprite position is the TND Alien Movement Maker V1.0+ (Available in the utilities section). This tool allows you set a starting position to a sprite and then record its movement. Be very careful when using this. You'll need to remember the screen size which you plan your game project.  I first created my own source code to do this for the game X-Force (pictured above). A small code example for moving an object based on table movement would look something like this:

;Example path movement code (based on reading the table)

MoveEnemy1
    ldx Enemy1MovePointer     ;Pointer to set position of enemy
    lda PositionTable,x       ;Read PositionTableX to grab a X position
    sta EnemySpritePosX       ;Write the position to the sprite X position
    lda PositionTable+$100,x  ;Read PositionTableY to grab a Y position
    sta EnemySpritePosY       ;Write the position to the sprite Y position
    inx                       ;Increment value of pointer loop for moving object
    beq RemoveEnemy1          ;Until all 256 byts are read
    inc Enemy1MovePointer     ;Increment EnemySpritePos X+Y table by 1 byte
    rts                       
RemoveEnemy1                  ;All 256 bytes from X+Y position table complete.
    ldx #0                    ;Reset the pointer of the enemy movement
    stx Enemy1MovePointer
    jsr SetNextTable          ;Call a subroutine to move the next table.
    rts

;Example binary file (inside project)

    *=$7000 ;Or where to put the movement data
PositionTable
    !bin "movement.prg",,2

I'll show you how it is done properly, when we do GAME 9.  Using C64Studio. Please also note that this method uses slightly more memory. Alternatively, if you cannot wait all that long .... You can check out issue 27 of Scene World, and check out the source code for Zap Zone 




or alternatively, if you want to learn an even bigger/advanced phase in game programming. You could always try 
Star Toast
from issue 28 of Scene World magazine. Please note that both games were coded in 64ASM, which means that you will need to alter some of the pseudo commands, should you wish to port those games to C64STUDIO, and tweak the code for fun. (Or make your own game from it).




BACK TO TOP



The Timed Control  Movement



Example: Starfysh

There is also another example, which is slightly trickier, compared to the option (above). Especially if you want to have objects using timed movement, based on behaviour patterns. This is because you need to use MORE pointers, although it does use less memory. The trick does work a treat. You first set the starting X, Y position of a sprite. Set the pointer/delay and then another pointer read, to read the table position, also your read the speed table of the sprite. After the time of one position has expired, the table read pointer increments to the next position on the table, recording the next X,Y speed (direction) of the object. Then store it to the sprite position. Sometimes this can result into awkward consequences, but eventually you can get some great enemy movement patterns - and not just going one straight direction.

;Example timed speed object movement

MoveEnemy1
   

        lda objpos+4
        clc
        adc Alien1XSpeedStore
   
        sta objpos+4
        lda objpos+5
        clc
        adc Alien1YSpeedStore
        sta objpos+5
       
        ;Calculate flip properties - So that
        ;the movement can be triggered to change

        ;direction
        jsr Alien1FlipTest           
        rts

;Actual flip test for alien 1

Alien1FlipTest

        lda Alien1FlipDelay    ;Alien flip delay test ... Counter
        cmp Alien1_FlipTime
        beq Alien1SwitchToNextMotion ;Switch to next motion from table
        inc Alien1FlipDelay
        rts

        ;Switch alien motion

Alien1SwitchToNextMotion
       
        lda #$00                ;Reset alien flip delay
        sta Alien1FlipDelay
        ldx Alien1FlipPointer   ;Read pointer
        lda Alien1_XSpeed,x     ;Read selected X direction/speed from table
        sta Alien1XSpeedStore   ;Store it to alien speed X (Alien1SpeedStore)
        lda Alien1_YSpeed,x     ;Read selected Y direction/speed from table
        sta Alien1YSpeedStore   ;Store it to alien speed Y (Alien1SpeedStore)
        inx
        cpx #$04                ;Has the table reached the last byte on each speed table?
        beq Alien1SpeedReset    ;Yes ... Reset the speed table.
        inc Alien1FlipPointer   ;Then move to next table setup (To be Self-modified)
        rts

        ;Reset flip table and delay for alien 1

Alien1SpeedReset           
        ldx #$00
        stx Alien1FlipPointer
        lda #$00
        sta Alien1FlipDelay
        rts
       
        ;Time alien 1's movement. Has it reach its movement deadline
        ;if so. Switch over to the next set of properties for the next
        ;alien. Then spawn the next alien object.

TimeAlien1Movement
        lda Alien1MovementPointer   
        cmp Alien1_MoveTime
        beq Alien1WaveComplete
        inc Alien1MovementPointer
        rts
Alien1WaveComplete       
        lda #$00
        sta Alien1MovementPointer
        lda #1
        sta Alien1Offset
        rts

BACK TO TOP


COMING SOON: Charset Animation, Horizontal map scrolling and GAME 10: BLASTOPIA