Enemies falling off ledges on the left side cause player to die in platformer

Snuckey

New member
This only seems to happen on screens OTHER than the initial screen. If I create a first screen in the scrolling platformer that has a drop on the left side, if enemies fall off the left edge they correctly are destroyed. If I scroll to the right a screen and an enemy walks and falls off a ledge on the left side of screen 2 then the player loses a life and starts over, even though the enemy did not hit them.

Has anyone run into this before? It's been driving me crazy for a couple of hours and I haven't been able to find any similar threads on the forum. Any ideas appreciated!
 

Jonny

Well-known member
Have you watched the tutorials where Joe talks about the 'deadzone' and where placing monsters on first 2 screens can cause problems?

Platformer Basic (Deadzone) - Mentioned at about 15:00

Maybe this could have something to do with your problem? It's explained in more detail in the intermediate and advanced tutorials but In short, placing monsters there can cause more issues than just not showing the monster. If you think this could be why, try replicating the same setup on screen 3 and onwards to see if you get the same results.
 

Snuckey

New member
That was a good call out, I tried putting enemies on the third screen but it still happened. For what it's worth, it seems to only happen if enemies fall off a ledge on the left half of the screen. If they fall on the right half of the screen they just fall and are destroyed normally.
 

Jonny

Well-known member
Did you check if the position of the player makes any difference i.e if player is on left or right side of the monster when it falls on the left?
 

Snuckey

New member
Looking a little more closely, I think it's not when enemies fall. It appears to be when enemies move the edge of a screen AND are to the left of the player. No matter where you are scrolled to, if they walk to where a screen boundary is and they're on the player's left the player loses a life and starts at the beginning again.
 

Snuckey

New member
Works.png
Here is a picture of something that doesn't cause a problem. I've drawn a red line on the picture where the boundary between two screens are. If the player stands there then the penguin falls into the hole and the game keeps going.

If instead I jump over the hole and penguin, as soon as the penguin touches the spot where I've drawn the red line the player loses a life and starts at the beginning.
 

Snuckey

