FROSTBITE C64 - diary of a programming novice ...

Friday May 30th

 

In contrast to yesterday, I woke up raring to go, perhaps because the problem I left last night seemed so easy to solve. Thankfully it was, but I was still a little disappointed with the running speed. With so much still to add it’s not fast enough for my liking. At least I have found that updating the positions twice between drawing them runs pretty quickly.

 

Anyway, without worrying about such things, I think it’s time to add some player input. Sorted out the use of the fire button to change the direction of the icebergs. This was a snap, in actual fact, as the iceberg direction variable is set up with bits set and unset in the high nybble of a single byte, so it was just a case of setting up another byte containing the player’s current level, with bit 0 set if he’s on the ground, bit 1 set if he’s on the first ice level, etc. Then whenever he changes level, it RORs or ROLs the bit along the player level byte, and when the fire button is pressed, it loads up the byte and, in similar fashion to the joystick routine published by TMR in the OSG forums, you just LSR until you find where the player level bit is, then EOR the iceberg direction by either #$80, #$40, #$20 or #$10 respectively for each row. For once, something seems to have had an elegant solution, and I’m quite pleased that the planning has done the trick. Again, I think looking over Ralph’s shoulder while watching him code in C++ has helped a lot.

 

Then spent late morning working on a couple of fixes for ‘playability’ (a slightly optimistic word at this stage). I decided I might be able use hardware player to background detection, and that it would be a good thing if I could – after all, I ought to take every opportunity to get something for nothing from the VIC chip, given that moving the icebergs around is costing CPU time. I’m checking collision between background and the player’s torso by checking bit 1 of $d01f. If the collision’s happening, the player’s face is supposed to turn blue (I had it as a red border flash previously). First thing was that the player’s torso brushes the ice floe above, and thus collisions with that row are also detected. This was sorted out pretty easily by moving the player down 4 pixels. His position on the icebergs is now a little low, but there may be a way to draw some of the body in the ‘head’ sprite, though I won’t be able to use orange, as the sprite-specific colour needs to be pink for the player’s face. However, sometimes the collision checking routine still returns a 0, even when Frostbite is on terra firma at the top of the screen; again, the way in which collision detection and screen refresh work is something I’ll need to research. But for now, I’ve changed the program so that it has to detect 3 ‘no collisions’ in a row before turning the player’s face blue. This does let you – on occasion – get away with jumping on the water and immediately hopping off, but I don’t see much point in worrying about this until the screen refresh has been cleaned up. The other fix was a simpler affair, setting a fire button flag so that the direction changing method will only work if the fire button has been released before being pressed again. This prevented the program from cycling too quickly between direction changes when fire is pressed.

 

Spent the afternoon developing the player status register so that I could start to get the game running with delays and events, such as jumping, which require several stages during which other things have to be going on. So far, there are only 3 things that really happen to the player – he’s either on the ice (‘landed’), jumping or drowning. All three events are already detectable but for the latter two, their detection leads only to a single consequence that happens instantaneously. By putting together a status register (á la Ralph) I can now set bits 0-3 on for, respectively, landed, jumping up, jumping down and drowning. So jumping is now controlled by an increment that will allow all the other updating processes to go on, and drowning freezes the player for a while (while everything else keeps going) and reinitializes the level. At first things started to go wrong though, so I put a pair of status monitors in the top left corner of the screen – one to display playerstatus and one to display playerlevel. The bottom one of the two was cycling like haywire, because although I’d enabled the jumping routine, I hadn’t disabled the up and down controls while jumping which, although betraying no immediately discernable change in gameplay, would still be increasing the player’s level to numbers far higher than the 4 rows that there actually are on screen. Once the status monitors had given the game away, putting a block into the jump routine was fairly straightforward. The final work of the afternoon went on moving Frostbite along with the icebergs. Again, once a safe landing has been detected and fed into the player status byte, it was fairly easy to use the player level gauge and the iceberg direction nybble to add an increment or decrement to Frostbite’s X position whenever the icebergs are updated. So, a day on which a lot of very visible changes have been made, and the first day on which it might be said that my game is actually a game – albeit a very poor one. Still a long way to go though, and many lessons to be learnt yet …!

 

 

