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.
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.
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
#$01 ;1 SPRITE
STA $D015 ;TURN ALL SPRITES ON
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)
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)
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).
have their own priorities. You can put certain sprites in front or
the characters on screen. This can be toggled by using $D01B. For
LDA #$00, STA $D01B puts all sprites over the text, and LDA #$FF, STA
puts all sprites under the text. The thing is that you can actually
the sprites moving over and under the screen (like in a classic intro
which involves a green sprite bar going under and over the logo),
advanced techniques would be required. We'll be taking a look at this
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.
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
these fun routines. I am pretty sure you would have fun with this.
These will constantly move SPRITE 0.
collision is used with $D01E. But we will be using SOFTWARE
Sprite/Background collision is used with $D01F. This will be showed later on.
Sprite/Sprite collision is used by
creating and storing values according to the virtual sprite position
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.
are going to create a small 2 player game, where you have two ships.
be using three sprites for this tutorial, but in chapter 11, we will
the game more. Here is what to do. Using the sprite editor, draw 2
(not in multi-colour) One pointing up, and the other pointing down,
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
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
too much hassle to get you started then I have attached a .D64 image
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
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:
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:
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:
PAINT LDA $5800,X
Now let's add HOLD JMP HOLD, assemble and then test. Viola, an accurate bitmap picture displayed at last :o).
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
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)
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.
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.
Another game: For Speed We Need
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
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):
And here is the
.D64 with the data, executable and Turbo Assembler 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
RTS ;Player is not hit, so terminate the routine
HIT INC $D027 ;Flash sprite colour to show collision
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
objpos = $0370
sync = $0380
;Clear the screen
lda #$00 ;Blacken screen
wipe lda #$20
;Draw a line somewhere at the bottom
;using RVS on + SPACEBAR char.
draw lda #$a0
cpx #$28 ;(Or use #40 instead)
;Fill $2000 so we can make a square as
;the test sprite.
mksquare lda #$ff
;Turn the only sprite on
;Put square object into sprite memory
;Now set up only one sprite and its
;default position (for expansion)
sta objpos+$00 ;Default xpos
sta objpos+$01 ;Default ypos
;Set the sprite colour to white
;Make our interrupt
mainloop lda #$00
jsr expand ;Call expansion rt
jsr readjoy ;Call joy read rt
jsr bgrcol ;Call bgr.coll rt
;Expand the sprite x position for only
;the first sprite
expand lda objpos+$01
irq1 inc $d019
;Move the square slowly around the
;screen with a joystick plugged into
readjoy lda $dc00
up lsr a ;Remove 'a' if not
bcs down ;using Turbo Assembler
down lsr a
left lsr a
right lsr a
fire rts ;Ignore firebutton as
;we don't really need
;The hardware sprite/background
bgrcol lda $d01f;Hardware detect
lsr a ;If sprite 1 touches
bcs hit ;visible char then
;else sprite stays white
;Sprite hits a visible char so for now
;we'll make the sprite flash.
hit inc $d027
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
enddelay lda #$00
wrap1 lda $2a00,x ;Copy the whole
;char data and
sta $2a40,x ;paste it to $2040
inx ;8 times
wrap2 lda $2a08,x ;Copy chars from
sta $2a00,x ;$2a08 to $2a00
inx ;for a perfect
cpx #$40 ;working charset
bne wrap2 ;animation.
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.