Wednesday, 31 July 2019

Status Bar Score

I gave myself the afternoon off work today so had a little extra time for coding; this time was welcome as there are lots of little background routines that need to be written before the code transitions from being little more than a demo into an actual playable game.

Since the sprite to sprite collision code was written recently along with the energy bar, I thought I'd write a couple of routines to handle the scoring and the cross counter to complement the energy bar.

I did actually tweak the collision detection code the other night so that my yellow cross sprite didn't deplete the energy bar as it was doing; it was originally part of the main enemy check that did remove energy.  As a temporary measure for testing purposes, I made collision with the yellow cross change the background colour so I knew the code was executing in the right order.  My Grandson is doing some testing for me and he made a noise equal to "Urgh!" when he first saw the background change, hence my decision to do some code that increases the score and cross counter.

I've had it in my head for a while now that collecting crosses will score the player 100 points and that 20 yellow crosses will need to be collected to complete a level.  The code keeps this in mind, but this could change in the future.

Here is the code in action; at the moment the yellow cross sprite doesn't change position when "collected" so that multiple collisions can be registered to test the status bar.



How does it work?  When a collision with a yellow cross is detected, a flag is set which then makes the main code loop jump to a subroutine that increase the score by 100 and the cross counter by 1.  Well, that's what it looks like in practise, but I learned a trick a few months ago from Jason 'T.M.R' Kelk: no "real" score is actually ever used.  All that's really happening is that score digits are being checked and manipulated in a table.

Eh?  Well, keeping in mind that my score is six digits long, collecting a cross adds a 1 to the fourth column along from the left (hundreds).  This keeps happening until the column reaches a maximum of 9, at which point that column resets to 0 and the third column along from the left (thousands) increases by 1.

The same happens to the cross counter as well.  When a cross is touched, the units column is increased by 1 until it reaches 9, at which point the tens increases by 1.  No "real" scoring in the sense that humans think of it.

This method has the benefit of using RAM to store the score instead of space in the zeropage.  Also, it's now going to be quite easy to check the end of the level.  All I will need to do is load up the tens column of the cross counter and see if it's equal to 2.  If so, "20" crosses have been collected and the level is complete!

Anyway, here is the score code that increases by 100.  It is flexible so that I can very easily add an increase of, for example, 1000 on level completion in the future.

 ; score accrue subroutine ------------------------------------                 
   
 score_accrue_100  
           ldx #$03  
             
 sa_loop  
           lda score,x  
           clc  
           adc #$01  
           cmp #$0a  
           beq sa_cnt  
           sta score,x  
   
           jmp score_compare  
   
 sa_cnt       
           lda #$00  
           sta score,x  
           dex  
           cpx #$ff  
           bne sa_loop  
   
 ; now compare current score to high score  
   
 score_compare  
           ldx #$00  
 score_chk  
           lda score,x  
           cmp high_score,x  
           beq score_chk_cnt  
           bcc score_chk_end  
           bcs hi_score_update  
 score_chk_cnt       
           inx  
           cpx #$06  
           bne score_chk  
 score_chk_end  
   
           rts  
   
 ; current score is a high score???  
   
 hi_score_update  
           ldx #$00  
 hi_up_loop  
           lda score,x  
           sta high_score,x  
           inx  
           cpx #$06  
           bne hi_up_loop  
             
           rts  
   

If you've just read that code block, you may just see that a high score comparison routine is included for good measure.  I thought at first that the high score would only be updated at the end of a game, but instead decided to update it on the fly should, during play, the player accrues a current score equal to or greater than the current high score.

The cross counter routine works on a similar principle, with the current amount being stored in a "cross_score" table after digit manipulation.  It's shorter because there is no high score check obviously!

 ; cross accrue subroutine ------------------------------------                 
             
 cross_accrue  
           ldx #$01  
 ca_loop  
           lda cross_score,x  
           clc  
           adc #$01  
           cmp #$0a  
           beq ca_cnt  
           sta cross_score,x  
             
           rts  
             
 ca_cnt       
           lda #$00  
           sta cross_score,x  
           dex  
           cpx #$ff  
           bne ca_loop  
             
           rts  
   

