Scrolling Platformer seam collision fix [4.5.9]

TakuikaNinja

Active member
The infamous seam collision bug in the scrolling platformer modules (L2R, MetroVania) has finally been fixed by yours truly!
It turns out that Joe had actually fixed this issue during the 4.5 bootcamp, but forgot to implement it when upgrading the physics for 4.5.9.
Thanks to derexgar for providing a backup of the code to reference!

How to fix the bug: Assign the attached script to "Handle Physics" in the script settings instead of the default one.

Let me know if you run into any issues I might have missed.

EDIT: I've noticed there's an edge case that can be triggered by using large values for the scroll pad constants or through abusing bugs in the scroll stop code. As far as I can tell, one of the contributors to this is a flaw with how NESmaker loads collision tables in the scrolling engine. Keep the scroll pad values below $74 and it shouldn't cause any issues. (Gosh, I hate how jank this engine is)
 

Attachments

  • doHandlePhysics_PlatformBase_SeamFix.zip
    4.1 KB · Views: 165
Last edited:

TakuikaNinja

Active member
The gist of the changes:
  • For the left collision point, save the collision table number (tempB in this instance).
  • For the right collision point, get the collision table number as well (this is saved to tempA). <- this fixes the seam issue
  • Check the left point's collision using tempB.
  • Only check the right point's collision using tempA if the left point did not detect a solid tile. <- this fixes the seam issue + removes redundant collision checks
  • If the tile is solid, check the specific tile & do the necessary actions.
  • For the ladder tiles, change the arguments for GetCollisionPoint depending on which side it's checking. <- this fixes the seam issue
Here is a code comparison between line 479 (a couple of lines after the "doneWithH" label) and the "isOneWaySolid" label.
Original (BASE_4_5\Game\MOD_PlatformerBase\Subroutines\doHandlePhysics_PlatformBase.asm):
Code:
    LDA Object_x_hi,x
    CLC
    ADC self_left
    STA temp
        JSR getPointColTable
    LDA Object_x_hi,x
    CLC
    ADC self_right
    STA temp3 ;; the right bottom collision point.
    LDA Object_y_lo,x
    CLC
    ADC Object_v_speed_lo,x
    LDA Object_y_hi,x
    ADC Object_v_speed_hi,x
    CLC
    ADC self_bottom
    STA temp1
    ;;; CHECK FOR SOLID TILE, which is tile type 1 in this module.
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;;;; In this module, we have
        ;; 1 = solid
        ;; 7 = one way platform
        ;; 9 = prize block, which behaves as a solid
        ;; 10 (0A) = ladder, whose top behaves like a solid.
        ;; Here is where we handle the "landing" scenario for all of those possibilities.
        
        
    GetCollisionPoint temp, temp1, tempA ;; is it a solid?
        CMP #$01
        BNE +isNotSolid
            JMP +isSolid
        +isNotSolid
        CMP #$07
        BNE +isNotOneWaySolid
            JMP +isOneWaySolid
        +isNotOneWaySolid
        CMP #$09
        BNE +isNotSolid
            JMP +isSolid
        +isNotSolid
        CMP #$0A
        BEQ +isLadderSolid
        
    GetCollisionPoint temp3, temp1, tempA ;; is it a solid?
        CMP #$01
        BNE +isNotSolid
            JMP +isSolid
        +isNotSolid
        CMP #$07
        BNE +isNotSolid
            JMP +isOneWaySolid
        +isNotSolid
        CMP #$09
        BNE +isNotSolid
            JMP +isSolid
        +isNotSolid
        CMP #$0A
        BEQ +isLadderSolid
            JMP +notSolid
            
    +isLadderSolid
        LDA Object_v_speed_hi,x
        BEQ +checkSolid
        BPL +checkSolid
            JMP +notSolid
        +checkSolid
        LDA temp1
        SEC
        SBC #$02
        SEC
        SBC Object_v_speed_hi,x
        STA tempy
        GetCollisionPoint temp, tempy, tempA ;; is it a solid
            BEQ +checkForSecondPoint
            CMP #$0A
            BEQ +notSolid
        GetCollisionPoint temp3, tempy, tempA ;; is it a solid?   
            BEQ +checkForFirstPoint
            CMP #$0A
            BEQ +notSolid
            JMP +isSolid
                +checkForSecondPoint
                    GetCollisionPoint temp3, tempy, tempA ;; is it a solid?
                    BEQ +isSolid
                    JMP +notSolid
                +checkForFirstPoint
                    GetCollisionPoint temp, tempy, tempA ;; is it a solid?
                    BEQ +isSolid
                    JMP +notSolid

