Chapter 5: SPRITES, GRAPHICS AND PROGRAMMING YOUR OWN GAMES

What is a Sprite?

A sprite is a small object that can be moved around the C64 screen. A sprite is usually used in games and demos. Sprites can be repositioned, moved and also use hi-res or multicolour. Later on we are going to try and make a nice little 2 player game that involves sprites. But that will be in a later chapter. What we are going to do is play around with sprites. Here is what to do.

1. Load a sprite editor (You might have to download it)
2. Draw a sprite (can be anything)
3. Save to disk
4. Use an action replay cartridge and load in your own sprite at $2000, using the M/C prompt: L "(filename),8,2000
5. Load up and enter turbo assembler
6. Read on.

Right, the first thing, which we are going to do is learn how to turn the sprites on and off. If you remember right, $D020 was for border colour, but what's that to do with sprites? Ehm, nothing.

Turning On/Off Sprites

We use $D015 to turn on sprites. To turn a sprite on we can use LDA #$01, STA $D015, or if you wanted all 8 sprites turned on, we use LDA #$FF, STA $D015. This will be easy to remember.

Setting Sprite Properties

Also, setting up your sprite correctly would be quite tricky. Anyway, because we are using bank $03 on the C64, we will use $07F8 - $07FF for our sprites. However, because our sprite data is loaded at $2000, we will need to use LDA #$80, STA $07F8 (for sprite 1), STA $07F9 (for sprite 2),etc. LDA #$80 reads from the first few lines at $2000 and then pastes it into $07F8, etc to perform a perfect display for your sprites.

Sprite Positioning

To position sprites, we use $D000 - $D00F. Why are there 16 instead of 8 values? Well, the reason for this is because $D000, $D002, $D004, $D006, $D008, $D00A, $D00C, $D00E use the sprite's x-axis, while $D001, $D003, $D005, $D007, $D009, $D00B, $D00D, $D00F all use sprite's y-axis, both of these are according to the sprite number. Here is a simple routine to get you started on how to position, display and turn on sprites. Call out a start (*=xxxx) and SEI then enter the following.

A Practical Example with Sprites

LDA #$01   ;1 SPRITE
STA $D015 ;TURN ALL SPRITES ON
LDA #$80
STA $07F8
LDA #$70
STA $D000
LDA #$89
STA $D001
RTS

Assemble and run. You will see your sprite sitting on the screen at x = #$70 pixels, and y = #$89 pixels. However, 1 sprite is not enough, so let us make another 7, turn all sprites on and then position them into different places. Refer to the example at the top, then you'll know what you're doing :o)

Sprite Colours

This is something which we have not looked at in this feature. Sprite's colours are simple. We have a hi-res sprite which needs a touch of colour, so here's how it is done. The colour refers from $D027 (sprite 1) to $D02E (sprite 8)

LDA #$colour
STA $D027

You can even toggle multicolour sprites, using LDA #$FF, STA $D01C (Multi colour) and to change the 2 multi-colours, we use STA $D025 and STA $D026. $D025 uses multicolour 1, and $D026 uses multicolour 2. To get these to work, we need to set LDA #$colour before STA. The 'colour' has to be between #$00 - #$0F, as these are the main 16 colours. (Please refer to your C64 user guide).

Priorities

Sprites have their own priorities. You can put certain sprites in front or behind the characters on screen. This can be toggled by using $D01B. For example LDA #$00, STA $D01B puts all sprites over the text, and LDA #$FF, STA $D01B puts all sprites under the text. The thing is that you can actually toggle the sprites moving over and under the screen (like in a classic intro screen, which involves a green sprite bar going under and over the logo), however, advanced techniques would be required. We'll be taking a look at this later on in the feature.

Sprites can also use MSB $D010 to expand the position, so that the sprites can go across a full screen rather than miss the last part of the screen. The game code example will show you how this works.

Expanding Sprites

Another priority, which sprites have is expanding in two different ways x, and y axis. This transformation can sometimes be a good laugh to try (like I did in a BASIC demo called Biblet Land in 1996), but how do we expand our sprites? We use LDA #$FF (for all sprites), STA $D017, and STA $D01D. $D017 expands 'x' and $D01D expands 'y' for the sprites. You can turn one expansion off and another on.

