I have trouble getting my head around hardware sprite collisions. At first I thought an interrupt was triggered every time two sprites were rendered and they overlapped. But there are no interrupts even if there is a SPRCOl bit in the IEN register (?). Instead you get all information about sprite collisions once per frame when the vertical blank interrupt is triggered.
But what if several collisions have occurred? All sprite collision masks will be AND:ed together and you do not know how many sprites that were involved. And if you for example have a game with the player and several enemies, How do you know if the player has collided with an enemy or two enemies have collided with each other?
Let's say you have the following masks:
Player mask: %0011
Enemy mask: %0001
Player base: %0010
As long as you have one of each sprite type this works well. You can see if the player have collided with the enemy, the base or both. But if there are two enemies on the screen, you won't know if the player has collided with an enemy or the two enemies have collided with each other. In both cases the resulting mask at VBLANK will be %0001. So either you make sure enemies can never collide or you use code to get the answer, or do I overlook something here?
How handle sprite collisions when several sprites are colliding?
-
- Posts: 292
- Joined: Wed Jun 03, 2020 11:33 am
- Location: Kalmar, Sweden
Re: How handle sprite collisions when several sprites are colliding?
You are right: HW sprite collision detection doesn't help you all the way to know what exactly collided. As you said it can help you to distinguish groups of sprites and then have to know which ones actually collided. In fact there is only 4 groups you can distinguish: As I understand it, you are only supposed to use one bit per group. So your player mask %0011 should probably be %0100.
As I see it HW sprite collision helps you to detect pixel-perfect collisions first between groups. Then you have to use an easier algorithm to find the sprites which are in each others vicinity, depending on which groups were involved. This can still help performance and accuracy.
As I see it HW sprite collision helps you to detect pixel-perfect collisions first between groups. Then you have to use an easier algorithm to find the sprites which are in each others vicinity, depending on which groups were involved. This can still help performance and accuracy.
-
- Posts: 292
- Joined: Wed Jun 03, 2020 11:33 am
- Location: Kalmar, Sweden
Re: How handle sprite collisions when several sprites are colliding?
Ok, looks like these are the limitations. But if the player mask is %0100 it won't work. The masks of colliding sprites are AND:ed together. %0100 and %0001 is 0 just like %0100 and %0010.
I guess if you have many sprites on the screen, you can dynamically change the masks. If the player mask is %1111 and the closest four enemies or maybe shots have %1000, %0100, %0010 and %0001, you can discern which of the four that have collided with the player. But it is probably not worth the effort. If the sprites are moving faster than 1 pixel/frame you won't have pixel-perfect collision detection anyway.
I guess if you have many sprites on the screen, you can dynamically change the masks. If the player mask is %1111 and the closest four enemies or maybe shots have %1000, %0100, %0010 and %0001, you can discern which of the four that have collided with the player. But it is probably not worth the effort. If the sprites are moving faster than 1 pixel/frame you won't have pixel-perfect collision detection anyway.
-
- Posts: 292
- Joined: Wed Jun 03, 2020 11:33 am
- Location: Kalmar, Sweden
Re: How handle sprite collisions when several sprites are colliding?
I don't know if I can draw new attention to this thread, but I try it.
I have realized I still have trouble sorting out how sprite collisions work. I know from the manual that there are no real sprite collision interrupts. Information on which sprites have collided is updated once per frame, at vblank.
I have the following masks:
%0011 - enemies
%0001 - player
%0010 - shot
So when the player and an enemy collide and the masks are AND:ed, I get:
%0001 AND
%0011
-------
%0001
When the shot and an enemy collide, I get:
%0010 AND
%0011
-------
%0010
When the shot and two enemies collide, I thought I would get:
%0010 AND
%0011 AND
%0011
-------
%0010
But I don't. I get %0011. Why? As it works now, I know when an enemy is hit by a shot, but it just works as long as no enemies are colliding with each other at the same time. As I see it, it would be better if it worked as I expected.
Did VERA have real sprite collision interrupts from the beginning? And this is a less successful side effect of simplifying things to just update sprite collision info once per frame? At least, Dusan Strakl speaks about real interrupts in a blog post from 2021 relating to R43 (https://www.8bitcoding.com/p/sprites-in ... ision.html).
I have realized I still have trouble sorting out how sprite collisions work. I know from the manual that there are no real sprite collision interrupts. Information on which sprites have collided is updated once per frame, at vblank.
I have the following masks:
%0011 - enemies
%0001 - player
%0010 - shot
So when the player and an enemy collide and the masks are AND:ed, I get:
%0001 AND
%0011
-------
%0001
When the shot and an enemy collide, I get:
%0010 AND
%0011
-------
%0010
When the shot and two enemies collide, I thought I would get:
%0010 AND
%0011 AND
%0011
-------
%0010
But I don't. I get %0011. Why? As it works now, I know when an enemy is hit by a shot, but it just works as long as no enemies are colliding with each other at the same time. As I see it, it would be better if it worked as I expected.
Did VERA have real sprite collision interrupts from the beginning? And this is a less successful side effect of simplifying things to just update sprite collision info once per frame? At least, Dusan Strakl speaks about real interrupts in a blog post from 2021 relating to R43 (https://www.8bitcoding.com/p/sprites-in ... ision.html).
Re: How handle sprite collisions when several sprites are colliding?
Generally I used the interrupts to know that something has collided, but I use other logic to decide what collided. The interrupt just reduces how often you must check for collisions, but once it triggers you still need to figure out what collided.
-
- Posts: 292
- Joined: Wed Jun 03, 2020 11:33 am
- Location: Kalmar, Sweden
Re: How handle sprite collisions when several sprites are colliding?
Yes, hardware detection has its limitations, but there are still masks available that I would like to utilize if possible. At the very least, I wish to understand how they work.
Re: How handle sprite collisions when several sprites are colliding?
From the looks of it, it appears that it only compares two numbers at a time, then uses that result to compare it to the third, so I did the same comparisons in BASIC and got 2 (0010), the correct answer. Odd.
Re: How handle sprite collisions when several sprites are colliding?
I looked at the VERA's verilog, and the best I could figure out is this:
Each pixel on the screen contains collision mask data, kinda like an alpha channel, or a z-buffer.
When a non-transparent sprite pixel is drawn:
1) If the sprite's collision mask intersects the collision data already stored in the pixel, the intersection (maskFromSprite & maskFromPixel) is combined into the current "for the IRQ" collision status using a logical OR.
2) The sprite's collision mask is combined into the pixel's collision data using a logical OR to facilitate future checks.
When the screen is finished being drawn, if the "for the IRQ" collision status is nonzero, the sprite collision IRQ is asserted and this status is made available in the appropriate register. This status (and the IRQ) is reset and recalculated for each frame (it doesn't wait for you to acknowledge it), so you should explicitly wait for a sprite collision IRQ to occur, and then grab the status.
For example, %0001 is drawn to a pixel. %0010 is drawn to the same pixel. That pixel's collision mask data is now %0011, but since there was no intersection, the current "for the IRQ" status is still %0000.
If %0110 is now drawn to the same pixel, there's a collision because the pixel currently contains %0011, and (%0110 & %0011) is %0010. The "for the IRQ" status is now %0010, and the pixel now contains %0111.
If %0100 is drawn to the same pixel, there's another collision: (%0100 & %0111) is %0100, and the "for the IRQ" status is updated to %0110.
Each pixel on the screen contains collision mask data, kinda like an alpha channel, or a z-buffer.
When a non-transparent sprite pixel is drawn:
1) If the sprite's collision mask intersects the collision data already stored in the pixel, the intersection (maskFromSprite & maskFromPixel) is combined into the current "for the IRQ" collision status using a logical OR.
2) The sprite's collision mask is combined into the pixel's collision data using a logical OR to facilitate future checks.
When the screen is finished being drawn, if the "for the IRQ" collision status is nonzero, the sprite collision IRQ is asserted and this status is made available in the appropriate register. This status (and the IRQ) is reset and recalculated for each frame (it doesn't wait for you to acknowledge it), so you should explicitly wait for a sprite collision IRQ to occur, and then grab the status.
For example, %0001 is drawn to a pixel. %0010 is drawn to the same pixel. That pixel's collision mask data is now %0011, but since there was no intersection, the current "for the IRQ" status is still %0000.
If %0110 is now drawn to the same pixel, there's a collision because the pixel currently contains %0011, and (%0110 & %0011) is %0010. The "for the IRQ" status is now %0010, and the pixel now contains %0111.
If %0100 is drawn to the same pixel, there's another collision: (%0100 & %0111) is %0100, and the "for the IRQ" status is updated to %0110.
-
- Posts: 292
- Joined: Wed Jun 03, 2020 11:33 am
- Location: Kalmar, Sweden
Re: How handle sprite collisions when several sprites are colliding?
Thanks, for analyzing this! I think this is quite hard to understand, but I think I get it.
If I take my example with a shot and two enemies colliding again, is the following right?
1. Shot has mask 0010, pixel mask is 0000, result for IRQ 0000, new pixel mask 0010
2. First enemy has mask 0011, pixel mask is 0010, result for IRQ 0010, new pixel mask 0011
3. Second enemy has mask 0011, pixel mask is 0011, result for IRQ 0011, new pixel mask 0011
This matches what I get in the emulator. So if two enemies collide I will never know if the shot has hit an enemy. The question is if I can choose masks in some other way so, in the end, I will always know if the shot has collided with an enemy even if several enemies also are colliding with each other.
If I take my example with a shot and two enemies colliding again, is the following right?
1. Shot has mask 0010, pixel mask is 0000, result for IRQ 0000, new pixel mask 0010
2. First enemy has mask 0011, pixel mask is 0010, result for IRQ 0010, new pixel mask 0011
3. Second enemy has mask 0011, pixel mask is 0011, result for IRQ 0011, new pixel mask 0011
This matches what I get in the emulator. So if two enemies collide I will never know if the shot has hit an enemy. The question is if I can choose masks in some other way so, in the end, I will always know if the shot has collided with an enemy even if several enemies also are colliding with each other.
Re: How handle sprite collisions when several sprites are colliding?
After reading all this, I've come to the conclusion that BASIC really needs sprite-handling statements.