Need some help and advice with my collision detection

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

SNgamer
Posts: 44
Joined: Tue Feb 11, 2014 7:12 am

Need some help and advice with my collision detection

Post by SNgamer » Fri Sep 12, 2014 9:50 am

I have programmed a bit on the NES and it seems to be a fun project to create a game from scratch, so i tried to program a little platformer with my own collision detection scheme (i have not looked at how other games do the detection, it might totally differ from how it would normally be done).
I have created a file which holds my level data as a nametable, and it is also used in order to detect any collision. for the moment i have only programmed when a sprite hits ground, it should stop falling. it does work as intended, i can let the sprite fall from any position to any ground on any hight, it would stop the sprite as soon as it detects the ground (actually it checks if the sprite is in empty space and lets it fall down as long as empty space is detected).
My problem is that my sprite is 4 pixels deep in the ground in any situation, and i can not tell why that is.
i hope someone can look into my code and tell what the issue is. the file is for asm6

thanks in advance

a bit further explanation on my program:
every nmi the sprite is moved to the right and an animation routine is executed, so there is an actual animation.
i later will also implement controller button detection.
the main routine checks for the tile 8 pixels (1 tile) below the lower sprite tile(feet) and checks if it is air (empty tile #$07), if so, it will set a flag to tell another routine to execute (which is within NMI), which will then lower the sprites by one pixel.
this is executed until the tile below the lower sprite is something else than #$07. if this is the case, no flag will be set and therefore there is no fall routine executed in NMI.
if further explanation is needed, i can give more.
Attachments
chr.chr
(8 KiB) Downloaded 119 times
level.asm
(2.22 KiB) Downloaded 122 times
collision.asm
main file to be assembled in asm6
(4.68 KiB) Downloaded 124 times

User avatar
tokumaru
Posts: 11744
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Need some help and advice with my collision detection

Post by tokumaru » Fri Sep 12, 2014 10:24 am

SNgamer wrote:My problem is that my sprite is 4 pixels deep in the ground in any situation, and i can not tell why that is.
Without looking at the code (I'm at work now, so I don't have much time), I'd probably blame the speed at which your sprite falls. If it moves at more than 1 pixel per frame, the likelihood of it sinking into the ground is high, and unless you "eject" it back up to a valid position, it will remain that way.

Collision detection doesn't usually work by checking if the movement is allowed and then moving the objects, instead it just moves the objects anyway, assuming every movement is possible, and then ejects the objects in case they ended up going into something solid. Ejecting is easy if you don't have slopes and your basic collision unit is a tile or metatile of constant dimensions, because it's all neatly aligned to a grid.

Since we're talking about gravity specifically, objects often have a flag indicating whether they are on the ground or not. That stops you from constantly pushing objects down when you should be concentrating on horizontal movement (why push objects down and eject them back every single frame, wasting CPU time and possibly making horizontal movement harder?). So if you know your object is falling, you'll keep moving it down by an amount of pixels compatible with its vertical velocity (which might change dynamically depending on how elaborate your physics are) and checking its lowest point (by the feet) against the map (or name table) to see if it's inside a solid block. If it is, you use the block's coordinates to calculate the last allowed coordinate for the sprite's feet. After you find it, check the difference between that and the invalid position and move the whole sprite up by this many pixels.

SNgamer
Posts: 44
Joined: Tue Feb 11, 2014 7:12 am

Re: Need some help and advice with my collision detection

Post by SNgamer » Fri Sep 12, 2014 1:52 pm

sadly, it is not the falling velocity, which causes the problem (it is 1pixel/frame).
i think i will probably rewrite the collision detection to what you described, because this sounds most convenient to implement.
nevertheless, i would like to know what was wrong with my way of handling detection out of interest.

3gengames
Formerly 65024U
Posts: 2276
Joined: Sat Mar 27, 2010 12:57 pm

Re: Need some help and advice with my collision detection

Post by 3gengames » Fri Sep 12, 2014 2:10 pm

Post some of the code if you can, just try to comment it. We're not psychic, I haven't looked at code for a bit so I'd be interested in helping, but I don't have a dev setup ATM.

SNgamer
Posts: 44
Joined: Tue Feb 11, 2014 7:12 am

Re: Need some help and advice with my collision detection

Post by SNgamer » Fri Sep 12, 2014 2:24 pm

Here is the code for anyone whose device is not able to display asm files properly. Just tell me where explanation is needed and i will explain, as i did not really comment on all the code.

Code: Select all

;--------------------------------------------
; constants
;--------------------------------------------

PRG_COUNT = 1 ;1 = 16KB, 2 = 32KB
MIRRORING = %0001 ;%0000 = horizontal, %0001 = vertical, %1000 = four-screen

;--------------------------------------------
; variables
;--------------------------------------------

.enum $0000
count .dsb 1
xpos .dsb 1
ypos .dsb 1
yadd .dsb 1;this will be used to determine the exact position of the tile by adding #$20 to X register
fall_f .dsb 1;a flag to let the nmi know that the sprite is supposed to fall down

.ende

;--------------------------------------------
; iNES header
;--------------------------------------------

.db "NES", $1a ;identification of the iNES header
.db PRG_COUNT ;number of 16KB PRG-ROM pages
.db $01 ;number of 8KB CHR-ROM pages
.db $00|MIRRORING ;mapper 0 and mirroring
.dsb 9, $00 ;clear the remaining bytes

;--------------------------------------------
; program bank(s)
;--------------------------------------------

.base $10000-(PRG_COUNT*$4000)

;------------------------------------------- 
Reset:
sei			; disable IRQs
cld			; disable decimal mode
ldx	#$40
stx	$4017		; disable APU frame IRQ
ldx	#$ff		; Set up stack
txs			;  .
inx			; now X = 0
stx	$2000		; disable NMI
stx	$2001		; disable rendering
stx	$4010		; disable DMC IRQs

	;; first wait for vblank to make sure PPU is ready
vblankwait1:
bit	$2002
bpl	vblankwait1

clear_memory:
	lda	#$00
	sta	$0000, x
	sta	$0100, x
	sta	$0300, x
	sta	$0400, x
	sta	$0500, x
	sta	$0600, x
	sta	$0700, x
	lda	#$fe
	sta	$0200, x	; move all sprites off screen
	inx
 bne	clear_memory

;; second wait for vblank, PPU is ready after this
vblankwait2:
bit	$2002
bpl	vblankwait2
;-------------------------------------------
initloadpal:
lda $2002
lda #$3F
sta $2006
lda #$00
sta $2006
ldx #$00

loadpal:
lda pal,x
sta $2007
inx
cpx #$20
bne loadpal

lda #$80
sta $2000;enable NMI
lda #$00;disable Sprites and BG
sta $2001;enable only when BG writes are done
lda #$00 ;disable scrolling
sta $2005;disable scrolling
sta $2005;disable scrolling
;-------------------------------------------
ldx #$00
ldsp:
lda sprite0,x
sta $0200,x
inx
cpx #$08
bne ldsp

lda #$2002;reset PPU latch
lda #$20
sta $2006
lda #$00
sta $2006

ldx #$00
ldy #$00
ldbg0:
lda level0,x
sta $2007
inx
bne ldbg0
ldbg1:
lda level1,x
sta $2007
inx
bne ldbg1
ldbg2:
lda level2,x
sta $2007
inx
bne ldbg2
ldbg3:
lda level3,x
sta $2007
inx
cpx #$C0
bne ldbg3

ldx #$00
ldy #$00
lda #$1E
sta $2001
;-------------------------------------------
;-------------------------------------------
main:;checks for collision
lda $0204;vert pos of metasprite
clc
adc #$08
clc
ror A
clc
ror A
clc
ror A
clc; this will divide the y position in pixels by 8 to determine the tile position (so its like pixelposition->tileposition)
sta ypos
lda $0207;hor pos of metasprite
clc
ror A
clc
ror A
clc
ror A
clc;same for X
sta xpos
;-------------------------------------------
ldx #$00
lda ypos
clc
ror A
clc
ror A
clc
ror A
clc; this will determine which part of thee nametable has to be looked at by dividing by 8 again
cmp #$00
beq le0;until #$07 is reached
cmp #$01
beq le1;until #$0F is reached
cmp #$02
beq le2;until #$17 is reached
cmp #$03
beq le3;until #$1F is reached
;-------------------------------------------
le0:
lda ypos
sta yadd;could also be used to know which line of the nametable part has to be looked at, eg. if 1 then its the 2. line (zeroindexed)
jsr add32; this will add as many time #$20 to the x register as ypos has stored from a range within 0-7
ldx xpos
lda level0,x
cmp #$07;emptyness->falls through
beq fallf;if true, fall_f is set
jmp main
le1:
lda ypos
and #$07
sta yadd
jsr add32
ldx xpos
lda level1,x
cmp #$07;emptyness->falls through
beq fallf
jmp main
le2:
lda ypos
and #$07
sta yadd
jsr add32
ldx xpos
lda level2,x
cmp #$07;emptyness->falls through
beq fallf
jmp main
le3:
lda ypos
and #$07
sta yadd
jsr add32
ldx xpos
lda level3,x
cmp #$07;emptyness->falls through
beq fallf
jmp main
fallf:
lda #$01
sta fall_f
jmp main

add32:
ldx #$00
lda yadd
cmp #$00
beq rts_le
add32_on:
lda xpos
clc
adc #$20
sta xpos
inx
cpx yadd
bne add32_on
rts_le:
rts
;-------------------------------------------


;-------------------------------------------
;-------------------------------------------
NMI:
pha
txa
pha
tya
pha

inc $0203
inc $0207
inc $0203
inc $0207; this will always increase hor pos of sprite
inc count;used for animation routine
lda fall_f
cmp #$01;is flag for fall set?
beq fall
nmi_on:
jsr anim
lda #$00
sta $2003
lda #$02
sta $4014

pla
tay
pla
tax
pla
rti
;-------------------------------------------
IRQ:

;-------------------------------------------
anim:
lda count
cmp #$08
beq a2
cmp #$10
beq a3
rts
a1:
lda #$01
sta $0205
rts
a2:
lda #$02
sta $0205
rts
a3:
lda #$03
sta $0205
lda #$00
sta count
rts
;-------------------------------------------
fall:
inc $0200
inc $0204;add one pixel to y pos of both sprites
lda #$00;reset fall_f
sta fall_f
jmp nmi_on
;-------------------------------------------
pal:
;bg palette data
HEX 0F 30 10 00
HEX 0F 02 38 3C
HEX 0F 1C 15 14
HEX 22 36 05 14 
;sprite palette data
HEX 0F 10 30 00
HEX 3f 30 10 00
HEX 0f 00 30 10
HEX 22 36 05 14
sprite0:;Sprite in Stand position
;   ve ti at ho
HEX 85 00 00 70
HEX 8D 01 00 70

level:
.include "level.asm"
;-------------------------------------------
; interrupt vectors
;-------------------------------------------

.org $fffa

.dw NMI
.dw Reset
.dw IRQ

;--------------------------------------------
; CHR-ROM bank
;--------------------------------------------

.incbin "chr.chr"
Here is also the level.asm file, which contains the nametable. this is only one screen, but i needed to split it into several parts as the nes can not count beyond #$FF with its X register:

Code: Select all

;This will be used for level data and Collision detection
;One Screen is 32x30 tiles big
;$06=Top Block, $05=Middle Block, 04=Top Block
level0:
HEX 0505050505050505050505050505050505050505050505050505050505050505
HEX 0505050505050505050505050505050505050505050505050505050505050505
HEX 0505060606060606060606060606060606060606060606060606060606060505
HEX 0505070707070707070707070707070707070707070707070707070707070505
HEX 0505070707070707070707070707070707070707070707070707070707070505
HEX 0505070707070707070707070707070707070707070707070707070707070505
HEX 0505070707070707070707070707070707070707070707070707070707070505
HEX 0505070707070707070707070707070707070707070707070707070707070505
level1:
HEX 0505070707070707070707070707070707070707070707070707070707070505
HEX 0505070707070707070707070707070707070707070707070707070707070505
HEX 0505070707070707070707070707070707070707070707070707070707070505
HEX 0505070707070707070707070707070707070707070707070707070707070505
HEX 0505070707070707070707070707070707070707070707070707070707070505
HEX 0505070707070707070707070707070707070707070707070707070707070505
HEX 0505070707070707070707070707070707070707070707070707070707070505
HEX 0505070707070707070707070707070707070707070707070707070707070505
level2:
HEX 0505070707070707070707070707070707070707070707070707070707070505
HEX 0505070707070707070707070707070707070707070707070707070707070505
HEX 0505070707070707070707070707070707070707070707070707070707070505
HEX 0505070707070707070707070707070707070707070707070707070707070505
HEX 0505070707070707070707070707070707070707070707070707070707070505
HEX 0505070707070707070707070707070707070707070707070707070707070505
HEX 0505070707070707070707070707070707070707070707070707070707070505
HEX 0707070707070707070707070707070707070707070707070707070707070707
level3:
HEX 0707070707070707070707070707070707070707070707070707070707070707
HEX 0707070707070707070707070707070707070707070707070707070707070707
HEX 0404040404040404040404040404040404040404040404040404040404040404
HEX 0505050505050505050505050505050505050505050505050505050505050505
HEX 0505050505050505050505050505050505050505050505050505050505050505
HEX 0505050505050505050505050505050505050505050505050505050505050505

nostromo
Posts: 9
Joined: Tue Aug 12, 2014 11:25 pm
Location: Sonora, Mexico

Re: Need some help and advice with my collision detection

Post by nostromo » Fri Sep 12, 2014 5:39 pm

I decided to check the ppu viewer and saw the tiles in wrong place
then I add this code just before the main rutine

Code: Select all

 lda #0
 sta $2005
 sta $2005
and It works.

3gengames
Formerly 65024U
Posts: 2276
Joined: Sat Mar 27, 2010 12:57 pm

Re: Need some help and advice with my collision detection

Post by 3gengames » Fri Sep 12, 2014 6:05 pm

Didn't get to it, but it's because at the end of NMI, you have to clear $2005, or $2006, or preferably both. What happens is $2006 (PPU Addr), and $2005 (Scroll) registers are the exact same register internally, so what you have to do is write the scroll registers last, because any tiles you update from $2006 changes the scroll if not reset. The scroll is reloaded every frame before rendering, so if you write $2006, it basically overwrites the $2005 scrolling. For the wiki on it:

http://wiki.nesdev.com/w/index.php/The_ ... _scrolling

User avatar
thefox
Posts: 3141
Joined: Mon Jan 03, 2005 10:36 am
Location: Tampere, Finland
Contact:

Re: Need some help and advice with my collision detection

Post by thefox » Fri Sep 12, 2014 7:07 pm

Scroll coordinates (X and Y) are 9 bits big, so you need to write both $2005 (twice) and $2000 to set them fully. You don't need to write $2006, unless you're doing midscreen scroll changes.
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi

SNgamer
Posts: 44
Joined: Tue Feb 11, 2014 7:12 am

Re: Need some help and advice with my collision detection

Post by SNgamer » Sat Sep 13, 2014 2:53 am

thanks for the suggestion, but changing scroll register right before main routine did not change anything (i actually turned off scrolling way before in the code).
here is a picture to show what i actually mean, maybe this was not really clear:
Attachments
is stuck in ground but moves
is stuck in ground but moves

User avatar
Kasumi
Posts: 1292
Joined: Wed Apr 02, 2008 2:09 pm

Re: Need some help and advice with my collision detection

Post by Kasumi » Sat Sep 13, 2014 4:51 am

What you did doesn't "disable" scrolling. It does set scrolling to the top left of the first nametable as you might want, though.

Code: Select all

lda #$80
sta $2000;enable NMI
lda #$00;disable Sprites and BG
sta $2001;enable only when BG writes are done
lda #$00 ;disable scrolling
sta $2005;disable scrolling
sta $2005;disable scrolling
But... slightly after this, you write to $2006.

Code: Select all

;-------------------------------------------
ldx #$00
ldsp:
lda sprite0,x
sta $0200,x
inx
cpx #$08
bne ldsp

lda #$2002;reset PPU latch
lda #$20
sta $2006
lda #$00
sta $2006
Writes to $2006 affect the scroll's position, so after those writes to $2006, the scroll is likely no longer at the top left of the first nametable where you want it.

The fix mentioned absolutely does work:
Image

That is to say, add these writes to $2005 slightly before main

Code: Select all

ldx #$00
ldy #$00
lda #$1E
sta $2001
;-------------------------------------------
;-------------------------------------------

lda #$00 
sta $2005
sta $2005

main:;checks for collision
SNgamer wrote:but changing scroll register right before main routine did not change anything
May I ask what how you did it it that it didn't work?

Edit: I'm wrong again, this doesn't work. But I'll find out why...

SNgamer
Posts: 44
Joined: Tue Feb 11, 2014 7:12 am

Re: Need some help and advice with my collision detection

Post by SNgamer » Sat Sep 13, 2014 5:09 am

Kasumi wrote: That is to say, add these writes to $2005 slightly before main

Code: Select all

ldx #$00
ldy #$00
lda #$1E
sta $2001
;-------------------------------------------
;-------------------------------------------

lda #$00 
sta $2005
sta $2005

main:;checks for collision
SNgamer wrote:but changing scroll register right before main routine did not change anything
May I ask what how you did it it that it didn't work?

Edit: I'm wrong again, this doesn't work. But I'll find out why...
Just the same way you placed the $2005 writes: right before main routine, but as you yourself did notice, it does not fix the problem...
its no problem if this can not be solved, i will eventually stick with the suggested way of doing collision, but would be interestening why
the sprite is stuck in ground when collision detection stops letting the sprite fall.

User avatar
Kasumi
Posts: 1292
Joined: Wed Apr 02, 2008 2:09 pm

Re: Need some help and advice with my collision detection

Post by Kasumi » Sat Sep 13, 2014 5:34 am

Whee... being wrong is fun. But I'm still quite confused by this. Putting this at the end of your NMI does work:

Edit: No... it doesn't? I just had a rom... that did work. But apparently the change I suggested isn't what made it work, since I did other debugging stuff... I'll find out what works and avoid making more wrong posts again, sorry.

Edit2: Okay, figured it out. Here's a ROM (Let me know if you want it removed, it's here to prove I'm not nuts), as well as the changes. If the changes I listed don't give you this result, tell me and I will find out what I forgot.

Code: Select all

main:;checks for collision
bit $2002
bpl main
lda $0204;vert pos of metasprite
clc
adc #$09
lsr a
lsr a
lsr a
sta ypos
lda $0207;hor pos of metasprite
lsr a
lsr a
lsr a
sta xpos
I made your main loop actually wait for the vblank to start (bit $2002, bpl). There are better ways to do this which I hope I'll remember to list in another post, but I have something to do like right now.

I changed your CLC, RORs to LSR A. LSR ignores the carry, so no need to CLC. LSR is identical to CLC, then ROR basically. (Both of these may not have had much to do with the problem, but when I didn't list everything and tried it, it didn't work.)

I added this to the end of your NMI:

Code: Select all

lda #$80
sta $2000

lda #$00 
sta $2005
sta $2005
This sets the scroll every frame. It's good practice to do it every frame, even if it doesn't change. A bit $2002 before those $2005 writes would be the most safe, but you cannot do this because of it messes up the frame wait stuff I mentioned above. (Which is part of why there are other ways to do it that I can't cover right this minute)

Finally, I did this:

Code: Select all

lda $0204;vert pos of metasprite
clc
adc #$09
lsr a
lsr a
lsr a
sta ypos
The PPU draws sprites one pixel lower than the position you give it. (A y position of 0 will be drawn on scanline 1, etc.) So I added 1 here to compensate.

I am sorry for the wrong post before, and I will try to give some other tips later. But I really gotta go now.
Attachments
col.nes
(24.02 KiB) Downloaded 118 times
Last edited by Kasumi on Sat Sep 13, 2014 6:03 am, edited 1 time in total.

Sik
Posts: 1589
Joined: Thu Aug 12, 2010 3:43 am

Re: Need some help and advice with my collision detection

Post by Sik » Sat Sep 13, 2014 5:58 am

Basically setting the scroll position is the very last thing you need to do with the video hardware.

User avatar
Kasumi
Posts: 1292
Joined: Wed Apr 02, 2008 2:09 pm

Re: Need some help and advice with my collision detection

Post by Kasumi » Sat Sep 13, 2014 6:09 am

I'm curious now too. I feel like putting the writes to $2005 where I first said should have been enough. There were no writes to anything that I know about that would have changed it after that point. $2006 isn't touched, nor $2005 again, nor $2000 or $2001, unless I'm missing something. Does $2005/$2000 really have to be written every frame? I thought it could be expected to stay what it was, so long as no other writes were made to the mentioned registers.

Regardless, I made an edit to my last post that does get the desired behavior. (Mentioning because the edit was made after another post was made.)

Sik
Posts: 1589
Joined: Thu Aug 12, 2010 3:43 am

Re: Need some help and advice with my collision detection

Post by Sik » Sat Sep 13, 2014 6:29 am

Kasumi wrote:Does $2005/$2000 really have to be written every frame?
Yes, because the address completely changes after it rendered the entire screen (the address keeps changing as it fetches the pixels for the background).

Post Reply