Object collision

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems.

Moderator: Moderators

Post Reply
Celius
Posts: 2157
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Object collision

Post by Celius » Sun Jun 12, 2005 5:16 pm

I know how to move sprites and do backgrounds and all that, but how do you make an object collide with another one? I couldn't really find any info on it, so can someone help me? thanks. :)

User avatar
Zepper
Formerly Fx3
Posts: 3217
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Post by Zepper » Sun Jun 12, 2005 7:27 pm

Well, if you know how to move sprites, you know their position, correct? I'm unsure about what do you plan but... anyway, keep track of sprite #0 - if it's a game character (or whatever) and you wanna collision, there are 2 points:

A. Sprite x Sprite collision = you could keep track of their X,Y positions in RAM 200-2FF as example. Once X1 = X2 and Y1 = Y2 (in a latency of S pixels, where S is the size of your desired sprite), you got a strike and triggers the event.

B. Sprite x Background collision = even if you use sprite #0 hits to detect solid background pixel, it's useless most of times. This way, you must read the nametable (a tile in X,Y position) and compares with the sprite - it would had attributes (as solid, air, spikes...). Another RAM region would get the things working good.

I'm sorry, try ASM code by yourself. Get the idea and test it.

tepples
Posts: 22049
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples » Sun Jun 12, 2005 7:38 pm

First, given two rectangles specified by left, right, top, and bottom, determine whether they overlap. Can you do that?

