A$$emble IT!
A C64 Coding Tutorial - Now featuring example screen shots
Introduction / What is An Assembler? / ASM Commands / Writing Your First Program / Using X&Y Loops / Displaying Text/Characters & Colours on Screen / Introduction to $D012 / IRQ Raster Interrupts / Introduction to Sprites using M/L
Colour-Washing Text / Making Your First Game
Chapter 1: INTRODUCTION

The main purpose for this web site is to produce legal future reference for those people who would like to be involved with assembly programming side of the C64 scene. This documentation differs through various assembly coding techniques, commands, etc. By reading through this documentation, you should soon end up creating cool, exciting and possibly crazy programs in no time. Later on in this documentation, you will learn how to create your own games, that involve moving sprites, animating background objects, playing SID music, adding scores, etc. Hopefully you should be able to understand assembly programming in approximately one or two months. Oh and you'll be having a go at making a C64 game in no time.

Chapter 2: WHAT IS AN ASSEMBLER?

WHAT IS AN ASSEMBLER?
An assembler is a programming language that allows you to program in a different way, compared to the BASIC programming language. BASIC is a very easy programming language, but assembly language is more professional and it can do a lot more enhanced techniques. Many demo programmers, such as Civitas (The demo group which I'm in) use an assembler, which creates cool demos, effects etc.

WHAT TYPE OF ASSEMBLERS ARE THERE?
Assemblers may differ, as different commands are used, but they all build the same routines. You write a program listing in an assembler, and then you need to assemble it before you create a runnable file and test your file. There are different types of assemblers, which have their own features. The assemblers are as follows:

- 6150+ Assembler by Dave Weaver (A little bit like BASIC, except that you can assemble your own programs as well)
- Code Suck Monitor by Polunus/Science 541 (M/C Montor based assembler)
- Action Replay MK 6 Cartridge by Datel Electronics (M/C Monitor)
- Professional Assembler by ???? (Kind of similar to turboassembler)
- AssBlaster V3.0 by Zeldin/Cascade (An advanced assembler with a user-friendly interface)
- Turbo Assembler Vx by Omikron (One I always use)
- ASM Monitor by Raistlin/Excess (Oldie, and like 6510+)
- +More

Chapter 3: ASM Commands
When you are writing your own programs, it would usually be the best thing to take a look at various resources, so that you can understand all these following: commands. I can explain a few of these, but not all of them.

LDX #$00 (LDX #0), LDY #$00 (LDY #0)
This command sets the starting loop, at a value of 0. This command is very useful for writing control loops in your own programs. You can change various commands for your program, by indicating LDX #nn, where nn is the number you want to start.

When you are using LDX, or LDY loops, you can start from 0 to 256, or ($00 - $FF). Easily done

LDA #$00 (LDA #0)
This command allows you to set a value. This value could be used for either raster splits, charsets, colours, RAM, etc.

STA $xxxx (STA xxxxx)
When you set values, using LDA you can build the type of RAM which are using, when entering STA. For example if you want to build a black screen, then you enter:

LDA #$00
STA $D020
STA $D021

Quite simple eh? I'm sure it is. Ah, but you can't just LDA and STA things, you can also use LDX and LDY and instead of use STA, you can use STX or STY, for example:

LDX #$00
STX $D020
STX $D021

LDY #$00
STY $D020
STY $D021
Let us say for example you wanted to draw a black screen, but you want a red frame. You could use LDA and STA like as the example below:

LDA #$02
STA $D020
LDA #$00
STA $D021

Or then again, you would prefer to tidy your code, by using the X,Y method, for example:

LDX #$02
LDY #$00
STX $D020
STY $D021

There, that is MORE tidy!

INX , INY
These are two command that are use to increment a value which is inside a timed loop. These can also be used for continuous moving of objects, flashing, rasters, etc.

CPX #$00, CPY #$00
These are comparing loop values of a loop, which is the value of X or Y. Basically if you use 0 as start loop and want the C64 to count the loop 255 times, then we CPX or CPY the limit. I'll show you how to use these later on :o)

BNE $xxxx
This command is used in a loop. For example, compare a value and if it does not match, go to the looping command. For example:

LDX #$00 LDY #$00
LOOP INC VALUE LOOP INC VALUE
INX OR INY
CPX #$FF CPY #$FF
BNE LOOP BNE LOOP

Easy!

INC $xxxx or INC VALUE
The INC command is used to increment a value. For example, this command can be used for creating your own sprite movements, timers, etc.

DEC $xxxx or DEC VALUE
DEC is opposite to INC. Instead of incrementing a value, this command decrements a value. Yet again it can be used for practically the same as with INC, but goes the opposite way :o)

