Test Sprite Collision Flag

SGDK only sub forum

Moderator: Stef

Post Reply
kubilus1
Very interested
Posts: 237
Joined: Thu Aug 16, 2012 2:25 am
Contact:

Test Sprite Collision Flag

Post by kubilus1 » Mon May 30, 2016 11:14 pm

So when, am I supposed to test the Sprite collision flag. I can't seem to get this to work reliably without adding a crazy amount of "delay". For instance, if I take the old basic sprite example and test for collision, this does not work unless I loop over the test about 1000 times.

For example, I would expect this to show me a collision, but it will not:

Code: Select all

#include <genesis.h>

#define TILE1	1
#define SPR_NBTILES	4	//tiles needed for our sprite

//const is used to keep tile in ROM, not in RAM
const u32 spriteTiles[SPR_NBTILES*8]=
{
		0x00001111, //Tile Top Left
		0x00001111,
		0x00111144,
		0x00111144,
		0x11112244,
		0x11112244,
		0x11112244,
		0x11112244,

		0x11112222, //Tile Bottom Left
		0x11112222,
		0x11112222,
		0x11112222,
		0x00111122,
		0x00111122,
		0x00001111,
		0x00001111,

		0x11110000, //Tile Top Right
		0x11110000,
		0x44111100,
		0x44111100,
		0x44221111,
		0x44221111,
		0x44221111,
		0x44221111,

		0x22221111, //Tile Bottom Right
		0x22221111,
		0x22221111,
		0x22221111,
		0x22111100,
		0x22111100,
		0x11110000,
		0x11110000
};

int main( )
{
	SpriteDef mySprite;
	SpriteDef mySprite2;
	SpriteDef mySprite3;

	//load the tile in VRAM (check it using GensKMod CPU>Debug>Genesis>VDP)
	VDP_loadTileData( (const u32 *)spriteTiles, TILE1, 4, 0);

	//optional, but take the use to
	VDP_resetSprites();

	// Try 1 : define sprite using setSprite
	// arg0 : sprite idx (from 0 to 79)
	// arg1 : x
	// arg2 : y
	// arg3 : size (from 1x1 to 4x4 tiles)
	// arg4 : tiles properties
	// arg5 : link property (more on this later)
	//VDP_setSprite(0, 0, 0, SPRITE_SIZE(2,2), TILE_ATTR_FULL(PAL0,1,0,0,TILE1), 0);


	// Try 2 : define sprite using setSpriteP
	mySprite.posx = 0;
	mySprite.posy = 0;
	mySprite.size = SPRITE_SIZE(2,2);
	mySprite.tile_attr = TILE_ATTR_FULL(PAL0,1,0,128,TILE1);
	mySprite.link  = 2; //1; //0;
	VDP_setSpriteP(0, &mySprite);

	//the sprite(s) won't be drawn until this call
	//VDP_updateSprites();

	// Try 3 : define multi sprite
	mySprite2.posx = 0;
	mySprite2.posy = 0;
	mySprite2.size = SPRITE_SIZE(1,1); //a sprite 1x1 using 1 tile
	mySprite2.tile_attr = TILE_ATTR_FULL(PAL0,1,0,64,TILE1);
	mySprite2.link  = 2;
	VDP_setSpriteP(1, &mySprite2);
	//VDP_updateSprites();

	// Try 4 : skip mySprite2
	mySprite3.posx = 0;
	mySprite3.posy = 0;
	mySprite3.size = SPRITE_SIZE(2,2);
	mySprite3.tile_attr = TILE_ATTR_FULL(PAL1,1,0,0,TILE1);
	mySprite3.link  = 0;
	VDP_setSpriteP(2, &mySprite3);

	VDP_updateSprites();


    VDP_drawText("no coll ", 2, 2);
	while(1)
	{
		VDP_waitVSync();

		VDP_resetSprites();

		//mySprite.posx++;
		mySprite.posy++;
		VDP_setSpriteP(0, &mySprite);

		//mySprite2.posx+=2;
		mySprite2.posy++;
		VDP_setSpriteP(1, &mySprite2);

		//mySprite3.posx++;
		mySprite3.posy+=2;
		VDP_setSpriteP(2, &mySprite3);

		VDP_updateSprites();
        if(GET_VDPSTATUS(VDP_SPRCOLLISION_FLAG)) {
            VDP_drawText("  COLL  ", 2, 2);
        }

	}
	return 0;
}
If I loop over GET_VDPSTATUS 1024 times, I will show the collision. Obviously that approach is no good, what am I doing wrong here?

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Re: Test Sprite Collision Flag

Post by Stef » Tue May 31, 2016 11:16 am

Honestly trying to use the collision flag is, i believe, a waste of time :p
It only tells you a collision between 2 non transparent pixel sprite happened but it doesn't tell you which sprites...
It was useful back in time when you had only very few sprites but on Megadrive you never rely on this flag. In fact maybe 3 or 4 games uses it and only 1 really uses it to check collision between players versus objects and it's probably the worst game ever released on Megadrive (Barbie Super Model) :p

kubilus1
Very interested
Posts: 237
Joined: Thu Aug 16, 2012 2:25 am
Contact:

Re: Test Sprite Collision Flag

Post by kubilus1 » Tue May 31, 2016 4:58 pm

