Strange Issue With Metatile Collision

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

rlawlor
Posts: 6
Joined: Tue Sep 01, 2020 2:46 am

Strange Issue With Metatile Collision

I just managed to decode metatile level data to display on screen and shortly after tried to write code for collision... but it seems like the collision for a metatile is governed by the top left corner for some reason. The following is my code for checking collision:

Code: Select all

``````CheckCollide:
TXA
STA collideX
LSR
LSR
LSR
LSR                     ; divide x by 16 to get into metatile space
STA tempX
TYA
STA collideY
LSR
LSR
LSR
LSR                     ; divide y by 16 to get into metatile space
ASL
ASL
ASL
ASL                     ; multiply y by 16 to change rows of level table
STA tempY
LDA tempX
ADC tempY               ; X/16 + (Y/16)*16
TAX
LDA (Level1), x         ; load what current metatile you are in
STA currentMetatile

CheckCurrentTile:
LDA collideX
AND #%00001111
LSR
LSR
LSR                     ; divide by 8
STA metatileX           ; find out if player in right or left of metatile

LDA collideY
AND #\$00001111
LSR
LSR
LSR                     ; divide by 8
ASL
ASL                     ; multiply by 4
STA metatileY           ; find out if player in top or bottom of metatile

; 0 0 0 0 0 0 0 0
;         | | | |_ X
;         | | |___ X
;         | |_____ Y
;         |_______ Y

CLC
LDA metatileX
STA metatileCorner      ; calculate what corner the player is in

LDA metatileCorner
AND #%00000101          ; x = 01, y = 01
BEQ +
JMP TopLeft
+
LDA metatileCorner
AND #%00000110          ; x = 10, y = 01
BEQ +
JMP TopRight
+
LDA metatileCorner
AND #%00001001          ; x = 01, y = 10
BEQ +
JMP BottomLeft
+
JMP BottomRight         ; x = 10, y = 10

TopRight:
LDX currentMetatile
LDA (CastleTR), x       ; find out what block type player is on
TAX
LDA (TileProperties), x
AND #%00000001          ; only check tile collision

RTS

TopLeft:
LDX currentMetatile
LDA (CastleTL), x       ; find out what block type player is on
TAX
LDA (TileProperties), x
AND #%00000001          ; only check tile collision

RTS

BottomRight:
LDX currentMetatile
LDA (CastleBR), x       ; find out what block type player is on
TAX
LDA (TileProperties), x
AND #%00000001          ; only check tile collision

RTS

BottomLeft:
LDX currentMetatile
LDA (CastleBL), x       ; find out what block type player is on
TAX
LDA (TileProperties), x
AND %00000001          ; only check tile collision

RTS
``````
and this is the TileProperties and metatile tables (only collision is being used as a property currently, the others are purely examples I may use in future):

Code: Select all

``````;===================================Meta Tiles===============================================

CastleTL: .db \$00, \$00, \$00, \$00, \$07, \$07, \$07, \$07
CastleTR: .db \$00, \$07, \$07, \$00, \$07, \$07, \$07, \$07
CastleBL: .db \$00, \$00, \$00, \$07, \$00, \$07, \$07, \$07
CastleBR: .db \$00, \$07, \$00, \$07, \$00, \$07, \$07, \$07

;==================================Tile Properties===========================================

;0 0 0 0 0 0 0 0
;| | | | | | | |_ Collidable
;| | | | | | |___ One Way Platform
;| | | | | |_____ Ladder
;| | | | |_______ Kills
;| | | |_________ Slippery
;| | |___________ ?
;| |_____________ ?
;|_______________ ?

TileProperties:
.db %00000001, %00000000, %00000100, %00000000      ; \$00 to \$1F
.db %00000000, %00000000, %00000000, %00000000
.db %00000000, %00000000, %00000000, %00000000
.db %00000000, %00000000, %00000000, %00000000
.db %00000000, %00000000, %00000000, %00000000
.db %00000000, %00000000, %00000000, %00000000
.db %00000000, %00000000, %00000000, %00000000
.db %00000000, %00000000, %00000000, %00000000
etc. etc.
``````

rlawlor
Posts: 6
Joined: Tue Sep 01, 2020 2:46 am

Re: Strange Issue With Metatile Collision

The following is an example of a way in which CheckCollide would be called just for some sort of context:

Code: Select all

``````MovePlayer1Right:
LDA #%00000000
STA \$206
LDA p1XVelocityL            ; load lower byte of x velocity
CLC                         ; clear carry flag
STA tempL                   ; store in a temporary variable
LDA p1XVelocityH            ; load high byte of x velocity
STA tempH                   ; store in a temporary variable

LDA tempL                   ; load temporary variable
CMP #maxXVelocityL          ; compare with max allowed velocity
LDA tempH                   ; load temporary variable
SBC #maxXVelocityH          ; subtract max allowed velocity

BVC +                       ; branch on overflow clear
EOR #\$80                    ; exclusive or with %1000000
+
BMI NotMaxVRight            ; branch on result minus
LDA #maxXVelocityL          ; load max x velocity (low) into accumulator
LDX #maxXVelocityH          ; load max x velocity (high) into x register
JMP MaxVRight

NotMaxVRight:
LDA tempL                   ; set temp variable to max allowed velocity
LDX tempH

MaxVRight:
STA p1XVelocityL            ; store new velocity
STX p1XVelocityH