BCC & BCS
BCC & BCS are similar to the BNE command, but these are more special. Many C64 programs use BCC and BCS for their programs, I.E. some nice little game I made in the past, that use collision detection with an enemy and player, I used the following command:

LDX #$00
LOOP LDA ENEMYPOS+$00,x
CMP COLLISION
BCC NO COLLISION
CMP COLLISION+$02
BCS NO COLLISION
LDA ENEMYPOS+$01,x
CMP COLLISION+$03
BCC NO COLLISION
CMP COLLISION+$04
BCS NO COLLISION
INC $D020
RTS

NO COLLISION INX
INX
CPX #$10
BNE LOOP

Pretty simple, but we will take a look at this when we start a simple little two player game project.

CMP #$00 (or CMP #0)
The command CMP #$nn compares a value that IS/NOT in a loop. For example you can compare values for positions of sprite movements and set the stopping values rather than just have them continuously looping :o)

JSR $xxxx, JSR ROUTINE
The JSR routine is always used inside or outside an Interrupt ReQuest (IRQ) flag, which jumps to a routine, but allows you to continue your programming. For example:

LDX #$00
JSR $1048

JSR COLOURWASH
JSR ANIMATE
JSR $1021 ;Play music

JMP $xxxx, JMP ROUTINE
JMP is similar to JSR, but this time it jumps to a routine that you want. For example, freezing your own program

HOLD JMP HOLD

There are also a couple of special JMP routines, which are JMP $EA81 and JMP $EA31, these are of course used in IRQ routines

CLC
ADC #$00 or (ADC #0)
Calculate and add a value

SEC
SBC #$00 or (SBC #0)
Reverse calculate and subtract a value

BEQ STATEMENT
Similar BNE, BCC and BCS, but a bit different. These are mainly used in loops, to defualt values of pointers.

SEI
SEI turns off an IRQ interrupt flag, when a loop is inside the program

CLI
Clears registers and allows the programmer to insert additional commands, which they cannot use inside an IRQ loop!

PLA
PHA
RTI
These are special commands.

TAX or TAY
Mainly used to control scrolling types, initialise everything, for example, music!

LDA #$00
TAX
TAY
JSR $1000 ;Initialise DMC 4 tune

.BYTE (or .BYT)
Data tables for animation, colours, etc

.TEXT (or .TXT)
Data tables for creating your own text

There are many other commands, but the commands (PLA, PHA, RTI, SED, CLD) that I don't use, and they're for more advanced programmers.

Chapter 4: WRITING YOUR FIRST PROGRAM
We are going to write our first program, which is just something small and simple. This program shows you how to create your own flashing border, while asking for the user to press the space bar, so that then the program exits. So load up your assembler and type in the following listing. There are two different methods for this phase ;o)

METHOD 1

;===================
;RAINBOW COLOURS
;===================

* = $0900 ;Jump start for code
SEI ;CLEAR IRQ
LOOP INC $D020 ; INCREMENT BORDER
LDA $DC01 ; CHECK BUFFER
CMP #$EF ; IS SPACE PRESSED?
BNE LOOP ; IF NOT THEN JUMP TO LOOP
RTS ; IF SPACE IS PRESSED THEN END

Can you see how easy it is to create your own short program? Now all you need to do is assemble the program and run it. Guess what? You'll see a flashing border. The border will continue to flash until you press space. Then the program will finish. Well why does the program continue flashing, before SPACEBAR is pressed? Well, that's easy, because the program is inside a control loop, which continues to loop until the value #$EF is found, and then the C64 stops running the program, as the program tells it to do so. Now why not try deleting LDA $DC01, CMP #$EF and BNE LOOP into:

METHOD 2:

;===================
;RAINBOW COLOURS
;===================

* = $0900 ;Jump start for code
SEI ;CLEAR IRQ
LOOP INC $D020 ; INCREMENT BORDER
LDA $DC01 ; CHECK SPACEBAR
LSR ; If SPACEBAR IS NOT
LSR ; PRESSED THEN JUMP
LSR ; TO THE LOOP!
LSR
LSR
BCS LOOP
RTS

Not much of a difference there, but this is also checking for a button on joystick port 1. Yes, that's right FIREBUTTON. The spacebar will still work.

