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.