Once all this digit manipulation is complete, I have a subroutine that prints the contents of the score, high score and cross tables into the correct places on the screen.

And that's scoring done for now!

Next diary entry...



Tuesday, 30 July 2019

Default Player

After showing the title screen dancing player select option on Twitter the other day, someone suggested that perhaps the girl should be the default player!

I debated for a few hours and then decided this was a good idea!  I've not done this as some kind of feminism based altruism, even though it was pointed out that even little choices like this in support of women can go a long way.

The actual reason for making the change is to differentiate Chiller 2 from the original game.  In 1984 you played as the boy out to rescue the girl by collecting blue crosses and after playing through the levels and "rescuing" the girl, you then had to play through the levels backwards as both the boy and the girl, with the girl collecting pink crosses.  Hmmm... does seem a little 1980's to me.

Thus, in 2019 you can select to be either girl or boy at the start and both characters have to collect yellow crosses.  That seems a bit more "modern" to me.  As for playing levels backwards when all levels are complete:  I may still incorporate this in my game.  I may also do a character switch on last level completion so you have to play as both characters anyway.  Since the girl and boy have slightly different in-game characteristics, this will perhaps extend the gameplay, providing a bit more of a challenge?

Someone also suggested using some character names (Tina and Tom) on the title screen instead of "girl" and "boy".  The only problem is the characters are called "Michael" and "Michaela" and that doesn't fit on the screen!  Those names do appear in the brief instructions in the "scrolling" message.

So after a quick code rearrangement, the girl is now selected by default on first load.



Next diary entry...

Friday, 26 July 2019

Dancing Player Select

A couple of weeks ago, I was playing around with the title screen for the game looking for a way to add more movement and/or break up all the text a little.  I added some some extra sprites to the bottom part of the title screen by recycling another 3 sprites in the second raster split.

At the time, I made both the boy and girl player sprites dance in time to the music.  After adding this, I thought it might be a nice idea at a later date to make only the player you select (boy or girl) dance, while the unselected option stood still.

Today was that 'later date' and it's finally in!  On the title title screen, pushing left on the joystick selects the boy to play in the game, while pushing right selects the girl.  Further highlighting the selection is the text next to the boy or girl which is coloured white or dark grey depending on the choice made.

I'll be honest, at the moment pressing fire to enter the first level results in the boy sprite being displayed, even if the girl is selected.  I still need to write the code to copy the right sprites into place.  However, in the background, variables are being copied into place that changes the way the player behaves or is affected by other sprites.  Currently, playing as the boy means that less energy is taken away on contact with a meanie than with the girl, but on the other hand, the girl can move a little quicker than the boy.  These attributes will probably change as more progress is made on the game!

However, here is a screen dump of a small part of the title screen of the the boy/girl select in action:


And the code that switches between the two players...

 ; title screen player select subroutine ------------------------  
             
 boy_select  
           ldx #$d8  
           stx t_sprite_def+$01  
           stx t_sprite_anims+$01  
           ldx #$dc  
           stx t_sprite_anime+$01  
             
           ldx #$dc  
           stx t_sprite_def+$02  
           stx t_sprite_anims+$02  
           ldx #$dd  
           stx t_sprite_anime+$02  
             
           ldx #$00                         ; zero x register  
 boy_sel_loop                                
           lda #$01                         ; load white  
           sta $db51,x                    ; write 'boy' in white  
           lda #$0b                         ; load dark grey  
           sta $db5d,x                    ; write 'girl' in dk grey  
           inx  
           cpx #$05                         ; done 5 writes?  
           bne boy_sel_loop               ; all written? no? loop back!  
             
           lda #$00                         ; make player store 0  
           sta ply_type                    ; so boy is selected  
             
           rts  
             
 girl_select  
           ldx #$d8  
           stx t_sprite_def+$01  
           stx t_sprite_anims+$01  
           ldx #$d9  
           stx t_sprite_anime+$01  
             
           ldx #$dc  
           stx t_sprite_def+$02  
           stx t_sprite_anims+$02  
           ldx #$e0  
           stx t_sprite_anime+$02  
             
           ldx #$00                         ; zero x register  
 girl_sel_loop                                
           lda #$0b                         ; load white  
           sta $db51,x                    ; write 'boy' in white  
           lda #$01                         ; load dark grey  
           sta $db5d,x                    ; write 'girl' in dk grey  
           inx  
           cpx #$05                         ; done 5 writes?  
           bne girl_sel_loop               ; all written? no? loop back!                 
             
           lda #$01                         ; make player store 1  
           sta ply_type                    ; so girl is selected  
             
           rts       


