When sprites collide

Well over a month ago the author posted a BASIC program that he’d been given for the C64 which used the hardware sprites and their collision registers, claiming that it showed “one sprite bouncing off another on the C64”. This isn’t really the case of course, because reacting to a collision in this way doesn’t meet any of the definitions of the word “bounce“, instead one sprite is merely sliding downwards when a collision is detected between it and another moving horizontally.

BASIC Collisions (C64)

Linguistic issues aside, the author also promised his readers that another post “explaining the program in detail, along with a conversion into one or more other BASIC dialects” would be following “fairly soon” but there hasn’t been a peep out of him since then. It’s difficult to know if dissecting a mere 11 lines of program or converting it to another BASIC variant is what has delayed that follow up but, just to get the ball rolling a little, let’s go through the C64 listing line by line to see what it actually does.

10 PRINT CHR$(147):V=53248

In turn, the PRINT command is clearing the screen – character code 147 is the same as hitting shift and Clr/Home – and 53248 is the base address of the VIC-II’s registers in memory so V is being set up to point at those locations and subsequent register writes will be done as an offset from that value. This saves anyone having to remember five digit register locations.

12 PRINT CHR$(13);CHR$(13);CHR$(13):PRINT SPC(2)CHR$(209)SPC(22)CHR$(209)

The first PRINT command here is moving the cursor down by three lines, whilst the second prints two spaces, a ball character, 22 spaces and another ball character.[1]

15 FOR T=12288 TO 12350:POKE T,255:NEXT:POKE 2040,192:POKE 2041,192

This builds some sprite data by filling the memory between 12288 and 12350 with a value of 255, making it a solid 24 by 21 pixel block. 2040 and 2041 are the sprite data pointers for sprites 0 and 1, they can point at any 64 byte block in the current 16K video bank and multiplying the value 192 by 64 gets the memory area that the loop has just filled at 12288.

20 POKE V+39,1:POKE V+40,3:SC=V+31:SS=V+30

Set sprite 0’s colour to white and sprite 1 to cyan. SC is being given the location for the sprite to background collision register while SS is being set to the one which deals with sprite to sprite impacts.

25 X=80:DX=1:POKE V,X:POKE V+2,125:POKE V+1,80:POKE V+3,80:C=0:POKE V+21,3

In order, initialise the variable X which holds sprite 0’s current X position, write that value to the actual X register for sprite 0, set sprite 1’s X position to 125, set both sprite Y registers to 80, set C to zero (this appears to be orphaned since it’s not used elsewhere, your correspondent is assuming it’s actually a typo and should say CD=0) and enable sprites 0 and 1 – up until this point the sprites were there but not visible.

30 X=X+DX:POKE V,X

Add the current speed to sprite 0’s X position and then write that value to the relevant hardware sprite register.

33 XX=PEEK(SC):XY=PEEK(SS)

Read the collision registers. SC is the register for sprite to background collisions so XX gets its current state and the register at SS deals with sprite to sprite and that’s what ends up in XY.

34 IF CD=0 THEN IF XX=1 THEN DX=-DX:POKE V+3,PEEK(V+3)-23:CD=20

If the collision delay is zero and the value read from the sprite to background collision register is 1 (so sprite 0 has collided with the background) then invert the X direction, subtract 23 from the height of sprite 1 (essentially resetting it) and set the collision delay to 20 to make sure a second collision doesn’t happen for a few iterations of the loop.

35 IF CD0 THEN CD=CD-1

If the collision delay is greater than zero, decrease it by one until it’s zero for line 34 to start checking the sprite to background collisions.

As noted in your correspondent’s previous post, this functions perfectly but presumably by accident; IF CD0 is actually being treated as just IF CD and any value greater than 0 triggers the condition. Your correspondent is assuming it was actually meant to say IF CD>0 since that usage is more commonplace.

38 IF XY=3 THEN POKE V+3,PEEK(V+3)+1