LDA player1XF               ; load player 1 fractional x coordinates
CLC                         ; clear carry
STA player1XF               ; update player coordinates

LDA player1XI
STA player1XI

LDA player1YPos             ; load player 1 y location
CLC
TAY
LDA player1XI               ; load player 1 x location
CLC
TAX
JSR CheckCollide
BEQ +
CLC                         ; clear carry
LDA player1XF               ; load player 1 fractional coordinates
SBC p1XVelocityL            ; subtract velocity
STA player1XF               ; update coordinates
LDA player1XI               ; load player 1 integer coordinates
SBC p1XVelocityH            ; subtract velocity
STA player1XI               ; update coordinates
LDA #\$00
STA p1XVelocityL
LDA #\$00
STA p1XVelocityH
+
LDA player1YPos
CLC
TAY
LDA player1XI
CLC
TAX
JSR CheckCollide
BEQ +
CLC                         ; clear carry
LDA player1XF               ; load player 1 fractional coordinates
SBC p1XVelocityL            ; subtract velocity
STA player1XF               ; update coordinates
LDA player1XI               ; load player 1 integer coordinates
SBC p1XVelocityH            ; subtract velocity
STA player1XI               ; update coordinates
LDA #\$00
STA p1XVelocityL
LDA #\$00
STA p1XVelocityH
+

RTS
``````

dougeff
Posts: 2735
Joined: Fri May 08, 2015 7:17 pm
Location: DIGDUG
Contact:

Re: Strange Issue With Metatile Collision

lsr x4
asl x4

Don't do that. Just use
and #\$f0

Code: Select all

``LDA (Level1), x``
There is no such opcode. Indirect like this is always with the Y register.

LDA (Level1), y

The assembler is probably silently converting your code to this LDA Level1, x
nesdoug.com -- blog/tutorial on programming for the NES

rlawlor
Posts: 6
Joined: Tue Sep 01, 2020 2:46 am

Re: Strange Issue With Metatile Collision

lsr x4
asl x4

Don't do that. Just use
and #\$f0
Thanks for the tip, certainly saves a lot of code! As for the "LDA (something), x" not being an opcode I had no idea. I changed it there and I'm still getting a similar problem so I'm not sure why it was working in the same way with x. Thanks for the help .

Drag
Posts: 1322
Joined: Mon Sep 27, 2004 2:57 pm
Contact:

Re: Strange Issue With Metatile Collision

You're using lda (nn), Y (Indirect Y addressing) but I think you actually want lda nnnn, Y (Absolute Y addressing).

lda (\$08), Y means, "I've written a 16-bit address in RAM at \$08 and \$09, take the address I wrote there, add Y to it, that's the byte I want to fetch."

lda \$9040, Y means, "Fetch the byte at (\$9040 + Y)", and you can use either Y or X.

The next thing to note is with this chunk of code:

Code: Select all

``````    LDA collideX
AND #%00001111
LSR
LSR
LSR                     ; divide by 8
STA metatileX           ; find out if player in right or left of metatile``````
That final LSR will shift bit 2 of collideX into carry, which is going to affect the ADC. From the looks of the following code, this looks unintentional. You can drop a CLC there if you want, but a shortcut you can use is to change your AND mask from #%00001111 to #%00001000. (Can you guess why?)

----------
For posterity, Indirect X addressing is: lda (\$08, X) = "Starting at RAM addresses \$08-\$09, I've written several 16-bit addresses, one at \$08-\$09, one at \$0A-\$0B, etc. Look at memory address (\$08 + X), the 16-bit address I've written there is the address I want to fetch from"

So, for example, if the memory starting at \$08 looks like "40 90 B8 90 D0 90", and you do lda (\$08,X) with X set to 4, you will fetch a byte at \$90D0.

It's funny that, when you do indirect addressing, the behavior is different depending on whether you're using X or Y as your index, but that's how it goes.

rlawlor
Posts: 6
Joined: Tue Sep 01, 2020 2:46 am

Re: Strange Issue With Metatile Collision

You're using lda (nn), Y (Indirect Y addressing) but I think you actually want lda nnnn, Y (Absolute Y addressing).
Spot on . Didn't realise there were multiple types of addressing.
That's something I never would've thought to do, thanks.

I've made all the changes suggested but it seems I'm still getting the same problem. I know my code for finding what metatile the player is in works so it could be that the rest of my code just needs rewritten in some form or another. Originally I was using RLE compression and a collision bitmask but very quickly realised how much storage space that would take up with a scrolling game hence the change to metatiles. Its nice being able to specify properties for each tile in a table and call it whenever you need to check something (or at least it will be when I get it working properly ).

rlawlor
Posts: 6
Joined: Tue Sep 01, 2020 2:46 am

Re: Strange Issue With Metatile Collision

I know my code for finding what metatile the player is in works
Famous last words... I disabled collision and did a quick check and it seems it thinks each metatile is one normal tile to the left of where it actually is (i.e. 8 pixels to the left of where it is on screen). So time to take a look through that code .

dougeff
Posts: 2735
Joined: Fri May 08, 2015 7:17 pm
Location: DIGDUG
Contact:

Re: Strange Issue With Metatile Collision

You could just add 8 before doing the calculations.
nesdoug.com -- blog/tutorial on programming for the NES

rlawlor
Posts: 6
Joined: Tue Sep 01, 2020 2:46 am

Re: Strange Issue With Metatile Collision

Turns out I was using LSR before ADC and so I had a carry in my calculations .