Next diary entry...

Thursday, 25 July 2019

Software Collision Detection

Following on from yesterday, I've decided to move away from using the C64 built-in collision detection almost straight away since I know other routines (such as the energy bar) are working.

The reason the built-in sprite collision detection register ($D01E) isn't used is because it requires a (metric?) tonne more code to work out which sprites are involved in the collision.  This means that I wouldn't have been able to (without wasting time and memory on that extra code) have any of the meanie sprites overlapping without there being issues in detection - they would have had to stay clear of each other to keep things simple and this would limit the game play and level layout somewhat.

Thanks to Jason 'T.M.R.' Kelk for pointing me in the direction of some online GitHub resources which, almost unbelievably, I read and then proceeded to write a software based collision that worked first time.

All that's happening in the detection code is that the x-y coordinates of the main player sprite are grabbed from the sprite table and invisible x-y points are calculated within the sprite and stored in collision variables.  These variables are then tested against the x-y coordinates of the meanie sprites, grabbed from the same sprite table.  When an overlap occurs, there is a virtual 'collision'.

From there, in my code, energy is then taken a away from the player, although I have tweaked the timer so that it's possible to be 'colliding with a meanie for some time without losing too much energy in one go.

Here is the collision code as I finished coding today, which will obviously change quite a bit as new features are added, but for now works fine...

 ; player to enemy sprites subroutine ----------------------------  
   
 ; software based collision detection... no $d01e here!!!  
   
 player_collision  
         lda #$00                 ; set the death flag to 0  
         sta ply_death_flag  
   
         lda sprite_x+$00         ; setup a 'bounding box'  
         sec                      ; around the player sprite  
         sbc #$04                 ; for software collision  
         sta coll_temp+$00        ; detection  
         clc                      ; grab the some x positions  
         adc #$09                 ; for our player sprite which      
         sta coll_temp+$01        ; is sprite 0!      
   
         lda sprite_y+$00         ; and do the same for some y  
         sec                      ; positions of sprite 0  
         sbc #$0a  
         sta coll_temp+$02        ; the x and y positions are  
         clc                      ; stored in the 'coll_temp'  
         adc #$16                 ; labels  
         sta coll_temp+$03  
   
         ldx #$00  
 enem_colls_loop  
         ldy colls_timer          ; first load up the collision timer  
         iny                      ; and increase it by '1'  
         cpy #$08                 ; is the timer equal to '8' yet?  
         bne coll_tmr_skip        ; no? go down to coll_tmr_skip  
                                  ; and skip collision checking  
                                   
         lda sprite_x+$01,x       ; now grab the x postion of each sprite  
         cmp coll_temp+$00        ; from the sprite table  
         bcc enem_colls_skip      ; and check against our 'bounding box'  
         cmp coll_temp+$01        ; coordinates to see if they      
         bcs enem_colls_skip      ; overlap...  
   
         lda sprite_y+$01,x       ; and do the same for the y coordinates  
         cmp coll_temp+$02  
         bcc enem_colls_skip      ; if no coordinates overlap, skip down  
         cmp coll_temp+$03        ; to 'enem_colls_skip'  
         bcs enem_colls_skip  
                                  ; if some coordinates overlap, collision!  
         dec ply_energy           ; decrease the player energy flag by 1  
           
         jsr energy_bar           ; redraw the energy bar  
           
         lda ply_energy           ; is the player out of energy?  
         cmp #$00                 ; yes?  
         beq energy_out           ; skip down to 'energy_out'      
   
 enem_colls_skip  
         inx  
         cpx #$07  
         bne enem_colls_loop      
   
         ldy #$00                 ; load x register with '0'      
 coll_tmr_skip                    ; to reset collision timer and...                  
         sty colls_timer          ; store x register to colls_timer  
           
         rts                      ; go back to main game loop  
               
 energy_out  
         lda #$01                 ; load the player death flag with      
         sta ply_death_flag       ; 1 because all the energy is gone!  
                                  ; then...  
         rts                      ; go back to main game loop where  
                                  ; player will be killed!!!! MWHAAAA!
  