What to do Next

Load up the IRQ player, which you've made (Previous chapter) (Or build a new one). Before the IRQ routine, call up your sprites, and before JMP $EA7E, enter INC $D000 and $DEC $D001. You'll see that your sprite will move diagonally. Try experimenting with these fun routines. I am pretty sure you would have fun with this. These will constantly move SPRITE 0.

Hardware Collisions

Sprite/Sprite hardware collision is used with $D01E. But we will be using SOFTWARE sprite/sprite collision
Sprite/Background collision is used with $D01F. This will be showed later on.

Software collision

Sprite/Sprite collision is used by creating and storing values according to the virtual sprite position co-ordinates.
Sprite/Background collision is more complex where checks through a table for a killer char on screen, and then processes a collision. Most games use the software collision, than the hardware collision, as it is more reliable and handles collisions well - depending on the program..

A little 2 player blast 'em duel game.

Don't get too excited because it will not be that easy to code your own C64 game :o) There are loads of new routines which you need to learn. To make things a lot easier, I have added a little explanation to each part of the program. You can also download everything in zipped .D64 format so you can read the code off line and try to understand it a little more.

We are going to create a small 2 player game, where you have two ships. We'll be using three sprites for this tutorial, but in chapter 11, we will enhance the game more. Here is what to do. Using the sprite editor, draw 2 triangles (not in multi-colour) One pointing up, and the other pointing down, then draw 1 small circle. The two triangles will be the two players and the circle will be the player's bullet. Save your sprite data, and rip or compose your own demo tune using any music composer which initialize your tune at $1000 and play at $1003. Save your music to disk. However, If this is too much hassle to get you started then I have attached a .D64 image with the data and code. You'll just need Turbo Assembler. Please read the 2 note files supplied with the code and data. There is also a runnable file for you so you can see the sort of game, we're teaching you to create :). The runnable file should look something like this. Yeah, I know. I used basic shapes, but what the heck?


.... and now, the code, fully documented:

SOURCE CODE

GET THE DISK IMAGE WITH EXECUTABLE, ASSEMBLY CODE AND DATA

Quite a lot of code there eh?. Well, more to come :)

Enhancing Your Game, using Bitmap/Hires Graphics

I wont add the whole listing to the game again, but not to worry, I've added another .D64 image, which consists of the game code and extras. What I've done for the enhanced game is add a picture, converted into Vidcom Paint format, as that way it is easy to remember what banks and charset memory to use. You could save your picture using KOALAPaint, but you would need to use the Comic Pirates' Picture Splitter program, which can be downloaded from the CBM64 FTP sites. Anyway, let me tell you about Vidcom paint images shall I?

First of all, the Vidcom Paint images are compressed to 40 blocks and uses the following locations for the image. First of all, the image uses BANK #$02 so that memory from $4000 - $8000 can be read. If this is the case then a sprite has to move to a newer location. We use $5800 - $5be8, where the data for our colours to be pasted into the main color RAM (If you don't know where the colour RAM is, take a look at an earlier chapter. We use $5C00 - $5FE8 for the colour data, which is indicated by the charset memory using $D018. Finally we use $6000 - $7F3F for the bitmap, where that also uses $D018. We need to use a correct POKE for $D018 to display the screen accurately.

Right, now I have mentioned the technical part about Vidcom Paint graphic images, it is time to show you how to actually display them. First of all, load up your image, load Turbo Assembler, use G9000 in Action Replay M/C monitor or SYS36864 and enter * = (spare memory location you want to use), enter a loop which will clear the screen now enter the listing, which is as follows:

LDX #$02                 LDA #$02
LDY #$78                 STA $DD00
LDA #$3B or              LDA #$78
STX $DD00                STA $D018
STY $D018                LDA #$3B
STA $D011                STA $D011

Now that we have set $D011 in bitmap mode, if you display the Vidcom picture, it looks a sort of mess - colour wise, so now we do an additional routine, which will copy all data from $5800-$5BE8 to the screen RAM. Here's how it's done:

LDX #$00
PAINT LDA $5800,X
STA $D800,X
LDA $5900,x
STA $D900,X
LDA $5A00,X
STA $DA00,X
LDA $5AE8,X
STA $DAE8,X
INX
BNE PAINT

Now let's add HOLD JMP HOLD, assemble and then test. Viola, an accurate bitmap picture displayed at last :o).

Okay, what about our game? Well, I have attached a zipped .D64 image, so you can download it. It consists of all the data, for music, sprites and bitmap. The assembler and also the game code. There is also a runnable file of this game too. :o) Beware, because of the size of the code in Turbo Assembler, the bitmap will mess up. All you need to do is load your bitmap, once the assembly is complete and everything works. :o)

SOURCE CODE

DISK IMAGE + ENHANCED GAME

RESULT:


Another game example: Missile Blasta

In this chapter, we are going to be working on a 1 player blasting game. First of all. We are going to have a player, bullet and also enemy. This game is going to feature sprite animation (unlike the previous game example). Animating sprites are not that easy, unless we created a routine, which would read from the sprite table and animate these. Here's what you need to do (or just look at the example .d64 image). We are going to be placing music at $1000, sprites at $2000, charset at $2800. Now using a screen editor or any other tool, draw a nice little space background. Save it, and then load it at $3000-$3400. Now do the same, but create a simple front end (title). Once you have done this, load the Turbo Assembler and then load in the routine. If you are using PC instead of turbo assembler, then I have a nice text file with the routine, that you can assemble using a cross-assembly program (C64ASM) and you will generate your C64 file.

If you don't want to create your own sprites, gfx, etc. You don't have to. You can load in the game data on the zipped .D64 image, supplied on this page and sort of experiment and/or learn how to use my routines.

SOURCE CODE

DISK IMAGE WITH DATA AND SOURCE

RESULT:


Another game: For Speed We Need

In this chapter, we take a look at For Speed We Need V2 game. Well before I give you the code let me tell you more about this simple game. First of all, it is one of those simple dodge and avoid games,  which consist of 4 levels of different speeds. It also involves each level being timed by a clock. Plus simple sprite to sprite coliisions using $D01E (It is better to not use this function if you're doing more advanced game programming). Also this features a rough background scroller, which loops if '@' is detected in the M/C. There are different parts of the code which you should be familiar with, but not everything is as familiar as it could have been for you. There are some newer routines, such as making the game more stable, instead of using raster splits that use CMP $D012. An example of this is inside the game code itself.

You might have noticed that I have added a SYNC routine, which tries to synchronize the main body of the game code, instead of using JSR routines for the game inside an IRQ raster interrupt. This is mainly because the IRQ raster interrupt can slow down if too many Ioops inside an IRQ is being used. So it is best to clear the IRQ flag and syncrhonize the timing, so that sprites and data work accurately. Sometimes the SYNC mode is a pain in the backside, but if you use it right, it should work fine. I have however, deliverately put some sprite routines inside the IRQ, as the movements did not synchronize properly while music was playing. Other routines work fine :)




If you take a look at (11.) properly you will notice that the game scroller is not a smooth scroll. But a rough scroll routine. Where you see the $0400+(N*n),x bit in the rough scroll. This is where 40 chars ($28 chars) is read from the bottom, and is then pulled to the upper 40 chars row. After all rows are pulled. A new row of data is visible on screen from the map buffer, and the pulling routine continues.

Like myself, you'd find this routine difficult, but later on you should be able to get the hang of it :).

O.k. now here's the code (TASS64, TASM, C64ASM and Turbo Assembler Format):

SOURCE CODE

And here is the .D64 with the data, executable and Turbo Assembler code

GAME DATA AND CODE

Hardware sprite to background collision + animated chars

We are going to write another little game. This time it is a game which uses sprite to background collision detection. Before we get started, I need to point out that there are actually two different types of sprite / background collisions. They are the hardware collision and also the software collision.

For this example, we will be using the hardware sprite to background collision, which is more simple. In the next chapter, we'll be using the software sprite/background collision, which is all to do with the char type and also collision char tables. The hardware collision uses the $D01F value, which means if a sprite hits a visible char anywhere on the screen, a collision is made. This is pretty simple to detect by using the following statement in your source code:


SPRCOL      LDA $D01F ;Read sprite/char hardware
            LSR A ;Remove A if you are NOT using Turbo Assembler
            BCC HIT
               RTS ;Player is not hit, so terminate the routine
HIT         INC $D027 ;Flash sprite colour to show collision
            RTS ;End

Pretty simple huh? Well, it is pretty boring to look at as code. You would want a practical example wouldn't you?. Well, thankfully, you can download the example and the source code below to look at it in a more practical kind of way. The program below was programmed in Turbo Assembler, and shows the whole example code for the sprite/background collision. It does not look anything too exciting. It shows a blank screen with a line of the reverse on + spacebar chars and a square sprite, which will move until it hits the visible charset.

;Assemble IT - Chapter 21, part 1
;
;Sprite to background collision
;By Richard Bayliss

;Global labels/constants

objpos   = $0370
sync     = $0380

         *= $4000
         sei

;Clear the screen

         lda #$00  ;Blacken screen
         sta $d020
         sta $d021

         ldx #$00
wipe     lda #$20
         sta $0400,x
         inx
         bne wipe

;Draw a line somewhere at the bottom
;using RVS on + SPACEBAR char.

         ldx #$00
draw     lda #$a0
         sta $06d0,x
         lda #$02
         sta $dad0,x
         inx
         cpx #$28 ;(Or use #40 instead)
         bne draw

;Fill $2000 so we can make a square as
;the test sprite.

         ldx #$00
mksquare lda #$ff
         sta $2000,x
         inx
         bne mksquare

;Turn the only sprite on

         lda #$01
         sta $d015

;Put square object into sprite memory

         lda #$80
         sta $07f8


;Now set up only one sprite and its
;default position (for expansion)

         lda #$58
         sta objpos+$00 ;Default xpos
         lda #$42
         sta objpos+$01 ;Default ypos

;Set the sprite colour to white

         lda #$01
         sta $d027

;Make our interrupt

         lda #<irq1
         ldx #>irq1
         sta $0314
         stx $0315
         lda #$00
         sta $d012
         lda #$7f
         sta $dc0d
         lda #$1b
         sta $d011
         lda #$01
         sta $d01a
         cli
mainloop lda #$00
         sta sync
         cmp sync
         beq *-3
         jsr expand ;Call expansion rt
         jsr readjoy ;Call joy read rt
         jsr bgrcol ;Call bgr.coll rt
         jmp mainloop

;Expand the sprite x position for only
;the first sprite

expand   lda objpos+$01
         sta $d001
         lda objpos+$00
         asl a
         rol $d010
         sta $d000
         rts

irq1     inc $d019
         lda #$01
         sta sync
         jmp $ea7e

;Move the square slowly around the
;screen with a joystick plugged into
;port 2

readjoy  lda $dc00
up       lsr a     ;Remove 'a' if not
         bcs down ;using Turbo Assembler
         ldx objpos+$01
         dex
         dex
         stx objpos+$01
down     lsr a
         bcs left
         ldx objpos+$01
         inx
         inx
         stx objpos+$01
left     lsr a
         bcs right
         ldx objpos+$00
         dex
         stx objpos+$00
right    lsr a
         bcs fire
         ldx objpos+$00
         inx
         stx objpos+$00
fire     rts   ;Ignore firebutton as
               ;we don't really need
               ;it.

;The hardware sprite/background
;collision routine

bgrcol   lda $d01f;Hardware detect
         lsr a    ;If sprite 1 touches
         bcs hit  ;visible char then
                  ;collision detected.
              ;else sprite stays white
         lda #$01
         sta $d027
         rts

;Sprite hits a visible char so for now
;we'll make the sprite flash.

hit      inc $d027
         rts



Okay. So now you seem to have the grasp of what is going on here, it is time make a game, but before you do, I want to show you a new trick, which will be implemented into the source code. Do you remember my games such as Balloonacy and Balloonacy 2? These games used the same type of technique as above, but you also notice how the game uses animated chars. It is tricky at first, but after a while you will get the hang of the routine. It is quite nice and handy to use.


