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 initialise 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:
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)
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.
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):
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
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.