Once compiled and running in WinVICE, it looks a little like this...



Next diary entry...

Wednesday, 24 July 2019

Energy Bar

I've fancied tackling the in-game player energy bar for a while now and have decided to keep it very simple for me to code which may mean inefficient or inelegant, but at this stage, if it works then that's fine by me!

Before tackling the energy bar code though, I needed to code some collision detection so when the player touches a meanie, some energy can be taken away!  As a stop gap measure, I used the C64 built-in sprite hardware collision detection register $D01E, which will be changed in the future for reasons I won't explain right now!

Now a collision between sprites can be detected, it's time to subtract some energy!  The way I've gone about this is to keep the amount of energy stored in a 'variable' which in my code is currently called 'ply_energy' and which is set to '33' or '$21' at the start of the game.  Why such a strange number?  Well the energy bar length represented in blocks at the bottom of the screen after the word energy, is 33 chars wide!  There you go, count the blocks...


Now, being new to C64 coding, I've absolutely no idea if there is a standard way of doing this but my solution to the energy bar has been to set up the colour RAM at the beginning of the level to the red, yellow and green that you can see and which always remains the same, but then replace each block character in the screen RAM with a space character when energy is taken away.

So quite simply, upon the player touching a meanie, the energy in variable 'ply_energy' is subtracted by one, then the whole energy bar is deleted and redrawn to the new value.  This is my delete and redraw the energy bar code:

 ; energy bar drawing subroutine ----------------------------------  
   
 energy_bar  
           ldy #$00              ; update the energy bar!  
           lda #$20  
 clr_energy_loop                 ; clear the row of chars that display the  
           sta $07c7,y           ; energy bar by printing a line of  
           iny                   ; blank spaces!  
           cpy #$21  
           bne clr_energy_loop  
             
           ldy #$00                      
           lda #$40  
 drw_energy_loop                 ; now redraw the energy bar with char $40  
           sta $07c7,y           ; (the block making up the bar)  
           iny                   ; equal to the amount of energy   
           cpy ply_energy        ; remaining  
           bne drw_energy_loop       
             
           rts                   ; go back to wherever this was called from!       


And for now, that'll do because it appears to work just fine and dandy!

Next diary entry...

Saturday, 13 July 2019

More Title Screen

After getting a basic title screen up and running the other day and deciding it needed some extra something or other, I spent some time today adding some colour washing to the text so that there was more colour on the screen.

What the screen dump doesn't show is the text colours "animating" across the screen, left and right.

I had also previously decided it may be quite nice to make the title logo sprites move up and down continuously.


I was quite surprised how easy it was to do the "bounce".  In the mainline title screen loop, I just needed some code that added or subtracted a pixel from each sprites y position and then saved the new position into the sprite table to picked up by the sprite plotter in the interrupt code.

There was an extra table added that kept track of whether the sprite was moving up or down so the code knew whether to move the sprite up/down after checking if each sprite had reached it's top or bottom limit.

Here's the code to do the bounce; it may be possible to refine it in the future, but it works as it stands at the moment!

 ; update title sprites 'y' position to 'bounce' them  
   
           ldx bounce_timer               ; load up the bounce_timer  
           inx                              ; increase it by '1'  
           cpx #$03                         ; is the timer equal to '4' yet?  
           bne bounce_skip               ; no? don't update movement  
                                         ; yes? better do some moving then!  
           ldx #$00  
 t_sprite_y_upd  
           lda t_spr_y_dir,x  
           cmp #$01  
           beq t_sprite_up  
             
           lda sprite_y,x  
           clc  
           adc #$02  
           sta sprite_y,x  
           cmp #$4a  
           bcc t_next_sprite  
           lda #$01  
           sta t_spr_y_dir,x  
           jmp t_next_sprite  
                            
 t_sprite_up  
           lda sprite_y,x  
           sec  
           sbc #$02  
           sta sprite_y,x            
           cmp #$3e  
           bcs t_next_sprite  
           lda #$00  
           sta t_spr_y_dir,x  
           jmp t_next_sprite                 
   
 t_next_sprite  
           inx  
           cpx #$08  
           bne t_sprite_y_upd  
             
           ldx #$00                         ; load x register with '0'  
 bounce_skip                              ; to reset anim_timer and...       
           stx bounce_timer               ; store x register to anim_timer       

