Monday, 13 January 2020

Level 3 Insertion

A fair few months ago, I started to design Level 3 for the game (see blog post here).  Up until yesterday, it only existed in my screen editor, but I've finally exported the screen and colour ram data and inserted it into the game, along with the code to set-up and call the level.

Since this level has been languishing for a while, I thought it deserved some habitation, so I've also added some data to the enemy table for this level and there are now various baddies crawling and flying around.  I still need to add some x and y data for the cross locations; currently the data table contains my stand-by data that only contains 2 locations that strobe back and forth.

Once it was all up and running, I wanted more screen action, but in a subtle way.  I've seen a couple of games recently that have rain in the background (it seems fashionable to have rain in your game at present and, at time of writing, appropriate given the weather outside) so I decided this level shall have rain!

I must also admit to having watched Simon Jameson's Twitch channel the other night where he demonstrated how he had implemented rain in his game and this also provided the idea and motivation for me to include rain in Chiller 2.  However, I wanted a much simpler solution for my game compared to Simon's code, so decided to go with the 'copying char data around' route rather than the pixel plotting through a char route he demonstrated.

So, to start I set aside 5 sequential chars that will be used for the rainfall and plotted a 1,2,3,4,5 repeating sequence in columns using these chars.  In the editor to begin with, the rain looked a little like this...


I did my very best to ensure it looked 'random', with columns of chars that were near or adjacent to each other not having identical numbers that were in-line (1's in line with other 1's, 2's next to other 2's and so on) - not doing this would have resulted in very unnatural looking rainfall methinks!  Once I was happy with the layout, I cleared the chars themselves of the numbers, knowing the chars were still actually in place on the screen.

I then designed a simple raindrop, not in the editor, but on a scrap piece of paper which I then turned into a table of hex bytes.  If you're interested, that table of data looks a little like this within my code...



 ; raindrop pattern  
   
 rain_patt     !byte $ff,$ef,$ff,$ff,$ef,$ff,$ef,$ff  


And then it was time to code a very simple rainfall by copy my raindrop pattern above into each char sequentially.  The code I came up with looks a little like this (please note, this is wholly unoptimised at present but was written this way to ensure it could be followed in the future by me!):


 l3_bkgrd_anim                          ; level 3 rain  
   
 ; clear all raindrops first  
   
           ldx #$00  
           lda #$ff                     ; char needs to be solid!  
 clear_rain            
           sta $2400,x                  ; raindrop 1  
           sta $2408,x                  ; raindrop 2  
           sta $2410,x                  ; etc  
           sta $2418,x  
           sta $2420,x  
           inx  
           cpx #$08                     ; all 8 bytes of each char cleared?  
           bne clear_rain               ; no? branch back  
             
 ; now check which raindrop should be drawn! 
   
           lda raindrop                 ; which raindrop are we on?
             
           cmp #$00                     ; drop '0'?
           bne *+$05                    ; no? go and check drop '1'
           jmp draw_rain0               ; yes? go draw rain0!
   
           cmp #$01  
           bne *+$05  
           jmp draw_rain1  
             
           cmp #$02  
           bne *+$05  
           jmp draw_rain2  
             
           cmp #$03  
           bne *+$05  
           jmp draw_rain3  
             
           cmp #$04  
           bne *+$05  
           jmp draw_rain4                                     
             
 draw_rain0       
           ldx #$00  
 rain0_loop  
           lda rain_patt,x            
           sta $2400,x  
           inx  
           cpx #$08  
           bne rain0_loop  
             
           jmp draw_rain_dun  
             
 draw_rain1       
           ldx #$00  
 rain1_loop  
           lda rain_patt,x            
           sta $2408,x  
           inx  
           cpx #$08  
           bne rain1_loop  
             
           jmp draw_rain_dun  
             
 draw_rain2  
           ldx #$00  
 rain2_loop  
           lda rain_patt,x            
           sta $2410,x  
           inx  
           cpx #$08  
           bne rain2_loop  
             
           jmp draw_rain_dun  
             
 draw_rain3  
           ldx #$00  
 rain3_loop  
           lda rain_patt,x            
           sta $2418,x  
           inx  
           cpx #$08  
           bne rain3_loop  
             
           jmp draw_rain_dun  
             
 draw_rain4  
           ldx #$00  
 rain4_loop  
           lda rain_patt,x            
           sta $2420,x  
           inx  
           cpx #$08  
           bne rain4_loop  
             
 draw_rain_dun  
           lda raindrop  
           inc raindrop  
           cmp #$04  
           bne reset_bkgrd_anim_tmr  
           lda #$00  
           sta raindrop
  

What's happening?  Well, when this routine is called, first of all I'm clearing all five rain chars to erase any previously drawn chars (this could be optimised to clear only the last previously drawn char!).  Then, using a 'variable' that stores which raindrop we're on (it starts with '0'), the code determines which char should be drawn to next and jumps to the drawing code for that char and copies the raindrop pattern data pattern into that char's memory location.  The code then jumps to a label called 'draw_rain_dun' which increases the raindrop variable and then checks to see if all five chars have been drawn to in sequence.  If they have all been drawn to sequentially over the course of the routine being called a few times (i.e. the fifth raindrop char was last drawn to), the code resets the raindrop variable to '0' so next run through the raindrop pattern is drawn to the first char again.

Hopefully that makes sense?!  Of course, this code is also inside a timer that executes it (at present) once every 4th frame.  Without the timer that rain would, er, rain too fast!

To be honest, if this code was applied to the whole screen and not just the top of the buildings as in my level, it would probably look pretty jerky.  However, in the context of my level and game, it has a nice cartoony feel that I'm very happy with!  What does it look like?  Something like this...


Next diary entry...

No comments:

Post a Comment