I would prefer to use method 1, in order of processing the code. This is because it is shorter compared to method 2. Shorter routines can compress the program, which you write. It also saves the amount of memory that has been used in an assembler.

Chapter 5: USING X & Y LOOPS
In Chapter 4, I gave you an example program, which allowed you to flash the colour borders, but now, I'm going to show you how you can EXPAND colour sizes. Here is what we'll do. We shall use an LDX prompt and also an LDY prompt (for X and Y loops). We shall still use INC $D020 and INC $D021 and the pressing spacebar method, but this is just a little taster of what we have in store for this section :o)

;==================
;FLASHING BORDERS
;USING X & Y LOOPS
;==================
*=$0900 <- you should know what this routine does
SEI <- and this one
MAINLOOP LDX #$00 ;Set 'X' as 0
LOOPX LDY #$00 ;Set 'Y' as 0
LOOPY INC $D020 ;Flashy border
INY ;Increment Y
CPY #$77 ; Is 'Y' equal to #$77
BNE LOOPY ; If not then Y=Y+1, goto LOOPY
INX ; Increment X
CPX #$77 ; Is 'X' equal to #$77
BNE LOOPX ;If not then X=X+1, goto LOOPX
LDA $DC01 ;Load Spacebar command
CMP #$EF ;Is spacebar pressed
BNE MAINLOOP ; If not then jump to the MAINLOOP prompt
RTS ; else END program operation

You will notice that there wont be much of a difference in the flashing borders. However, we could try something different. Here is what to do.

Underneath RTS, build your own colour table. Include the label COLOURS. You could try the following:

COLOURS
.BYTE $00,$06,$0E,$03
.BYTE $03,$0E,$06,$00

Now let's try a little experiment shall we?

Where we have INC $D020, replace this with LDA COLOURS,X and then add STA $D020. We're not finished there yet. In order to read the amount of colours that are in the colour table, the next thing for you to do is change CPX #$77 into CPX #$08. Now let's test it ;o)

Different.

Now, why not try and change CPY #$08 and see what happens next ;o) Notice any differences? The border thins down and it scrolls something like those colour bars, which have been used on SEUCK games apart from SEUCK bars go upwards instead of downwards.

Thinning colour bars, etc is plain easy to handle, but when $D012 is involved, things change.

The borders look a mess, as they are flickering so what should be done now is some minor adjustment to the flickers. All we do is add NOP, a few times, until the borders are nice and straight. Let's try it.Erm, no, as not much effort would be put into it. Maybe using $D012 would help. We'll look at this later on

Chapter 6: Displaying text/characters & their colours on screens
How can we display text or characters on the screen? Easy, we use loops, but we need to use screen RAM, which is located in different memory banks. We shall stick to the normal C64 display bank ($0400 - $07E7), so that then we can display some text.

For a start off, let us try and something, which is located at $4000 and then pastes it through the whole of the screen area. Remember, this is only an experiment. There are different methods, but we'll use a simple method on displaying a screen, that is located at $4000.

;================================
;DISPLAYING TEXT AT BANK #$03
;================================

;SET UP PERAMETERS

SCREENLOC1 = $4000
SCREENLOC2 = $4100
SCREENLOC3 = $4200
SCREENLOC4 = $42E8

SCREENPOS1 = $0400
SCREENPOS2 = $0500
SCREENPOS3 = $0600
SCREENPOS4 = $06E8

* = $0900
SEI
LDX #$00 ;X=0
DISPLAY LDA SCREENLOC1,X ;READ FROM SCREENLOC1 'X' TIMES
STA SCREENPOS1,X ;PASTE TO SCREENPOS1 'X' TIMES
LDA SCREENLOC2,X ;READ FROM SCREENLOC2 'X' TIMES
STA SCREENPOS2,X ;PASTE TO SCREENPOS2 'X' TIMES
LDA SCREENLOC3,X ;READ FROM SCREENLOC3 'X' TIMES
STA SCREENPOS3,X ;PASTE TO SCREENPOS3 'X' TIMES
LDA SCREENLOC4,X ;READ FROM SCREENLOC4 'X' TIMES
STA SCREENPOS4,X ;PASTE TO SCREENPOS4 'X' TIMES
INX ; X=X+1 UNTIL X = $FF (256)
BNE DISPLAY ;IF X <> $FF THEN GOTO DISPLAY
RTS ;END PROGRAM

Compared to using BASIC, this routine is smaller and more compact to display text.

Now that you know how to display the screens, we want to display colours for the text. And here is how we can do this:

The colour RAM is always between $D800 and $DBE7. Therefore, variables can be created for the colours. So create some new variables, which are as follows:

COLOURPOS1 = $D800
COLOURPOS2 = $D900
COLOURPOS3 = $DA00
COLOURPOS4 = $DAE8

Then inside your loop (underneath STA SCREENPOS4,X) enter the following:
LDA #$0A
STA COLOURPOS1,X
STA COLOURPOS2,X
STA COLOURPOS3,X
STA COLOURPOS4,X

You don't just get the screen displaying only text, but you get the text to display painted in pink ;o)

Why not play around with the colours. Here is a small table on which colour does what job :o)

Hexadecimal ($) | Colour
$00 | Black
$01 | White
$02 | Red
$03 | Cyan
$04 | Purple
$05 | Green
$06 | Blue
$08 | Orange
$09 | Brown
$0A | Pink
$0B | Dark Grey
$0C | Medium Grey
$0D | Light Green
$0E | Light Blue
$0F | Light Grey

Chapter 7: USING $D012
This is the fun bit. $D012 is used to create some raster splits. For example, if you wanted to make your own title screen for a C64 game, you would need to code in the raster splits. Let us say for example, you paint a logo using drawing programs, save them as a VIDCOM format and you want to display the normal font you created which is located at $2000. A raster split would need to be used, therefore you would need to split everything up. For example:

If you look at the thin line, you can see that it is the raster bar, splitting an image. A prime example for something like this is a title logo, which was done for the game Balloonacy. Look below and you'll see what I mean by a raster split :o)

Now we are going to try something similar, but more simpler. We are going to program our own raster splits, but we are going to do this the more easier way. That's right, we are going to split the screen into two different colours. Now how do you do this? Easy, type in the listing below and you should begin to understand how the code will work :o)

;===========================
;COLOUR SPLITTING USING $D012
;===========================

*=$0810
SEI
MAIN LDA #$30
LDX #$00 ;BLACK
RASTER1 CMP $D012
BNE RASTER1
STX $D020 ;ASSIGN BLACK TO
STX $D021 ;BORDER AND FRAME
LDA #$A8
LDX #$01 ;WHITE
RASTER2 CMP $D012
BNE RASTER2
STX $D020
STX $D021
JMP MAIN

Now that we have typed in this listing if you run it, just assemble it and run the little program. You will see that the top border and frame is black, and that the bottom border and frame is white. You will also notice that using this routine, there are a few screen flickers. This is because we are not using an IRQ loop, and we're also not using TIMING either :o)

How do we add timing to rasters? There are different ways, but one of the easy ways is by adding the 'NOP' command a few times, before we actually start a process. For example

RASTER1 CMP $D012
BNE RASTER1
NOP
----- Rest of program

Adding NOPs will move the little flickers further across the screen. Therefore you will need to add a few of these until the split is STRAIGHT and not FLICKERING :o)

There are other methods of timing, which you can use, which can be easier. You could use timing inside an x or y loop. For example

RASTER1 CMP $D012
BNE RASTER1
LDX #$XX ;Timing Value
TIMER1 DEX
BNE TIMER1
------ Rest of program

You could reverse the timing loop, but if you do, you would need to change the values into the following.

LDX #$00
TIMER1 INX
CPX #$XX ;Timing Value
BNE TIMER1

There is also another method in timing, which is the hardest of them all. Imagine you are doing a raster bar, which uses loads of colours, like some demo groups use. Well a timing table would need to be produced. To find out more about timing, read the disk mag 'Coders World' issue 2.

Chapter 8 - IRQ Raster Interrupts

What is an IRQ Raster Interrupt?

An IRQ Raster Interrupt is a routine, known as the Interrupt Request flag. This is a continuous loop, which can hold more than one control loop. Therefore uses more complicated techniques. Most people use IRQ interrupts to do various effects in their programs. I mainly use IRQ interrupts for my C64 games. A little explanation will be added in a short while. But first copy this routine into your Turbo Assembler before you actually do anything. Below is a listing that shows a nicr and small IRQ raster interrupt routine.

SEI
LDA #<INIT
LDX #>INIT
STA $0314
STX $0315
LDA #$00
STA $D012
LDA #$7F
STA $DC0D
LDA #$01
STA $D01A
CLI
HOLD JMP HOLD
INIT LDA #$01
STA $D019
INC $0400
JMP $EA31

Right, looking from the top of the IRQ flag, the values $0314 and $0315 are very special, these call INIT to produce the main IRQ interrupt flag. However you MUST use (as highlighted) the prompts else your IRQ wont work properly. This is because they are vital to use in your program.