I also extracted the text scroller/plotter from "Unused Shmup Tunes" (see previous diary entry) to use on the title screen, so now intro/credit/greeting type text "types" itself on to the screen just above the ground.

As an afterthought, I decided it might be quite nice to have some sprites in the bottom part of the screen, since the screen is already split and therefore it's quite easy to recycle the sprites.  It struck me that it might be cool looking to use the ghost that is already in the sprite bank  and "fly" it across the screen to write and erase the scrolling message.

Again this was quite easy.  When each letter of the message is "plotted" onto the the screen, the ghost moves from left to right by 4 pixels at a time so it appears he is plotting the text.  A cheat really, but visually it works.


Finally, I decided to alter the title screen layout slightly to make more room at the bottom of the screen between "The Boy" and "The Girl" text to include the actual sprites of the boy and girl.  Another afterthought resulted in me making them dance in time to the music (yes, I have been venturing into Goattracker and toying with some sounds).

The decision to dance the sprites did mean a short trip into the sprite editor to adjust the main player sprites to add some dancing frames, but the boy and girl look happy enough having a boogie to an early version of the title screen music now!

Next diary entry...


Wednesday, 10 July 2019

Initial Title Screen

I've decided to work on the title screen today.

That may seem a little odd so early on in the project, but since so much code is needed right at the start to display anything at all (screen set-up and printing, splits and so on) and so much of it will be used for the title and in-game screens, I thought I may as well do it now and have something to show for it.  I'm too impatient!

I first completed a rough layout in my screen editor, 'ChillED'.



I then exported the screen RAM and colour RAM data into the game assembly file. I had previously written some screen display code for another C64 project (Unused Shmup Tunes, see here...), so surgically removed the code and inserted it into Chiller 2.

After a few changes to the layout in ChillED and a further export of data, the title screen ended up being displayed in the game.  Here is a screen dump using WinVICE...

Rather plain at the moment, but I have managed to include some previously pixelled sprites that spell out the game name.  The sprite "plotter" for this resides in split 1 on the screen and was written so that it won't just handle the the title screen sprites, but eventually the in-game sprite player and meanies too!  Double plus good!

I cannot tell a lie - this sprite plotting code was also written for and grabbed from the Unused Shmup Tunes release and since it's my code, it's allowed!  Here is the sprite plotter code for Chiller 2 that handles the x-y position (including MSB) and colour of all 8 sprites, as well as being able to pluck the correct sprite definition from the sprite bank...

 ; in-game sprite plotter!            
             
 sprite_plotter            
           ldx #$00  
           ldy #$00  
 sprite_plot  
           lda sprite_x,x  
           asl  
           ror $d010  
           sta $d000,y  
           lda sprite_y,x  
           sta $d001,y  
           iny  
           iny  
           lda sprite_col,x  
           sta $d027,x  
           lda sprite_def,x  
           sta $07f8,x            
           inx  
           cpx #$08  
           bne sprite_plot  


Now the basic title screen is in place, I fancy adding some colour washes to the text as well as making the logo sprites bounce up and down.  The grassy ground in the screen dump above will eventually have a scrolling message of sorts above it.

Next diary entry...



Tuesday, 9 July 2019

Other Projects

If things have seemed a little quiet on the Chiller 2 front recently, it's because I've been working on other projects!

What?  Why?  Quite simply, I'm still learning 6502 assembler and the best way to learn is by actually doing something.  When doing a longer term project like a game, there are so many other things to do as well, such as design, graphics, sound and so on and as a result you're not coding all the time, which is something I NEED to do to learn!

Just to prove it, here are some links to CSDb that contain two of my recently completed projects from which I can borrow steal code for Chiller 2!

PETSCII Doctors

Unused Shmup Tunes

Going forward, I can now dedicate more time to Chiller 2!

Next diary entry...