Where is a good place to check for collisions?

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Where is a good place to check for collisions?
by on (#146845)
Well, I had just recently moved my metasprite building routine to where it ran after all the objects had been gone through and it got me thinking... Would it be good to run through collisions for everything after all the objects have been gone through, like the metasprite routine? You could have every object have a register set aside for it that would be a flag for if it was hit during the collision code.
Re: Where is a good place to check for collisions?
by on (#146854)
For performance reasons, I only iterate over the list of objects once. Even drawing the metasprites is something I do during this single sweep.

I used to think that since objects can influence the positions and states of other objects, that I would only be able to draw a consistent state after all of them had been processed. But I ended up going with something simpler: I draw the objects using information from the previous frame, which is known to be stable, and only then I run the rest of the object code.

I didn't get very far with collision detection, but I'd surely look for an apropriate time during the one time slice I give each object, even if that results in small errors. For example, testing for a collision between an object that has already moved and another that hasn't might produce different results than if both objects had moved already... but I think that's a small price to pay for the performance boost that is not having to sweep the list of objects twice (or 3 times).
Re: Where is a good place to check for collisions?
by on (#146855)
If you aren't sweeping over the list of objects multiple times, you're preserving registers and jumping a bunch though. I like doing it all after because you don't have to write jumps and stuff for all the objects, and performance seems to be about the same. (It actually seemed like I got a slight boost, but I did some other stuff so I don't know if that was what actually helped.)
Re: Where is a good place to check for collisions?
by on (#146858)
Our experiences may differ, considering I work with the NES and you with the SNES, but to me it just makes sense to do everything related to a particular object when I'm already working in the context of that object, rather than leaving that context only to restore it at a later time.
Re: Where is a good place to check for collisions?
by on (#146860)
I just figure a simple lda, beq for checking each object slot is a quicker than jrs, phx, phy, plx, ply, rts.
Re: Where is a good place to check for collisions?
by on (#146871)
My design uses three loops.

The first loop updates the player and the player's projectiles

The second loops through the enemies and:
  • Updates its position
  • Checks for collisions between then enemy and the player.
  • Checks for collisions between then enemy and the player projectiles.

The third (display) loop displays the player, projectiles and enemies using my MetaSprite routines.


The main reason I'm using three loops is because:
  1. By separating the enemies and the player projectiles, I decrease the number of collisions needed from O(n2) to O(n*m).
    This has the disadvantage of having potentially overlapping enemies, but this is what I think Zelda aLttP does, so I don't think it will be a problem.
  2. The game design calls for times when the Entity's need to be displayed but not processed.
    The Game Over animation, acquire item animation and the (future) options menu spring to mind.
Re: Where is a good place to check for collisions?
by on (#146875)
UnDisbeliever wrote:
My design uses three loops.

The first loop updates the player and the player's projectiles

The second loops through the enemies and:
  • Updates its position
  • Checks for collisions between then enemy and the player.
  • Checks for collisions between then enemy and the player projectiles.

The third (display) loop displays the player, projectiles and enemies using my MetaSprite routines.

Even though I loop through my objects only once, my design is somewhat similar to this. I cheat with the player object, updating it before all other objects, but not drawing it. Then in the actual loop, that randomizes the order in which objects are processed (for sprite cycling), all objects are drawn (using the previous frame's stable state) and then processed, and the player also gets drawn during this time (so it takes part in the sprite cycling).

I know this is not the ideal setup, but on the NES I kinda feel the need to take a few shortcuts in order to optimize CPU usage. On the SNES I think you can take the time to sweep through the list of objects more times.
Re: Where is a good place to check for collisions?
by on (#146973)
I do collision in the AI routine. The only reason why I do metasprites seperately, is because the "plasma grinch" requires sprite priorities.

Is there anyway of doing sprite priorities and flickering at the same time?
Re: Where is a good place to check for collisions?
by on (#146974)
psycopathicteen wrote:
Is there anyway of doing sprite priorities and flickering at the same time?

I process objects in random order, so that sprite priorities are cycled every frame, and I created 2 virtual sprite layers by allowing objects to select which end of the OAM they'll be rendered to (the OAM is filled from both ends towards the center). I try to keep the number of high priority sprites down, otherwise the low priority ones will flicker too much or even disappear. Sprites of the same object are always rendered in the same order, so I have full control of priorities there.
Re: Where is a good place to check for collisions?
by on (#146975)
I handle both priority and flicker in the following way:

I have an array of 16 objects.

I always draw object 0 first, this lets me give a single object priority.

After this, I increment the index by some relatively prime number (e.g. 1, 5, 7, 11) that changes for each frame. This allows me to iterate through all the objects in a different order each frame, creating flicker when there is overlap. X = (X + prime) & 15

Aside from the object, there are some special things outside the object system that are drawn first or last for priority needs. If I ever needed more than one prioritized object, I might create a special solution for that, but so far hasn't come up in my game.
Re: Where is a good place to check for collisions?
by on (#146977)
On the SNES, you really don't even need to worry about sprite flicker, so I have no plans of implementing something like that. The sprite pixel per scan line limit is a major pain, but you can't really do anything about it.
Re: Where is a good place to check for collisions?
by on (#147006)
Flicker has other purposes besides the sprite limits. It can prevent overlapping objects from hiding each other, which can be very important to gameplay. E.g. imagine a bullet suddenly pops out from behind a spaceship.
Re: Where is a good place to check for collisions?
by on (#147008)
I probably wouldn't be doing it all the time though, and I could probably just get by coding it into the specific object.
Re: Where is a good place to check for collisions?
by on (#147867)
tokumaru wrote:
I cheat with the player object, updating it before all other objects, but not drawing it.

Why do you update the player object first? (Because its position is needed for the enemy-player collisions?)
Re: Where is a good place to check for collisions?
by on (#147875)
Perhaps because the camera follows the player.
Re: Where is a good place to check for collisions?
by on (#147882)
thefox wrote:
Why do you update the player object first? (Because its position is needed for the enemy-player collisions?)

Yes. Many objects collide with the player, and I'd rather have it consistently positioned for all collision tests. If the player took part in the object randomization, objects processed before the player would see it in one place and the ones after it in another.

tepples wrote:
Perhaps because the camera follows the player.

This was true at some point, but eventually I decided to have the camera follow the previous position of the player. I made this decision because the previous position is known to be valid, while the current position could still be modified by objects pushing the player.

I have to confess I'm starting to forget some of the decisions I made regarding this aspect of my Sonic-like game. I haven't looked at the source in years, so there is a possibility I'm talking nonsense! =)
Re: Where is a good place to check for collisions?
by on (#147883)
Have you ever posted a demo? I want to see Sonic on the NES.
Re: Where is a good place to check for collisions?
by on (#147886)
tokumaru wrote:
thefox wrote:
Why do you update the player object first? (Because its position is needed for the enemy-player collisions?)

Yes. Many objects collide with the player, and I'd rather have it consistently positioned for all collision tests. If the player took part in the object randomization, objects processed before the player would see it in one place and the ones after it in another.

I guess another reason for updating player before everything else could be to do any kind of calculations required by the other objects. For example, if object-object collisions are done by checking for bounding box overlap, the player's bounding box could be precalculated (no need to calculate it again for each enemy).

When it comes the time to draw the player in the object loop though, do you draw it with the previous frames coordinates? I think you'd need to save a copy of the previous frames coordinates specifically for player in that case.
Re: Where is a good place to check for collisions?
by on (#147893)
tokumaru wrote:
This was true at some point, but eventually I decided to have the camera follow the previous position of the player. I made this decision because the previous position is known to be valid, while the current position could still be modified by objects pushing the player.

You should update the camera position at the end, after all the objects have been processed (especially if there's anything else that could affect the camera position besides the player - e.g. a boss that brings attention to itself to make it easier to see what's going on).

Good cameras can end up being extremely complex anyway.
Re: Where is a good place to check for collisions?
by on (#147897)
psycopathicteen wrote:
Have you ever posted a demo? I want to see Sonic on the NES.

No, I never got past the stage of backgrounds made of colored boxes and dumb objects that are moved around without physics. Nothing particularly interesting to see.

thefox wrote:
For example, if object-object collisions are done by checking for bounding box overlap, the player's bounding box could be precalculated (no need to calculate it again for each enemy).

Yes, that's something I considered, but never got to implement.

Quote:
When it comes the time to draw the player in the object loop though, do you draw it with the previous frames coordinates? I think you'd need to save a copy of the previous frames coordinates specifically for player in that case.

I believe I did, but things are indeed fading from memory... :cry:

Sik wrote:
You should update the camera position at the end, after all the objects have been processed (especially if there's anything else that could affect the camera position besides the player - e.g. a boss that brings attention to itself to make it easier to see what's going on).

Ideally, yes, but that would require a second pass over the objects in order to draw them afterwards. This is the NES, where each CPU cycle is worth gold if you're trying to code something that can compare to 16-bit games, so the goal is to iterate over the objects only once, and do the AI and the drawing in one go, and the camera position has to be final so that sprites can be drawn.

A 1 frame delay in the camera in a game running at 60Hz should be unnoticeable. I was counting on it! =)
Re: Where is a good place to check for collisions?
by on (#147900)
tokumaru wrote:
psycopathicteen wrote:
Have you ever posted a demo? I want to see Sonic on the NES.

No, I never got past the stage of backgrounds made of colored boxes and dumb objects that are moved around without physics. Nothing particularly interesting to see.

I still got curious about how the graphics would look like =P

tokumaru wrote:
Ideally, yes, but that would require a second pass over the objects in order to draw them afterwards. This is the NES, where each CPU cycle is worth gold if you're trying to code something that can compare to 16-bit games, so the goal is to iterate over the objects only once, and do the AI and the drawing in one go, and the camera position has to be final so that sprites can be drawn.

Technically only the objects that can affect the camera are the ones that matter (usually just the player, and maybe the bosses if they affect the camera beyond locking - bosses have enough data to be worth considering making them separate from normal objects).
Re: Where is a good place to check for collisions?
by on (#147909)
Sik wrote:
I still got curious about how the graphics would look like =P

I shared some of it in the past, but recently I compiled a bunch of graphics from various stages of development to show someone, and since I don't see any reason to keep this stuff secret I just posted them in the graphics forum for anyone that wants to see.

tokumaru wrote:
Technically only the objects that can affect the camera are the ones that matter (usually just the player, and maybe the bosses if they affect the camera beyond locking - bosses have enough data to be worth considering making them separate from normal objects).

Objects that push the player (like moving walls) would indirectly cause the camera to move too. The screen coordinates for the sprites are calculated from the coordinates of the camera, so the position of the camera has to be final before the objects are processed because they're drawn during that time too. The simplest way to to that is to lag the camera by 1 frame, something I doubt anyone will notice. The only object to receive special treatment is the player, since he's the object that's interacted with the most, but this treatment wouldn't be so special anymore if several other objects started receiving it too.