Thursday May 29th

 

A slow start to the day. Monday’s return to school looms ever larger, and in a way I feel the need to just slob around a bit and at least try to enjoy the opportunity to get bored. The programming has been really absorbing – I’m a fidgety person by nature and it takes a lot to make me sit in one place for hours, but programming has done the trick!

 

Decided early on that it would be a good idea to switch the VIC-II to Bank I, as I wanted as much free space as possible for sprites. I couldn’t find the necessary instructions on which memory location to adjust to make this switch in the Programmer’s Reference Guide, but thankfully – Hex Files to the rescue again! A quick lda #$02 to $dd00 and the job was done. Thought that switching all the address for screen location in my program would be time-consuming, but it wasn’t. In fact, everything’s handier now – screen is at $4400, the characters at $5000 and the sprites are loaded in at $5800. That gives me 10K for sprites if necessary, which I’m sure will be more than enough. I could also include another bank of characters at $5400, and was thinking about the possibility of backbuffering the screen at $4800, which might sort out the shearing problem on the moving icebergs. I still don’t really know if that’s a possibility though. Every time I tell myself something like this, I can imagine real programmers burying their heads in their hands.

 

Putting the player sprite (2 of them actually – he is two sprites tall) on the screen was simplicity itself, and getting it moving was fairly easy too. However, collision detection is becoming an issue, and unfortunately, I expect I’ll need to program some kind of software collision detection. At first I had a problem with my colours – I’d mistakenly drawn the sea as the 11 colour (the one set by colour memory) and the snow as the 01 colour (set by $d022), which, for the purposes of sprite-data collision, is classed as background. So I had to swap the two colours around in Char Pad, resave and set the screen up differently. And even then, the top of Frostbite’s body is coming into contact with the ice floe above, which ruins the collision detection. I suppose this could all be changed if I made him shorter, but I don’t think that would be very effective from an aesthetic point of view.

 

Another thing that is now happening is that I’m having to start considering how to run the main game loop. Now that there are two processes going on, the movement of the ice and the user-controlled movement of the player, it no longer works simply with a delay loop because the player movement and iceberg movement require different delay times. Also, I’d like to start setting up a player status register that controls whether he is jumping, landed, immobilised by a creature, in contact with the bear, eating a fish, freezing or drowning. The plan is to push the bits along one by one into the carry flag, so that the status can trigger appropriate behaviours, something like: lda playerstatus; lsr a; bcc landed; jsr jumping; lsr a; bcc immobilised (etc., etc.!). The ‘status register’ concept is something I learned from my friend Ralph while we were working on Tuxbite for the PC.

 

However, I began discovering some serious slowdown problems – already, and there is so much left to add! I was quite surprised by how quickly things moved on earlier versions, and in a way my expectations of things being slow have caught up with me. Problem is that the ice drawing routine is checking every character to see whether it has gone off the right of the screen, something which has surely been made worse by the fact that I changed the drawing routine to draw each character in each of the three top left positions, then increment the character by one and go back to the original position+1. Problem with this is that the notional ‘cursor’, as held by the y register, is whizzing around all over the place, and for every calculation made, you have to dump the accumulator onto the stack, transfer y across to the accumulator, do the calculation, transfer it back to y, then pull the accumulator back off the stack again – all of which is burning clock cycles by the bucketload. It all seems so obvious now. But it’s late, so it’ll not get fixed until tomorrow …

 

Wednesday May 28th

 

Started today on trying to get the icebergs moving, with the check on wraparound planned for later on. Tried a few tricks fairly new to me today, such as using the stack for more than temporary storage while transferring the X or Y register to the accumulator to do a calculation. I also used the stack for the first time today in order to push the processor status after doing an asl, so I could do a bcc at a later time.

 