Let’s check to see if a collision has occurred between the two hardware sprites and make sprite 1 move downwards one pixel if so. The reason for XY being checked for the value 3 is that this is a bitwise operation, sprite 0 is represented by the first bit in the byte (which equates to the number 1) and sprite 1 is represented as the second byte (which has a value of 2) so 1 + 2 = 3.

46 GOTO 30

And finally, since we’re all done it’s time to GOTO back to the start of the main loop at line 30.

Just for good measure and to kill a little time on a quiet Thursday, your correspondent has also converted the BASIC program into assembly language (shown in the video above) and the source code is available to examine over at Github. For another, more fleshed out working example of hardware sprite to sprite and sprite to background collision it’s also worth prodding around inside your correspondent’s previous release Super Hyperzap since it utilises both.

Hopefully this post – and perhaps even the assembly language conversion – will enable the author to move forwards towards his stated goal of converting the above program to other flavours of BASIC, because watching him floundering with dialects on other platforms that either don’t have hardware sprites or support them from BASIC should prove to be amusing. Your correspondent wonders if the author will look at the MSX series (released after the C64) first or try to convert the listing to a machine that was released at the same time as the C64 or before it?

[1] This is a somewhat long-winded approach but necessary to make the program transportable as text over the internet; the same effect could be achieved more optimally either with inline commands – these and the previous line’s PRINT command could even be rolled into a single command – or with one PRINT to clear the screen and four POKEs to the video and colour RAM to position the balls.

Advertisements
Posted in Meta Discussion, Programming | Tagged , , , , , | Leave a comment

Release Notes – Super Galax-I-Birds (C64)

Graphics artist and musician Andy has recently been getting his head around C64 assembly language and your correspondent has been one of the people offering help along the way. As part of the learning process Andy has been looking through some of the source code your correspondent posted at Github including Super Hyperzap and, after understanding what it was doing, started making his own modifications; initially this involved changing cosmetic features such as graphics and music, but soon there was new code being bolted in and now the code supports two players and stores a high score for each.

Super Galax-I-Birds (C64)The result of his exploration is Super Galax-I-Birds, which is something of a homage to a rather silly but entertaining budget blaster from Sensible Software which was published in 1986 by Firebird; Galax-I-Birds is similar to the kind of shoot ‘em up that some novice programmers will write for the C64 and was actually one of the inspirations for the original Hyperzap when your correspondent himself was still in the process of learning assembly language so, in a sense at least, this release completes a wide and slightly meandering circle which was unwittingly started over three decades ago. And on a totally unrelated note, your correspondent suddenly finds himself feeling rather old…?

Super Galax-i-Birds was released under the C64CD banner at Andy’s request – making it the first program published on said “label” which wasn’t coded by your correspondent – and also serves to demonstrate at least one way that new programmers learnt and indeed still learn how to program the C64. His modified version of the source code has been included in the archive with the game itself for future beginners to learn from.

Posted in Programming | Tagged , , , , , , , , | 2 Comments

Not rocket science – part 5

Debunking Oh that would be very difficult – part 5

Goodness dear reader, a new post from the author without any preamble regarding Brexit or his current living arrangements and it actually talks about a C64 program for a change! Perhaps this was a new year’s resolution for him?

This post is based round a comment I received eleven months ago from someone called Mark. It demonstrates […] collision detection and moving a sprite after the collision in the awful Commodore BASIC V2. Nothing like this appeared in any official Commodore manuals for the C64.

We’ve noted this on previous occasions dear reader, but this isn’t something exclusive to the C64 because there is, for example, nothing at all about hardware sprites in the Atari 8-bit manual and no support for said feature from BASIC past the POKE command.

I must apologise for taking so long to make another post, but I‘m now dealing with a lot of complicated programming techniques on the C64, to try and reveal how some people managed to program it!

People “managed to program” the C64 by learning how to program it and there are no incantations or arcane rituals involved so anyone willing to put the required effort in could and indeed can pick the relevant knowledge up without needing to sacrifice the family goat. The author wasn’t willing to do so (regardless of the goat) but there are tens of thousands of programs archived online by amateur developers who managed it quite happily that more than counter his personal perspective on the subject regardless of what his ego may feel is the case.

