I still need to calculate coordinate locations for crosses on many levels and seem to be putting this off at the moment, mainly down to the fact I find it rather boring...
However, I'm putting this task off by actually tweaking and/or adding code to other sections! Honest!
The girl finally became 'properly' selectable/playable the other day and until now has shared characteristics with the boy. But no longer! I've altered certain variables so that when the girl or boy are selected they handle slightly differently.
The boy is slightly 'stronger' than the girl - he can be in contact with enemies or dangerous parts of the scenery for just a few milliseconds longer before experiencing an energy drain.
The girl is slightly 'lighter' than the boy - although she can jump no higher, she can stay in the air just a few milliseconds longer than the boy, making it a tiny bit easier to successfully make the longer jumps between platforms on some levels.
Those differences above are only subtle, but does give the player some choice as to how to play - do you choose easier jumps or more strength? No doubt the variables will be altered further once play testers get their hands on the game and maul my efforts to death, but it will be easy for me to change in the code now since it's all handled by a couple of labels.
I've also finally got round to moving my screen splits slightly to accommodate the fact that on two of the levels (Level 3 - The Apartments and Level 7 - The Park, if you're interested!) I've used a blue background.
I wanted to 'extend' the blue sky background into the upper border, an easy task since the top border is open, but not-to-hot looking because the split was in the wrong place, therefore the blue colour 'bled' too far down the screen. Also, the blue was appearing on levels where the background and top border should have been black.
It was simple fix in the end - the two levels needing a blue top border set a flag telling my top border split to colour itself blue, otherwise colour itself black. The result on Level 3 looks like this...
Next diary entry...
Showing posts with label collision. Show all posts
Showing posts with label collision. Show all posts
Wednesday, 4 March 2020
Tuesday, 25 February 2020
Dangerous Scenery
Another piece of the gameplay puzzle has finally fallen into place!
It's not really been necessary to do it until now since some gameplay mechanics just get in the way of testing and debugging, but I have now coded the, er, code that detects 'dangerous' scenery around the player and drains energy if touched. The main 'obstacles' in the various levels are mushrooms and pools of green slime and if they are walked upon, energy is subtracted.
I've tried to be fair however; the detection is quite 'loose' and you can jump up near or through such scenery without being penalised, with the energy drain only occurring if the player directly walks on such scenery. However, on some levels the mushrooms may be 'reversed' chars and appear only as silhouettes amongst other scenery; they can be quite difficult to spot in the heat of the action and will probably annoy those who go charging around without stopping, looking and thinking!
Here's how it looks in action (the animation below also showcases the first outing of the girl player, who is now selectable from the title screen!):
The scenery collision detection reuses values calculated from the gravity subroutine so checks what is underneath the players feet. There is a bit of a cheat going on - the subroutine is not checking the mushrooms directly, but 'special' chars underneath the mushrooms that trigger the collision!
Next diary entry coming soon...
It's not really been necessary to do it until now since some gameplay mechanics just get in the way of testing and debugging, but I have now coded the, er, code that detects 'dangerous' scenery around the player and drains energy if touched. The main 'obstacles' in the various levels are mushrooms and pools of green slime and if they are walked upon, energy is subtracted.
I've tried to be fair however; the detection is quite 'loose' and you can jump up near or through such scenery without being penalised, with the energy drain only occurring if the player directly walks on such scenery. However, on some levels the mushrooms may be 'reversed' chars and appear only as silhouettes amongst other scenery; they can be quite difficult to spot in the heat of the action and will probably annoy those who go charging around without stopping, looking and thinking!
Here's how it looks in action (the animation below also showcases the first outing of the girl player, who is now selectable from the title screen!):
The scenery collision detection reuses values calculated from the gravity subroutine so checks what is underneath the players feet. There is a bit of a cheat going on - the subroutine is not checking the mushrooms directly, but 'special' chars underneath the mushrooms that trigger the collision!
Next diary entry coming soon...
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.
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!
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...
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...
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...
Once compiled and running in WinVICE, it looks a little like this...
Next diary entry...
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:
And for now, that'll do because it appears to work just fine and dandy!
Next diary entry...
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...
Subscribe to:
Posts (Atom)