What can IRQ be used for? Let us say for example you are writing a demo, game or utility, you might need to use IRQ raster interrupt request flags to link various sources, such as the following:

- Scrolltext
- Raster Bars
- Charset Animations
- Playing Music
- Colour washing
- Advanced data handling (for special effects)
- Sprite control
- Keyboard commands
- Joystick commands

However, INC $0400 does not mean much, apart from you'll see a character changing on the top left corner of the screen.

Okay, press RUN/STOP and restore, load a Demo Tune or a tune of your own into $1000, (JCH, DMC or equivalent), enter sys 36864 and do as follows:

Underneath STA $D01A enter:

LDA #$00
TAX
TAY
JSR $1000

This is to initialise your music

Now, delete INC $0400 and change to JSR $1003. This is to play your music. Now, assemble and run.

You'll be able to hear some music playing in the background. Later on, we'll be taking a look at preparing a demo.

If you link other routines, be sure to JSR (routine) before JMP $EA31 Let's try something simple, such as flashing the screen. Before JSR $1003, put JSR FLASH and then underneath JMP $EA31, enter the following code:

FLASH INC $D020
DEC $D021
RTS

Why do we add an RTS command at the end of this prompt? This is because if we don't use RTS, the program will not respond properly, in fact it will virtually crash and you may lose everything.

Now, let's add another command to the IRQ. After JSR flash, try JSR CHAR, Underneath RTS inset the label CHAR and enter INC $D018 and add another RTS, assemble and run. You'll get some funny effects happening. This is because the C64 is playing with your charset memory.

Basically that is all for this chapter. We'll be taking a look at a few other chapters regarding assembly code :)

Chapter 8 - Introducing Sprites

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 from a PD utilities disk (Or download one).
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 $D018
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.

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

Simple. Load up the IRQ player, which you've made. Before the IRQ routine, call up your sprites, and before JMP $EA31, 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.

Chapter 9 - Colour-Washing Charsets

This is one of the most simplest tasks. In some demos and other programs on the Commodore 64, you see colours moving from the left hand side - to the right and also vice-versa. How do these simple routines work? Well, this is the easy part - in fact it is the easiest method of them all. Copy this listing below, and all will be revealed straight after the listing.

;Simple colour washing routine, inside
;an IRQ Raster Interrupt Player

* = $1000

LDX #$00
SHOWMS LDA MESSAGE,X
STA $0400,x
INX
CPX #$28
BNE SHOWMS

Now create your own IRQ raster interrupt, make the screen black and set the C64 charset mode to $16 (LDA #$16 STA $D018)

Inside your IRQ raster interrupt routine, call the colour washing routine.

IRQ JSR COLWASH
JMP $EA31

;======================
;COLOUR WASHING ROUTINE
;======================
COLWASH LDA COLOUR+$00
STA COLOUR+$28
LDX #$00
CYCLE LDA COLOUR+$01,X
STA COLOUR+$00,X
LDA COLOUR,X
STA $D800,X
INX
CPX #$28
BNE CYCLE
RTS

;DATA TABLES FOR COLOURS

COLOUR .BYTE $09,$09,$02,$02,$08
.BYTE $08,$0A,$0A,$0F,$0F
.BYTE $07,$07,$01,$01,$01
.BYTE $01,$01,$01,$01,$01
.BYTE $01,$01,$01,$01,$01
.BYTE $01,$01,$01,$07,$07
.BYTE $0F,$0F,$0A,$0A,$08
.BYTE $08,$02,$02,$09,$09
.BYTE $00,$00,$00,$00,$00

;DATA FOR TEXT MESSAGE

MESSAGE .TEXT "RICHARD BAYLISS'"
.TEXT " COLOUR SCROLLER"
.TEXT " ACTIVE......"
.TEXT " "

If you take a look at this routine, during the control of the colour washing routine, we take the byte, which is at COLOUR+00 and then we place it at COLOUR+$28, then we call a continuous loop which makes the data table cycle, by subtracting each piece of data in the data table by one, and read the calculations 40 times ($28 times), therefore the data table pulls each byte of data. Also inside our loop, the colours are read from the data table and the positioned on to the C64's colour screen RAM, which is from $D800 until $D828. As for reading the message, you'll see for yourself how that works. It is easy to remember ;o)

There is also a simple way to -reverse- the direction of your colour-washing routine. The listing below shows how you can do this :)