Fixed:
Code:
    LDA Object_x_hi,x
    CLC
    ADC self_left
    STA temp
        JSR getPointColTable
    STA tempB
    LDA Object_x_hi,x
    CLC
    ADC self_right
    STA temp3 ;; the right bottom collision point.
        JSR getPointColTable
    LDA Object_y_lo,x
    CLC
    ADC Object_v_speed_lo,x
    LDA Object_y_hi,x
    ADC Object_v_speed_hi,x
    CLC
    ADC self_bottom
    STA temp1
    ;;; CHECK FOR SOLID TILE, which is tile type 1 in this module.
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;;;; In this module, we have
        ;; 1 = solid
        ;; 7 = one way platform
        ;; 9 = prize block, which behaves as a solid
        ;; 10 (0A) = ladder, whose top behaves like a solid.
        ;; Here is where we handle the "landing" scenario for all of those possibilities.
        
        
    GetCollisionPoint temp, temp1, tempB ;; is it a solid?
        BNE +check
        
    GetCollisionPoint temp3, temp1, tempA ;; is it a solid?
        +check
        CMP #$01
        BNE +isNotSolid
            JMP +isSolid
        +isNotSolid
        CMP #$07
        BNE +isNotSolid
            JMP +isOneWaySolid
        +isNotSolid
        CMP #$09
        BNE +isNotSolid
            JMP +isSolid
        +isNotSolid
        CMP #$0A
        BEQ +isLadderSolid
            JMP +notSolid
            
    +isLadderSolid
        LDA Object_v_speed_hi,x
        BEQ +checkSolid
        BPL +checkSolid
            JMP +notSolid
        +checkSolid
        LDA temp1
        SEC
        SBC #$02
        SEC
        SBC Object_v_speed_hi,x
        STA tempy
        GetCollisionPoint temp, tempy, tempB ;; is it a solid
            BEQ +checkForSecondPoint
            CMP #$0A
            BEQ +notSolid
        GetCollisionPoint temp3, tempy, tempA ;; is it a solid?   
            BEQ +checkForFirstPoint
            CMP #$0A
            BEQ +notSolid
            JMP +isSolid
                +checkForSecondPoint
                    GetCollisionPoint temp3, tempy, tempA ;; is it a solid?
                    BEQ +isSolid
                    JMP +notSolid
                +checkForFirstPoint
                    GetCollisionPoint temp, tempy, tempB ;; is it a solid?
                    BEQ +isSolid
                    JMP +notSolid
 

vanderblade

Active member
Thanks! I had already changed my game design to avoid this issue, but I implemented your changes anyway, and it seems to work fine.
 

latetera

Member
@WhatDothLife On your main NesMaker window locate the gear icon, that's "project settings". There you have to go to "Script Settings" tab and then all the way down to "SubRoutines". There you have to find "doHandlePhysics_PlatformBase.asm" and hit "Change".
Is good idea to put the new .asm file in same folder of the old one :)
Thanks @TakuikaNinja for this fix < 3
 

WhatDothLife

New member
@WhatDothLife On your main NesMaker window locate the gear icon, that's "project settings". There you have to go to "Script Settings" tab and then all the way down to "SubRoutines". There you have to find "doHandlePhysics_PlatformBase.asm" and hit "Change".
Is good idea to put the new .asm file in same folder of the old one :)
Thanks @TakuikaNinja for this fix < 3
It worked. No more invisible platforms.
 

Jonny

Well-known member
:( I've been wondering why I'm still getting phantom solid tiles but then realized my scroll pad values are over $74 to keep player in the middle. Guess I'll have to rethink that.

@TakuikaNinja what is meant by abusing bugs?

Edit: Reduced padding to 70, still getting seam collision bug. My player character is 16px x 32px tall if that makes any difference?
 
Last edited:

Jonny

Well-known member
Is this the standard stopScroll code...? or, in other words what should be used with this fix?
Code:
LDA scrollByte
AND #%00001111
STA scrollByte
RTS
So strange, my first attempt was just making the changes needed as shown above. I've just tried using the entire fixed physics script instead and I can't get that to work either. I wish I could think of what is different in my project that would cause this. Has nobody else had any problems?
 
Last edited:

TakuikaNinja

Active member
@Jonny you can repeatedly tap a direction to move the player beyond the scroll pad, breaking the camera & collision system.
Unfortunately, the fix I shared ages ago seems to break the "scroll with centering" scripts.
 

TakuikaNinja

Active member
The bounding box could still be causing edge cases, too.
Like I mentioned in my latest profile update, I no longer want to look at the codebase because of how messy/janky it is.
 

Jonny

Well-known member
@Jonny you can repeatedly tap a direction to move the player beyond the scroll pad, breaking the camera & collision system.
Unfortunately, the fix I shared ages ago seems to break the "scroll with centering" scripts.
I'm using your fix for tapping left and right but not centering. It works in that player can not land on the tiles but still stops them left and right. Sorry I didn't see the profile update but I can understand that, thank you anyway. I'll do some testing with bounding box.
 

Jonny

Well-known member
Got it @TakuikaNinja ! thank you It was indeed the bounding box. If I have it set any less than the full 16px width of the player object the fix doesn't work. I need it to be less so I'll have to figure out some way to compensate for that. Surprised nobody else has come across this, I can't be the only person using the fix with a smaller width bounding box for player.

Edit: Just realized, for that latest test, I still had non-fixed script assigned. With fixed code I can have bounding box 14px but no less.
 
Last edited:
Top Bottom