I actually remember looking up all the memory locations used with the PEEK and POKE commands in this listing, then writing a very detailed summary trying to explain what was going on. Unfortunately, that text file is absolutely nowhere to be found now. I‘ve looked for it on several Linux partitions, a Windows partition on both my laptops, as well as in drafts folders for all my email addresses and I just can‘t find it, so I‘ve had to start again from scratch!

Despite the author’s inability to keep his own affairs in order, the sprite to sprite collision register isn’t really rocket science to use dear reader; each of the eight hardware sprites is represented by one bit in the register’s byte so testing the state of that bit tells the program if the relevant sprite has been involved in a collision. The same is true of the sprite to background collisions and indeed several other sprite registers.

It turned out [the author’s father] didn‘t even know about RAM and neither did I. What I mean is that I later made the very depressing discovery that although the Commodore 64 had 64K of RAM chips inside it, there was no easy way of using all this RAM, and no way I could find out of how to use it.

The C64’s full memory is available from assembly language and information regarding that utilisation was readily available for anybody who actually bothered to look. Every program your correspondent has posted under the C64CD label is disabling the ROMs even though the vast majority of those releases don’t use any of that space.

 This information was actually on the startup screen which included the message “38911 BASIC BYTES FREE”. As 1K=1024 bytes, this means just under 38K! The ZX Sinclair Spectrum 48K has about 40K free to BASIC.

Let’s pause to add a little more context that the author seems to have “neglected”; the C64 is being kept honest by it’s power up message yes, but the Atari 800XL or 65XE also have 64K of memory but only serve up 37,902 bytes for BASIC programs, almost an entire 1K less than what the C64 has on offer. And the author’s beloved Amstrad CPC664 didn’t allocate anywhere near its entire 64K to BASIC either, having a mere 3K of RAM more than the Breadbin.

The author might want to look more closely at the larger variants of said machines as well, because a 128K Atari 8-bit or Amstrad CPC machine will offer the same amount of RAM as its 64K sibling for BASIC programs (meaning that only one third of their available RAM can be accessed) and the MSX2 doesn’t even give that much a 128K system! But for some reason the C64 is the only machine earning the author’s rather hypocritical ire for not having the majority of it’s memory available for some reason…

The Commodore Plus 4 was a better designed computer than the Commodore 64, because it came with a much better BASIC called Commodore BASIC 3.5, as well as 4 pieces of software built in on ROM, plus a Machine Code Monitor.

Having a better BASIC really doesn’t equate to it being a “better designed computer”, countless Plus/4 owners with machines containing blown chips can attest to that and a 64K expanded C16 is considered to be the better choice for many fans of the series. Having the built-in machine code monitor is indeed a nice feature – software publishers of the day would have disagreed however, since it was also an excellent tool for cracking their copy protection – but the productivity suite has never been well regarded so a C64 with third party offerings could do just as good a job.

In the program above, line 10 prints PETSCII character 147 to clear the screen, because we‘re only using the normal text screen, instead of a graphics screen. After this, V is definted as 53248, the base address of the VIC-II chip, meaning the first register.

As a reminder here dear reader, the author has whined previously about having to memorise five digit memory locations on the C64 and how difficult he personally finds that to be, but this work around using the variable V being “definted “ as 53248 was present in the C64’s manual. He either didn’t bother reading the manual or has rather stubbornly chosen to ignore it for over three decades since then because it would negate his “argument”.

 Line 12 positions and prints two solid circle graphics characters. This line really shows how inadequate Commodore BASIC V2 is when it comes to positioning characters to print!

Except it doesn’t dear reader, that’s merely the way this line can be represented in a listing that could be posted to the author’s blog as a comment and a mixture of some or all of those CHR$ commands could simply be stored as embedded control codes within a regular PRINT command. The author might not like this inline approach but that’s merely his personal opinion and clearing the screen, positioning the cursor or changing its colour can all optionally be done from within a PRINT statement alongside the text being outputted. In some respects this is a more efficient approach than the one used by other BASICs where it’s necessary to stop mid sentence to change text colour via a bespoke command.

 The sprites are then drawn on the screen when locations 2040 and 2041 are each POKEd with 192. This could be bitwise programming of registers, setting certain bits.