Yeah, alone I realize that it is far from enough. But aside from being annoyed that it is not actually working correctly, I figure I may be able to take some kind of advantage of it.

For instance, let's say I use the collision detection method where I indicate which column each sprite is in. Then assume I move my spites one at a time and check collision between movement. If I detect the collision flag after moving the sprite, and lookup which sprite is in a matching column I should be able to have fairly cheap pixel-perfect collision.

Of course, there are probably a dozen details that will complicate such a method. At the very least the flags not working correctly really bugs me, is something being done in SGDK with horizontal interrupts or something that is causing the register to be read and therefore wiping out the flag?

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Re: Test Sprite Collision Flag

Post by Stef » Tue May 31, 2016 5:47 pm

Normally no, by default SGDK does not read the status flag during active period as H int is not enabled by default, but you need to know that many SGDK method does read it (timer related methods, DMA...) so you have to take care of that.

kubilus1
Very interested
Posts: 237
Joined: Thu Aug 16, 2012 2:25 am
Contact:

Re: Test Sprite Collision Flag

Post by kubilus1 » Tue May 31, 2016 11:30 pm

What I don't understand is that in this simple example, very little is going on. Basically, move sprite, VDP_setSprite, VDP_updateSprites, check collision.

No other methods are being called.

kubilus1
Very interested
Posts: 237
Joined: Thu Aug 16, 2012 2:25 am
Contact:

Re: Test Sprite Collision Flag

Post by kubilus1 » Wed Jun 01, 2016 2:41 am

Okay figured it out. I have to check this during hblank. I setup an interrupt and that seems to work.

So I figure I can grab the vcounter when a collision is detected and know where vertically a collision is happened, more or less for free.

Sik
Very interested
Posts: 939
Joined: Thu Apr 10, 2008 3:03 pm
Contact:

Re: Test Sprite Collision Flag

Post by Sik » Wed Jun 01, 2016 4:35 am

Stef wrote:It only tells you a collision between 2 non transparent pixel sprite happened but it doesn't tell you which sprites...
The TMS9918A would tell you :/ But yeah it's a complete waste of time on the Mega Drive, especially since more often than not you don't want pixel perfect collision (you want there to be some leeway by not having collision against insignificant parts of the sprite, usually hitboxes are a bit smaller than the sprite in use).
Sik is pronounced as "seek", not as "sick".

danibus
Very interested
Posts: 135
Joined: Sat Feb 03, 2018 12:41 pm

Re: Test Sprite Collision Flag

Post by danibus » Mon Oct 07, 2019 6:08 am

Hi there, here testing sprite collision flag also :mrgreen:

It's working, but not sure why... this is my code

Code: Select all

[..] //include and all these stuff

int a = 0;

main()
{

[...] //add sprites, pals,...  and these things

    while(1)
   {
     handleInput();
     check_collision();
     SPR_update();
     VDP_waitVSync();
   }

}



check_collision()
{
  SYS_setHIntCallback(my_hblank);
  VDP_setHIntCounter(8);		//every 8 scanlines, horizontal interr
  VDP_setHInterrupt(1);		//Enable horizontal interr

  VDP_drawText("Collision Bit HW?    ",  2, 20);
  if(GET_VDPSTATUS(VDP_SPRCOLLISION_FLAG)!=0) VDP_drawText("Yes", 26, 20);
  else VDP_drawText("No", 26, 20);
}



void my_hblank()
{
    if(GET_VDPSTATUS(VDP_SPRCOLLISION_FLAG))
    {
        //do nothing
    }
    if(!GET_VDPSTATUS(VDP_SPRCOLLISION_FLAG))
    {
        //do nothing
    }
    a = 0; //this is useless but... works
}





- To get VDP collision bit value, use GET_VDPSTATUS(VDP_SPRCOLLISION_FLAG)
- To get GET_VDPSTATUS(VDP_SPRCOLLISION_FLAG) working, before we need to set a function that launchs at horizontal blank time, and set when its launched:

SYS_setHIntCallback(my_hblank);
VDP_setHIntCounter(8); //every 8 scanlines, horizontal interr
VDP_setHInterrupt(1); //Enable horizontal interr

I put 8, to launch function every 8 scanlines. It's NOT WORKING if I put 4 or 20 scanlines, not sure why :oops:

-If I remove 'a = 0' from my_hblank() also works, but it's very difficult to get 'Yes' stable, just a second, 'No' appears fast.
When using 'a = 0', 'Yes' is stable. Not sure why :oops:


Now one question. Why I can't use vblank instead hblank?

I KNOW, this is useless, I won't use for but... I want to learn :mrgreen:

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Re: Test Sprite Collision Flag

Post by Chilly Willy » Mon Oct 07, 2019 2:33 pm

You know you're setting all the hblank stuff every single time through the loop? Not good. Set once, then do the main loop.

The reason you check it every few lines is because you only know if sprites collided, not which ones. If you check it once per frame, you give yourself no extra info since the bit only says ANY of the sprites collided. Checking it after X number of lines says only those sprites between those lines need to be checked for collision, thus limiting how many sprites you need to check... unless they're ALL between those lines, of course. :lol: Ideally, if the overhead isn't too much for your game, you'd check the collision flag every line. But then you're swapping one kind of overhead for another.

Post Reply