charanim lda chrptr
         cmp #$0c     ;Our actual delay
         beq enddelay ;for the anim
         inc chrptr   ;basically, the
         rts          ;speed.
enddelay lda #$00
         sta chrptr
         ldx #$00
wrap1    lda $2a00,x  ;Copy the whole
                      ;char data and
         sta $2a40,x  ;paste it to $2040
         inx          ;8 times
         cpx #$08
         bne wrap1
         ldx #$00
wrap2    lda $2a08,x  ;Copy chars from
         sta $2a00,x  ;$2a08 to $2a00
         inx          ;for a perfect
         cpx #$40     ;working charset
         bne wrap2    ;animation.
         rts

Now the background animation and that is sorted out. We are going to do a little game. Actually I have done an example of a simple game, which uses both the background char animation and also the hardware sprite to background collision routine. The game is called "Give The Dog A Bone". The concept is pretty simple, and you'll see the example source below. Okay, so it is not really much of a game, but we'll look into expanding the game and the source code in the next chapter, which I'm sure you will find interesting.



SOURCE CODE

DISK WITH DATA AND SOURCE CODE

Software related sprite/background Collision

Last time in this section, we were showing examples on making sprite/background collision, using the $D01F register. However, there's also another method (but longer method as well), which is the use of sprite/character collision. How is this usually done? Well, it is different compared to using $D01F. When we used $D01F, it could only detect a collision if a sprite hit a visible character. This method was used a lot, with some of my games, such as Balloonacy 1 and 2, Grid Zone, and a few others. However, we shall be taking a look at the software sprite/background collision - and even come up with a little example game for you to try out.

The software programmed sprite/collision register will detect whether or not a sprite hits a selected character value on screen. This is based on the Racked Off sprite/background collision routine by Kenho, and a few other people on the CSDB who has also contributed the routine on the CSDB forums. Before we start. We shall be making a simple game, here's my implementation of the routine (using the same square and line example) which will flash the square if it collides into the INVERTED SPACEBAR character.

SOURCE CODE (TASS Format)

Little quiz:

Taking a look at the example, above. Change the line from the inverted SPACEBAR character to a different character and then assemble and run the program to see what will happen. That's correct, no collision at all.
That is how the Software related sprite/background collision works, while $D01F uses any visible character on screen.

Okay folks it's now GAME MAKING time. Today we are very proud to bring you an example game called:

HYPER BLITZ
We are going to make a well known retro game, which may have been programmed in BASIC so many times either from books, magazines, toilet walls. Okay, maybe not. Anyway don't get too excited because we're pushing BLITZ even further and program our own. This is an example game which will be using the software related sprite/background collision feature, but this time round we are using this feature TWICE. Anyway, let me explain more about the game code before you decide - LET'S MAKE SOME BLITZ GAMES AND SHOW RICHARD WHAT WE CAN DO.



For a start off, before entering the machine code into Turbo Assembler or possibly one of the assemblers. Draw some sprites, the game charset. Make build your own level design and then compose some music (Unless you want to use my music of course). Now load in the assembler (or export what you done and place it where your cross assembler lies). Then load up the source. Feel free to modify it if you like :)


The source:

Just a quick explanation about what happens in the source (As the source is documented itself). We start the code by setting up the graphics type and colours. Simply by switching on the sprite/charset multicolour. Next comes the initializing of the IRQ interrupt routine. Where we try and hack a raster interrupt to work as a continues. After clearing the flag. We switch on only sprites, where the player is a space ship and the bullet is a simple bomb. After this, we create our own sync timer so, when an IRQ raster interrupt is playing, we can synchronize the timer to get all movements and subroutines synchronized. Then comes the JSR subroutines, which will do various checks. We also have subroutines that will constantly move the player until it hits one of the buildings. Routines to reposition the player once in a certain position off screen. Check for a sprite to char collision, according to whether the player hits the building or whether a bomb hits the building, making the play score points. There are also routines which will animate the player's ship as well.  And the finalize the code, we have the main IRQ raster interrupt in action as well. You best take a look at the source code to see what I mean.

View source code

Download Turbo Assembler with game code and executable .D64




Next Page / Previous Page / Back to Contents Page