;======================
;COLOUR WASHING ROUTINE
;======================
COLWASH LDA COLOUR+$28
STA COLOUR+$00
LDX #$28
CYCLE LDA COLOUR-$01,X
STA COLOUR+$00,X
LDA COLOUR,X
STA $D7FF,X
DEX
BNE CYCLE
RTS

We reverse the process. You'll also notice that $D800,x has been changed into $D7FF,x. Why is this? Well, simply because if you used $D800 instead of $D7FF you would find that the C64 will miss the first character, therefore you will need to subtract 1 from the screen ram location. Pretty easy to understand huh?

Something to try:

Now that you have learned how to do simple colour cycling, try and put BOTH routines on to the screen. Create your own message at the top of the screen, and bottom of the screen and use one cycling routine at the top and a reverse routine at the bottom.

Chapter 10 - Building Our Very First 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 was crunched using Time Cruncher V5.0, as I wanted to make quick file compression. While you're coding the game, this is how it should look.

Download code and data here

...and now the code:

;A$$EMBLE IT! - CODING TUTORIAL ;Creating your first game ;This is an example tutorial for you to ;learn how to create your own 2 player ;Shot 'em Up, which includes joystick ;control, a score system, etc. ;Let's setup the perameters for our ;game. These are the player positions. plr1Äx = $0340 ;Player 1 x-position plr1Äy = $0341 ;Player 1 y-position plr2Äx = $0342 ;Player 2 x-position plr2Äy = $0343 ;Player 2 y-position ;Our parameters for the player bullets plr1bÄx = $0344 ;Player 1 bullet-xpos plr1bÄy = $0345 ;Player 1 bullet-ypos plr2bÄx = $0346 ;Player 2 bullet-xpos plr2bÄy = $0347 ;Player 2 bullet-ypos ;Collisions parameters plr1col = $0350 ;Value storage for p1 plr2col = $0354 ;Value storage for p2 ;bullet lockup routines plr1lockup = $0360 ;Lockup for players plr2lockup = $0361 ;shooting ;We need to create a jump start for this ;example, so we will create our own jump ;address where it does not overlap data ;which had been loaded. *= $2400 start sei ;Set irq flag ;Clear the screen without JSR $E544 ldx #$00 ;Calls a routine clear lda #$20 ;to fill the whole sta $0400,x ;screen with #$20, sta $0500,x ;which is the sta $0600,x ;blank space sta $06e8,x ;routine. inx ; bne clear ; ;You should be familiar with the next ;example code. If not then look at the ;earlier chapters of A$$EMBLE IT! lda #$00 sta $d020 sta $d021 lda #$16 sta $d018 lda #$1b sta $d011 lda #$ff sta $d015 ;Now here we create the sprite objects lda #$81 sta $07f8 ;Player 1 ship lda #$82 sta $07f9 ;Player 1 bullet lda #$80 sta $07fa ;Player 2 ship lda #$82 sta $07fb ;Player 2 bullet ;This is where we setup the colours of ;the two players and bullets. lda #$02 ;Colour red sta $d027 ;Player 1 sta $d028 ;Player 1 bullet lda #$07 ;Colour yellow sta $d029 ;Player 2 sta $d02a ;Player 2 bullet ;This is a different routine, as now the ;default sprite positions are copied to ;the declared parameters. lda $d000 ;This is a method sta plr1Äx ;of copying and lda $d001 ;pasting the sprite sta plr1Äy ;positions so that lda $d002 ;you can use this sta plr1bÄx ;to program the lda $d003 ;sprites positions sta plr1bÄy ;later on in the lda $d004 ;routines, for a sta plr2Äx ;much faster lda $d005 ;and decent sta plr2Äy ;movement for all lda $d006 ;the sprites in sta plr2bÄx ;this game. lda $d007 sta plr2bÄy ;Now we reposition the two players and ;put the bullets into zero lda #$42 ;All this is the sta plr1Äy ;repositioning the lda #$18 ;two player ships, sta plr1Äx ;by using the 'x' lda #$e0 ;positions and the sta plr2Äy ;'y' positions, lda #$98 ;as simple as that sta plr2Äx ;:) lda #$00 ;All bullets are sta plr1bÄx ;repositioned to sta plr1bÄy ;the zero value sta plr2bÄx ;yet again 'x' and sta plr2bÄy ;'y' positions ;Setup the scoreboard lda #$30 ;We put zero on: sta $0400 ;first line lda #$02 ;paint first line sta $d800 ;red lda #$30 ;zero put on sta $0427 ;first line as last lda #$07 ;paint character sta $d827 ;yellow ;Now for the main body of this program ;the Interrupt flag, but we wont use ;JMP $EA81 or JMP $EA31, as no keyboard ;control will be required lda #<int ; Call INT values ldx #>int ; into an IRQ raster ldy #$00 ; interrupt value and sta $0314 ; zero the rasterline stx $0315 ; sty $d012 lda #$7f ; Keep the screen on ldx #$1b ; and continue the sta $dc0d ; main interrupt stx $d011 ; read lda #$00 ;Initialise music tax ;according to tune tay ;number jsr $1000 ; lda #$01 sta $d019 ;IRQ is turned on sta $d01a ;---------------- lda $dc0d ;Copy $DC0D to $DD0D sta $dd0d ;to have the IRQ ;working properly. cli ;Clear IRQ flag loop jmp loop ;Jump to the loop ;Our main interrupt int asl $d019 ;Keep $D019 running ;Call routine to expand and reconvert ;the sprite positions jsr expand ;Call routine to read joystick port 2 ;for player 1 and player 2 jsr read1up jsr read2up ;Call routine for bullet movements jsr bullmove ;Call routine for collision detection ;and player 1 and player 2 bullet to ;player collision. jsr detect jsr p1col jsr p2col ;And finally play the music jsr $1003 ;Play music pla ; An IRQ loop routine. tay ; pla ; This will keep all the tax ; jsr routines playing pla ; without using JMP $EA81 rti ; or JMP $EA31 ;Expand and reconver the sprite position expand lda plr1Äy ;Copy player y sta $d001 ;to exact position lda plr1bÄy ;Copy bullet 1 y sta $d003 ;to exact position lda plr2Äy ;The same goes sta $d005 ;with this routine lda plr2bÄy ;but instead it sta $d007 ;works with p2. lda plr1Äx ;Copy player x asl a ;calculate 64 ror $d010 ;Expand x pos. sta $d000 ;put at exact xpos lda plr1bÄx ;Copy bullet asl a ;and do the same ror $d010 ;as with the sta $d002 ;player. lda plr2Äx ; asl a ;All this is the ror $d010 ;same except that sta $d004 ;it will work with lda plr2bÄx ;Player 2 and the asl a ;Player 2 bullet ror $d010 ;instead. sta $d006 ; rts ; ;Read joystick control for player1 read1up lda $dc00 ;Read port 2 lsr a ;Joystick up lsr a ;Joystick down left1 lsr a ;Joystick left bcs right1 ldx plr1Äx ;Move player 1 dex ;left across screen dex ;using 2 for speed cpx #$0e ;does the player bcs set1 ;move further than ldx #$0e ;$0e, if so then set1 stx plr1Äx ;stop. Else continue right1 lsr a ;Joystick right bcs fire1 ldx plr1Äx ;Move player 1 inx ;right across screen inx ;using the same cpx #$9a ;speed. If player bcc set2 ;exceeds $9a, then ldx #$9a ;make the player set2 stx plr1Äx ;stop. fire1 lsr a ;Firebutton bcs nojoy1 lda plr1lockup ;Is player fire cmp #$00 ;control bne nojoy1 ;unlocked. If so lda #$01 ;then lock fire sta plr1lockup ;and position ldx plr1Äx ;the bullet x stx plr1bÄx ;and y positions ldx plr1Äy ;exactly at the stx plr1bÄy ;same areas as ;the player. nojoy1 rts ;Read joystick control for Player 2 ;(joystick port 1) read2up lda $dc01 ;Read JOY Port 1 lsr a ;up lsr a ;down ;Please read the left2 lsr a ;left ;player 1 bcs right2 ;joystick control ldx plr2Äx ;as this routine dex ;is exactly the dex ;same as the cpx #$0e ;player 1 controls bcs set1Ä1 ;but works for ldx #$0e ;player 2. set1Ä1 stx plr2Äx right2 lsr a bcs fire2 ldx plr2Äx inx inx cpx #$9a bcc set1Ä2 ldx #$9a set1Ä2 stx plr2Äx fire2 lsr a bcs nojoy2 lda plr2lockup cmp #$00 bne nojoy2 lda #$01 sta plr2lockup ldx plr2Äx stx plr2bÄx ldx plr2Äy stx plr2bÄy nojoy2 rts ;call bullet routines bullmove ldx plr1bÄy ;The bullet moves inx ;but if it hits inx ;$F6+ it will stop inx ;off screen else inx ;if below that inx ;limit, the bullet inx ;/ moves on, else cpx #$f6 ;bullet off screen bcc repsbul1 lda #$00 ;Turn off the sta plr1lockup ;fire lockup ldx #$f6 repsbul1 stx plr1bÄy ldx plr2bÄy ;The bullet moves dex ;up but if it hits dex ;$0C- it will stop dex ;off screen, else dex ;if below that dex ;limit, the bullet dex ;/ moves on. else cpx #$06 ;bullet off screen bcs repsbul2 lda #$00 ;Turn off the sta plr2lockup ;fire lockup ldx #$06 repsbul2 stx plr2bÄy rts ;Setup collision detection for player 1 ;and player 2 detect lda plr1Äx ;Calculate sec ;the storage sbc #$06 ;values for sta plr1col+$00 ;the exact clc ;positions of adc #$0c ;player 1, so sta plr1col+$01 ;that when the lda plr1Äy ;opponents' sec ;bullet hits sbc #$0c ;the player, sta plr1col+$02 ;it has to be clc ;in the exact adc #$18 ;position of sta plr1col+$03 ;player 1. lda plr2Äx ;The same sec ;calculations sbc #$06 ;for player 2 sta plr2col+$00 ;bullet to clc ;player adc #$0c ;collision. sta plr2col+$01 lda plr2Äy sec sbc #$0c sta plr2col+$02 clc adc #$18 sta plr2col+$03 rts ;Check player 1 bullet collision on ;player 2 ship p2col lda plr1bÄx ;Is the bullet cmp plr2col+$00 ;at the correct bcc missp2 ;position where cmp plr2col+$01 ;the player is? bcs missp2 ; lda plr1bÄy ;If not then cmp plr2col+$02 ;the bullet bcc missp2 ;misses the cmp plr2col+$03 ;player. bcs missp2 ; lda #$f6 ;Else move sta plr1bÄy ;bullet off lda #$00 ;screen, turn sta plr1lockup ;off fire lock inc $0400 ;add 1 point lda $0400 ;check score cmp #$3a ;is it over 9? bne missp2 ;if not then ;miss, else jmp victory1 ;jump to win missp2 rts ;Check player2 bullet on player 1 ship p1col lda plr2bÄx ;Does the cmp plr1col+$00 ;bullet hit bcc missp1 ;the player in cmp plr1col+$01 ;exact position bcs missp1 ;of the player lda plr2bÄy ;ship? If so cmp plr1col+$02 ;then continue bcc missp1 ;else jump to cmp plr1col+$03 ;missp1 bcs missp1 lda #$06 sta plr2bÄy lda #$00 sta plr2lockup inc $0427 ;Add 1 point lda $0427 ;check score cmp #$3a ;is it over '9' bne missp1 ;if so then jmp victory2 ;player2 wins missp1 rts victory1 sei ;Stop all IRQs lda #$00 ;Turn off all sta $d015 ;the sprites ldx #$00 ;Call a routine win1 lda vic1,x ;to display sta $0400,x ;player1 wins lda #$01 ;message and sta $d800,x ;paint the inx ;message white cpx #$28 ;and display bne win1 ;as 40 chars jmp space ;Jump to space ;prompt victory2 sei ; Look at lda #$00 ; 'victory1' sta $d015 ;same function ldx #$00 ;This routine win2 lda vic2,x ;does exactly sta $0400,x ;the same, but lda #$01 ;it reads the sta $d800,x ;text from inx ;vic2 so that cpx #$28 ;player 2 wins bne win2 ;the game jmp space ;You know this ;if not then ;look at the ;previous ;'jmp space' ;prompt space ldx #$00 ;Another text setspc lda spc,x ;display sta $07c0,x ;routine. This lda #$03 ;time position sta $dbc0,x ;the text at inx ;the bottom of cpx #$28 ;the screen as bne setspc ;40 chars hitspace lda #$80 ;Create a raster cmp $d012 ;raster control bne raster ;to continue jsr $1003 ;playing music lda $dc01 ;Read SPACEBAR cmp #$ef ;if not pressed bne raster ;then jump to ;the raster to ;continue ;the SPACE read ;routine and ;play music jmp start ;Restart game ;Our text display data tables. ;Player 1 victory vic1 .text "player 1 proves that" .text " player 2 is a loser" ;Player 2 victory vic2 .text "player 2 proves that" .text " player 1 is a loser" ;Spacebar prompt message spc .text " press the spacebar" .text " for another game! "

Next Month: Enhancing your game a little more