Then for each game object, construct its bounding box. (Normally, games will leave a few pixels outside the bounding box to compensate for the fact that sprite cels aren't rectangular.)

For each pair of game objects, compare their bounding boxes to see if they overlap.

Celius
Posts: 2157
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Post by Celius » Sun Jun 12, 2005 9:55 pm

I didn't really understand what you were saying there Fx3, though it's probably completely logical, and I'm just bad at interperting things into my own head. I have an idea to tell it when the object moving is in tile #99, it will disable the RIGHTKEYdown function. But I don't know how to define a variable in RAM for a tile #, because you can only say something like this:

Something = $80

you couldn't say this:

Something = #80

You can only define variables with hex crap, you can't do it with decimal, and that sucks! I think I'm using a crappy assembler, though, I'm using Nesasm, and I heard that sucks. I'm probably not making sense, so I'm gonna stop babling now.

Celius
Posts: 2157
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Post by Celius » Sun Jun 12, 2005 10:54 pm

Sorry, ignore that thing above. This is my code:

Code: Select all

Collide:
	lda Y_Pos
	cmp #100
	beq NOTHINGdown
	lda X_Pos
	cmp #99
	beq NOTHINGdown
I know that that isn't correct by the way. I don't know how to get it to stop when it's at location 99,100 if 100 is Y and 99 is X. It of course stops at in the column where X= 99, and in the column where Y= 100. Ya know what I mean? I can't think of a better way to explain it. How do you get it so it only stops when X= 99 and Y=100?

User avatar
Zepper
Formerly Fx3
Posts: 3217
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Post by Zepper » Mon Jun 13, 2005 5:43 am

Please, you must clarify what you want to do. Go read again what I and tepples wrote about it. :|

Celius
Posts: 2157
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Post by Celius » Mon Jun 13, 2005 12:46 pm

Sorry I'm not clear enough about what i want. I am trying to make a collision with my moving sprite, and a still sprite. It has the effect of a background collision, where when you hit the sprite, you stop moving. The still sprite basicly acts as a block like on mario. Sorry if I'm annoying everyone with my dumb questions... :(

User avatar
Memblers
Site Admin
Posts: 3877
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Post by Memblers » Mon Jun 13, 2005 1:33 pm

These questions aren't dumb, just kinda hard. :)

I'd say that collision detection is one of the trickier things to code. At least for for sprite-to-bg. Sprite-to-sprite is easier and a good place to start, since the sprites are on the same coordinate system to begin with.

What you need to do to use bounding boxes like tepples said, is to do some range checking. This probably isn't an ideal example, but here's how I do this in Munchie Attack.

notes:
player's "mouth" sprite starts at $204
food objects start at $240
the @itsblank label is where it goes for 'no hit'.
the BCC/BCS branch after CMP is used to do greater/less than checking. For example, food objects are coming from the right, so the food's coordinate has to be less than the player's right edge, and greater than the player's left edge to count as a hit.
The values added and subtraced change the size of the box.

Code: Select all

hit_detection:
        ldx #0
@hitloop:
        lda $241,x
        sta tiletype
        bne :+
        jmp @itsblank
:
        lda $243,x
        sec
        sbc #8
        cmp $207
        bcc :+
        jmp @itsblank
:
        clc
        adc #24
        cmp $207
        bcs :+
        jmp @itsblank
:

        lda $240,x
        sec
        sbc #15
        cmp $204
        bcc :+
        jmp @itsblank
:
        clc
        adc #30
        cmp $204
        bcs :+
        jmp @itsblank
:

        lda #0            ; if it makes it all the way here, it was hit
        sta $241,x
        sta $245,x
        sta $249,x
        sta $24D,x
Also see here for some info about sprite-to-bg collisions:
http://www.greggman.com/mckids/programming_mc_kids.htm

Guest

collision sample logic

Post by Guest » Mon Jun 13, 2005 1:36 pm

my guess is that you are doing something like this:

byte check_for_collision(
byte sprite_1_x, int sprite_1_y,
byte sprite_2_x, int sprite_2_y,
byte x_distance, /*max X distance needed for collision*/
byte y_distance /*max Y distance needed for collision*/
)
{
byte x_diff = sprite_1_x - sprite_2_x;

if (x_diff < 0)
x_diff = -x_diff;

if (x_diff > x_distance)
return(0); /*no collision*/

byte y_diff = sprite_1_y - sprite_2_y;

if (y_diff < 0)
y_diff = -y_diff;

if (y_diff > y_distance)
return(0); /*no collision*/

return(1); /*collision happened*/
}

Translating to assembly language should not be that difficult.

Celius
Posts: 2157
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Post by Celius » Mon Jun 13, 2005 2:20 pm

I wouldn't have trouble with this if there were some way to say this:

lda Y_Pos
cmp #100
and
lda X_Pos
cmp #93
bne NOTHINGdown

When I say and, I don't mean the actuall command. Is there some way to say only go to NOTHINGdown, if Y_Pos = 100 and X_Pos = 93?

User avatar
Memblers
Site Admin
Posts: 3877
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Post by Memblers » Mon Jun 13, 2005 2:28 pm

Celius wrote: When I say and, I don't mean the actuall command. Is there some way to say only go to NOTHINGdown, if Y_Pos = 100 and X_Pos = 93?
Yeah. You need to change the branch condition and/or destination of the first check. What comes to mind for me is this:

Code: Select all

 lda y_pos
 cmp #100
 bne skip
 lda x_pos
 cmp #93
 beq NOTHINGdown
skip:

Celius
Posts: 2157
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Post by Celius » Mon Jun 13, 2005 2:50 pm

Thank you! But is there a simpler way to do this? because if you're making a platformer with about as many platforms as say Metroid, You probably wouldn't want to do all that for every little pixel, if you know what I mean. Is there a way to write to the object, instead of the pixel? :)

User avatar
blargg
Posts: 3715
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg » Mon Jun 13, 2005 6:24 pm

Oh man, you should have seen the code for a PC sidescroller I tried to write when I was first learning C. I used fractional values for the player position and I think my "move until hit obstacle" tried every single sub-pixel position. A later version found the intercept of the movement vector. Still all major overkill; this wasn't a physics simulation that required absolute accuracy.

Draw a picture and think about the minimum work necessary to find if movement is possible, and how far. Then find simplifications that don't add much more work than the minimum. Be sure to abstract the problem to only the essential details.

Also, find a way to enjoy experimenting with 6502 programming techniques. It really helps to write simple debugging output routines to print a byte (or find an emulator with a good debugger), so you can write short test code and see the results.

User avatar
teaguecl
Posts: 210
Joined: Thu Oct 21, 2004 4:02 pm
Location: San Diego

Post by teaguecl » Mon Jun 13, 2005 10:30 pm

Combining the responses already given in another way, here's my $0.02: You obviously don't want to write custom code to detect collision between every object on every map of every level of your game. As blargg suggests, you should try to abstract this problem so that it is more general. This abstracted version (often called a "engine") should allow you design levels using the concept of objects, as opposed to pixels. The key is to get the level of abstraction right. The more abstract it is the more general your engine is, but it also becomes more difficult to implement it. You want it abstract enough that it simplifies your design, but not so abstract that it does more than you need.

tepples
Posts: 22049
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples » Tue Jun 14, 2005 2:43 pm

Try prototyping on a PC first. Get collision detection working in pure C code, then reduce the algorithm to what a 6502 can handle.

Post Reply