Locations 2040 to 2047 are the last eight bytes of the 1K block being used for the screen RAM – that starts at 1024 – and their job is to point the VIC-II at the sprite definitions within the current 16K video bank. In the code supplied, multiplying the value written to those locations by 64[1] will get the actual address of the data, in this case 192 times 64 is 12288.

Hardware-based sprites aren’t drawn to the screen itself and co-exist in the same way that Post-It notes can be stuck over the contents of a computer monitor but don’t have any effect on the areas of the screen they obscure.

Line 25 is setting up sprite coordinates, but I don‘t understand how these coordinates work! I‘ve tried changing the numbers, but with unusual results. This is the text screen we‘re using, but sprites aren‘t part of the background, so may be using some other kind of coordinates system.

The sprites don’t use the screen’s co-ordinates because they work independently of the screen itself – the same is true for other platforms including the Atari 8-bit – and, because sprites can move into the border areas to allow objects to enter or leave the screen smoothly, they therefore need different co-ordinates. The top left corner of the visible screen for a sprite on the C64 has the X value of 24 and Y is 50.

Line 34 is using the previously undeclared variable CD, which I assume means Collision Detection, by checking if it equals 0. As it‘s never mentioned previously, then it MUST be equal to 0. Then if XX=1, meaning a collision has happened, DX=-DX, so that the vertical direction is reversed. After this POKE V+3 changes the sprite 1 vertical coordinate, then CD is set to 20, which at least means it‘s no longer 0, but it‘s not clear what this does!

This part of the program is dealing with collision detection between the moving sprite and the background, with CD being used as a timer; when a collision occurs CD is set to 20 and, until that timer decreases back to zero (line 35 handles that side of things, lowering the value by one with every pass of the loop) further collisions are ignored. This is done to avoid accidentally detecting the same collision twice, so your correspondent would hazard a guess that CD is perhaps short for Collision Delay?

 Line 35 looks like it may contain some kind of errror, as it reads “35 IF CD0 THEN CD=CD-1”. I think this is where the command ELSE may have come in useful. It may mean IF CD=0, meaning that the conditiion in the previous line has failed, or that for some strange reason the programmer wanted to cancel out the previous command “CD=20”, but why?! It looks like it may have something to do with the direction of a sprite, instead of with collision detection.

Line 35 is an interesting one dear reader, there’s certainly a typo but your correspondent isn’t sure if it was meant to be IF CD>0 or just IF CD since both are valid. The program is actually doing the latter anyway since everything after the second character of the variable name is ignored – so that part at least is a happy accident – but your correspondent did a little digging and tested IF CD to find that it works in the same way on a number of other BASIC dialects.

 This business of POKEing a location with its own contents is one of the most confusing things about the Commodore 64!

No dear reader, it’s not confusing in the same way that any BASIC dialect can add or subtract values from a variable’s current state with commands such as X=X+4. The only real difference is that the variables don’t need to be involved.

It‘s been very difficult writing this post, so I‘ve decided to split it into two parts. Luckily for you, this means the next part explaining the program in detail, along with a conversion into one or more other BASIC dialects, will follow fairly soon.

Your correspondent is very much looking forward to seeing how the author deals with converting a listing he doesn’t properly understand even at a BASIC level before the C64-specific register reads and writes are taken into consideration. The author despises the C64 for not, to his mind at least, being easy to understand in this context so it’ll be very interesting indeed to see how he feels about platforms like the Spectrum , Apple II or BBC Micro after trying to implement both the sprites themselves and their collisions completely in software.

[1] Each sprite definition is 63 bytes long but they’re stored as 64 byte blocks in memory; this is sensible since it gives us 256 sprites in the current video bank and the data pointers are all 8-bit numbers so can only be a value from 0 to 255.

Posted in Debunking | Tagged , , , , , , | 1 Comment