New member
More info: you can repro this if you run the Platformer tutorial project and let any of the snails walk to a screen boundary (I removed one of the solid blocks on screen 3 so that the snails weren't stuck in their pen).

UPDATE:

I'm pretty new to assembly code, but the bug appears to be hurtPlayer_PlatformBase.asm, specifically lines 14 and 15:

LDA Object_v_speed_hi,x
BEQ +doHurtPlayer ;; equal to zero

For some reason, the BEQ check is true which jumps to the doHurtPlayer section of code, killing the player. Honestly, I'm not sure why this code is getting called at all since there's nothing that would obviously trigger the hurtPlayer script going on in the game.
 
Last edited:

TakuikaNinja

Active member
It seems like the player hurt routine is called when the high byte of the vertical speed of a certain object (determined by X) is equal to zero.
What gets put into X before that?

Edit: I think I get it now. This check is there so that the player would stomp the enemy if the enemy is below them and the player is moving downwards.
The branch conditions on lines 15 & 16 need to be reversed for this to work properly, though.
Here's what lines 14 to 17 should look like:
Code:
LDA Object_v_speed_hi,x
BNE +doHurtPlayer ;; not equal to zero
BPL +doHurtPlayer ;; or positive
;; here we are moving downward.
 
Last edited:

Snuckey

New member
I think the bounding box comparison in doCompareBoundingBoxes_multiscreen.asm is off when the enemy is at a screen boundary. I'm not sure *exactly* what the bug is, but I think it is in the part that is calculating getOtherColBox:

LDA other_left
CLC
ADC ObjectWidth,y
STA other_right
LDA Object_screen,x
ADC #$00
STA other_screen_right

The red text is trying to store what screen the right side of the enemy is on, which is then causing it to fall into this case when comparing bounding boxes in the same file:

+theseAreEqual
;;; we need to check the *other* side
LDA self_screen_left
CMP other_screen_right
BEQ +normalBoundsCheck
;; this means bounds are being straddled.
LDA bounds_right
CMP other_left
BCC +noBboxCollision
JMP +hCol
 

TakuikaNinja

Active member
Which version of nesmaker are you using? I don't see that JMP line in the file.
It would be redundant anyway since the +hCol label is right after that block.
 

Snuckey

New member
NES MAKER 4.5.9

Here's my entire doCompareBoundingBoxes_multiScreen.asm file. I don't believe I've edited it at all:

;;;
doCompareBoundingBoxes:
;;; more complicated than this
; LDA self_screen
; CMP other_screen
; BNE noBboxCollision


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Here we will check the horizontal collision.
;;; First we need to check the RIGHT SCREEN + RIGHT BBOX of self against the
;;; LEFT SCREEN + LEFT BBOX of other. If it is less, then there is no collision.
LDA self_screen_right
CMP other_screen_left
BEQ +theseAreEqual
;;; the self screen and other screen are not equal.
;;; But if the self screen is MORE than the other screen,
;;; it is still possible that this could return a collision.
JMP +checkOtherSide

+theseAreEqual
;;; we need to check the *other* side
LDA self_screen_left
CMP other_screen_right
BEQ +normalBoundsCheck
;; this means bounds are being straddled.
LDA bounds_right
CMP other_left
BCC +noBboxCollision
JMP +hCol
+normalBoundsCheck

;; the self screen and other screen are equal
;; which means now it is a matter of checking the
;; self right bbox against the left bbox.
LDA bounds_right
CMP other_left
BCC +noBboxCollision


+continueCollisionCheck
+checkOtherSide
LDA self_screen_left
CMP other_screen_right
BEQ +theseAreEqual
JMP +noBboxCollision
+theseAreEqual
;;; check the *other* side
LDA self_screen_right
CMP other_screen_left
BEQ +normalBoundsCheck

+normalBoundsCheck
LDA bounds_left
CMP other_right
BCS +noBboxCollision

+hCol
LDA other_bottom
CMP bounds_top
BCC noBboxCollision
LDA bounds_bottom
CMP other_top
BCC noBboxCollision
;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;



LDA #$01 ;; read that YES, there was a collision here. (could make this the object ID)
RTS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
noBboxCollision;; there is no collision here horizontally.
LDA #$00 ;; read that NO, there was no collision.
RTS


getOtherColBox:
TYA
PHA
; LDA Object_x_hi,x
; CLC
; ADC #$10
; LDA Object_screen,x
; ADC #$00
; STA other_screen_right
LDY Object_type,x

LDA Object_x_hi,x
CLC
ADC ObjectBboxLeft,y
STA other_left
LDA Object_screen,x
ADC #$00
STA other_screen_left

LDA other_left
CLC
ADC ObjectWidth,y
STA other_right
LDA Object_screen,x
ADC #$00
STA other_screen_right


LDA other_right
SEC
SBC other_left
LSR
STA other_center_x

LDA ObjectBboxTop,y
CLC
ADC Object_y_hi,x
STA other_top
CLC
ADC ObjectHeight,y
STA other_bottom
SEC
SBC other_top
LSR
STA other_center_y ;; self center in the vertical direction.
; LDA Object_screen,x
; STA other_screen

PLA
TAY
RTS
 

TakuikaNinja

Active member
I have a guess on what's going on.
When the enemy's bounding box straddles along the screen boundary, the position of one side of the box over/underflows in such a way that the hitbox spans an entire row of the screen.
Screen boundaries are notorious for causing issues in the codebase - tile collisions & object unloading, just to name a few.
 

Jonny

Well-known member
I have a guess on what's going on.
When the enemy's bounding box straddles along the screen boundary, the position of one side of the box over/underflows in such a way that the hitbox spans an entire row of the screen.
Screen boundaries are notorious for causing issues in the codebase - tile collisions & object unloading, just to name a few.
I did some testing and this seems to be exactly what's happening. I have a monster which moves from right to left. When the monster touches the left screen edge, player gets hurt.
 

CluckFox

Active member
Setting the monster's Edge Object Reaction to Destroy Me will prevent the unwanted player harm. It doesn't solve the underlying quirk, but for a one-way scroller it should keep the quirk out of your way most of the time.
1616556845088.png
 

Snuckey

New member
Unfortunately, setting "Edge Object Reaction" to "Destroy Me" doesn't fix this, when I set it on my enemy the same issue happens: enemy moves to where the "seam" between two screens are and kills the player. TakuikaNinja's guess does seem correct, if I jump right when the enemy moves onto the seam the player does not die.
 

CluckFox

Active member
Unfortunately, setting "Edge Object Reaction" to "Destroy Me" doesn't fix this, when I set it on my enemy the same issue happens: enemy moves to where the "seam" between two screens are and kills the player. TakuikaNinja's guess does seem correct, if I jump right when the enemy moves onto the seam the player does not die.
I am not able to reproduce the behavior when the Destroy Me reaction is set on a new Scrolling Platformer module project. I'm attempting to debug the collision script now to see if there's a simple way to prevent the bounding box wrap-around @TakuikaNinja observed.
 

Snuckey

New member
@CluckFox That's really weird since it reproes for me in both my project and the tutorial project (from the end of the full expert tutorial). I'm *very* new to this tool and 6502 assembly though, so very possibly I've messed up somewhere.
 

CluckFox

Active member
Same here, I've only been working with NESMaker and 6502 for a couple of months. I have plenty of time today though to sit down with a debugger and nail down the hitbox wrap-around as it happens.
 

Jonny

Well-known member
Unfortunately, setting "Edge Object Reaction" to "Destroy Me" doesn't fix this, when I set it on my enemy the same issue happens: enemy moves to where the "seam" between two screens are and kills the player. TakuikaNinja's guess does seem correct, if I jump right when the enemy moves onto the seam the player does not die.
I did some testing too and yeah, the edge object reaction and solid object reaction don't make a difference. My player still took damage when the monster hit the screens left edge before being destroyed. I only noticed this when @Snuckey mentioned it. I guess I'd been lucky in my monster and monster solid tile placement choices!
 

CluckFox

Active member
I'm starting from the Beginner Scrolling Platformer, which is the only difference I can see regarding the edge-reaction.

Regardless of the edge-reaction behavior, doCompareBoundingBoxes_multiScreen.asm is where I'm looking right now. I got the debugger to stop inside that script only when the monster wanders off the edge.
 
Top Bottom