However, with all that cleverness going on, I went and screwed things up big time. After assembling and running in VICE, it crashed completely, and of course without giving any obvious clues as to what had gone on. Then I realised – old clever clogs had used the stack for storing the xposition and xoffset and then jumped to a subroutine. The first thing the subroutine does is pull the two values off, followed by the processor status. Problem is, whenever you jump to a subroutine it puts the return address on the stack. So the first thing my subroutine was doing was pulling the return address off and hence preventing the program from knowing where to return to …

 

Sorting out the wraparound was a tricky one. At first I was getting the program to check both left and right limits, forgetting of course that if the left limit goes beneath zero, it is automatically adjusted to 39 by another routine. It's only the right limit that needs checking, as the iceberg plotting routine takes the initial x position then draws the remainder of the iceberg, and the two other icebergs on that row, all to the right of the initial position. So each block needs to be checked in turn. Unfortunately, I was trying to do too much with just the one register. The routine plots the three icebergs by taking a single character at a time, then adc-ing #$08 twice to plot it three times. If the third of those goes off the right, you make the adjustment (sbc #$28). However, when you then go to the next character, you want it to be one character to the right of the previous one. Before including the wraparound routine, this was a simple sbc #$0f to couter the two adc #$08 and add #$01 at the same time. However, the adjustment screws this calculation up entirely. If the leftmost block on a row has wrapped around and now occupies x=38, then the other two blocks will be caught by the wraparound routine and changed to 6 and 14 respectively. If, however, you now try to sbc #$0f, things start to go wrong, because it's greater than the value of the adjusted y register, which then starts wrapping around to 255. I sorted it out with a flag, but it's an ugly little fix really and I don't like it much. Still, that's outweighed considerably by the fact that it seems to work. Hurrah! 

 

Tuesday May 27th

 

First big day of coding; my intial plan was to get the icebergs onscreen and, if possible, moving! Thought I'd concentrate on rows 1 and 3, the rightward moving icebergs first. The scroll basically works by increasing the offset - effectively moving up the charset by 24 character intervals and then increasing the x position by 1. It also incorporates a wraparound check which ensures that characters that go off the right of the screen do not appear on the line below. As each x position is fed in, the program branches to a subroutine which subtracts $28 (must get used to thinking in hex!) if any block exceeds that value.

 

However, all that had to go. I had forgotten that because the player can change the direction of the ice floes, they really need to be controllable independently. This changed the complexion of the iceberg draw and update quite fundamentally. However, it did give me a chance to try out a couple of things I'd never done before, such as using the stack and indirect indexing. After a lot of trial-and-error debugging, I managed to at least get the four ice floes printed on the screen using the new method, fetching the xposition and xoffset of each ice floe in such a way as to allow independent control. I also set up a direction indicator which should allow me to shove bits into the carry flag to check the direction of each ice floe and update accordingly. However, having finally managed to get the ice floes on screen, I decided that update/wraparound checking could wait for another time ...

 

Monday May 26th

 

After spending the weekend creating placeholder graphics, I thought I'd make the plunge with the code. I'm still acutely aware that I'm very much a beginner, but I felt I had learnt enough from the Hex Files and the C64 Programmer's reference guide to at least put some graphics on the screen.

 

On my first try, I set up some loops to draw the main on-screen graphics - sky blue blocks for the sky (duh ...), blue for the water and white for the ice. Also, the ice shelf comprises a row of eight UDGs. I had had this at 6 characters but the loop seemed easier with 8, as 40 (the width of the screen) divides evenly into 8. Unfortunately I saw nothing, as I'd forgotten to put multicolour mode on! A simple lda $d016; ora #$10; sta $d016 did the trick. It also made the BASIC method of doing this seem a little less ... well ... basic. Anyway, with that sorted out the screen display came up fine. The dimensions needed sorting out a little to allow the lower part of the screen to display 4 icebergs at 4 characters high each, but this hardly presented an insurmountable problem!

 

Pottered around with the UDG set for the rest of the day, primarily with copying the chars and shifting them right to allow smooth movement of the icebergs. Finished the character set - just an 8x8 set for now, but I may do 1x2 numbers in the finest Activision style later on.

 

Hosted by www.Geocities.ws

1