Theorical question about the sprites

SGDK only sub forum

Moderator: Stef

dub
Very interested
Posts: 101
Joined: Thu Mar 19, 2015 1:26 pm

Theorical question about the sprites

Post by dub » Thu Oct 15, 2015 9:18 am

Hi,
I have question about sprites list.

1) What I want to do : Have one sprite for my player and sprites for enemies.

I don't know how the sprite_eng really work. I read the source and find all information about the sprites list.

In code, I have two arrays :

Code: Select all

//sprite for ennemy
Sprite enn_spr[ENN_MAX];

// sprites player
Sprite sprites[NB_PLAYER];
For the update, can I do that ?

Code: Select all

SPR_update(sprites, Nb_PLAYER);
SPR_update(enn_spr, ENN_MAX);
The problem is that I haven't already init all my enemy sprite. Do I need an other variable to know how much enemy I have created ?
I use ENN_MAX and NB_PLAYER because I know sometime I'll have 32 pixel sprites or 48 pixels sprites. And 48 pixels mean 2 sprites.

2) When I testing collide between player sprite and enemy sprites. I test all enemy sprite with my player. Enemy DIE when he collide. All I know is the number Inside the enn_spr[ENN_MAX] array. Can I use SPR_clear("Number to delete") ?

3) If I delete a enemy sprite, can I always use the SPR_update(enn_spr, ENN_MAX); when we know that a sprite is missing ?
For exemple I have 10 enemies, I kill the number 3. I have only 9 sprites but with the hole in the center of the 10 values array. So I will not test the collide when I test the 9 sprites : enn_spr[2] is empty.

Thanks in advance.

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

Re: Theorical question about the sprites

Post by Stef » Thu Oct 15, 2015 12:43 pm

You can't do that :

Code: Select all

SPR_update(sprites, Nb_PLAYER);
SPR_update(enn_spr, ENN_MAX);
You have to maintain a whole array for all sprite as only one call to SPR_update(..) should be done per frame.
A good way to sort that is to always put the player and fixed sprites at the beginning of the array and enemies / bullets at the end.
Still that is not very common and i plan to improve the sprite engine so we can easily add or remove sprites.
Currently when you want to remove a sprite, if it's at the end of the list you can just decrease the 'num' parameter in the SPR_Update(..) but almost time the sprite will be anywhere in the array, so in this case you can use the SPR_setNeverVisible(..) method to "hide" this sprite and the sprite engine will quickly discard it.

About your collision information, you can actually test for the visibility flag (if you set your hidden sprites to NeverVisible) :

Code: Select all

if (sprites[1].visibility != VISIBILITY_ALWAYS_OFF) 
  // do collision test
But you can also use the 'data' field which is reserved to user (you can store and use it for whatever you want) :

Code: Select all

// test if this sprite is 'alive'
if (sprites[1].data & FLAG_ALIVE) 
  // do collision test

dub
Very interested
Posts: 101
Joined: Thu Mar 19, 2015 1:26 pm

Re: Theorical question about the sprites

Post by dub » Thu Oct 15, 2015 1:14 pm

Thanks, I'll do that. And the field for user will be certainly useful.

For the sprite list and counting the max sprite on screen.
If I have one 32 pixel sprite and two 48 pixel sprite. With your sdk the 48 pixel sprite is in fact two sprites : one 32 pixel + one 16 pixel.
For having the good 'num' parameter in the SPR_Update(..) .

Do I need to make a spr_update(3) or spr_update(5) ?

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

Re: Theorical question about the sprites

Post by Stef » Thu Oct 15, 2015 1:38 pm

The sprite engine hide all that part for you, you just have to consider 1 sprite as 1 moving object, if internally it consumes several hardware sprites you don't have to matter about it.
You can have 1 sprite as big as 128x128 if you want, it will remains only one sprite :)
There is still a limit internally : 20 hardware sprites by software sprite but that should be enough (it allows sprite up to 160x128 max)

dub
Very interested
Posts: 101
Joined: Thu Mar 19, 2015 1:26 pm

Re: Theorical question about the sprites

Post by dub » Thu Oct 15, 2015 2:19 pm

Great.

Merci beaucoup.

dub
Very interested
Posts: 101
Joined: Thu Mar 19, 2015 1:26 pm

Re: Theorical question about the sprites

Post by dub » Thu Oct 15, 2015 4:34 pm

I have another problem with the Sprite list.

I have a player sprite in sprites[0].

Code: Select all

s8 Nb_Spr = 0;	//global
VDP_setPalette(PAL3, shmup_sprite.palette->data);
SPR_initSprite(&sprites[0], &shmup_sprite, posx, posy, TILE_ATTR(PAL3, FALSE, FALSE, FALSE));
Nb_Spr++;

SPR_update(sprites, Nb_Spr);	//in Main Code
After I add 4 enemies.

Code: Select all

for (i=1; i<=4; i++)
		{
			ennx = random() % 300;
			enny = random() % 200;
			SPR_initSprite(&sprites[i], &enn01_sprite, ennx, enny, TILE_ATTR(PAL2, FALSE, FALSE, FALSE));
			Nb_Spr++;

			SPR_setAnim(&sprites[i], ANIM_STAND);
		}
No problem, I see my player sprite and 4 sprites drawing in game view.

So now, I try to destroy enemy on collision.

Code: Select all

int posx1 = posx + 30;	//Collide point of player
	int posy1 = posy + 8;	//Collide point of player in y
	
	
	int nb = 0;
	

	
	for (i=1; i<Nb_Spr; i++)
	{
		ennx = sprites[i].x - 128;	//position of the sprite to test
		enny = sprites[i].y - 128;	

		//test if collision : working
		if ( (posx1 < ennx + ennwidth ) && (posx1 > ennx) && (posy1 < enny + ennheight) && (posy1 > enny) )
		{
			SPR_setNeverVisible(&sprites[i], TRUE);	//hide sprite wihen collide
			//Nb_Spr--;
			nb++;
		}
	}
	Nb_Spr -= nb;
I try with Nb_Spr--; Inside without success.

The problem is : the spritelist change the number of the sprite. I think if I colliding with the sprite[2], the sprite[3] become sprite[2] and disapear too.

If I collide with sprites[1] I lost sprites[1] till sprites[4]
If I collide with sprites[3] I lost sprites[3] till sprites[4]

I try to do the test backward like the function in spr_eng without success

Code: Select all

for (i=Nb_Spr; i>=1; i--)
	{
	//test collision
	}

Edit :: Edit
I read again (many times) your previous post. And I understand :

Code: Select all

for (i=1; i<=Nb_Spr; i++)
	{
		ennx = sprites[i].x - 128;
		enny = sprites[i].y - 128;
		
		if ( (posx1 < ennx + ennwidth ) && (posx1 > ennx) && (posy1 < enny + ennheight) && (posy1 > enny) )
		{
			SPR_setNeverVisible(&sprites[i], TRUE);
		}
	}
And I doesn't decrement the number of sprite. The variable Nb_Spr.
So I always do "SPR_update(sprites, Nb_Spr);" Nb_Spr always has 5 as value. 1 player sprite + 4 enemy Sprites. The invisible flag let the update doing the work even if Sprite doesn't show anymore.

I think that's work like that. But now I don't have the good Nb_Spr (nomber of sprite)

If I kill two enemy sprites (2 and 3 number sprites). I have an array like that before : SpriteListe(0,1,2,3,4) and after SpriteList(0,1,4,X,X) and (0,1,2,X,X) after sorting frame
I need to use variable who insert the number of sprite Destroy for using SPR_initSprite with the good value : SPR_initSprite(&sprites[newvalue = 3]

i try with the function you post :

Code: Select all

for (i=0; i<=Nb_Spr; i++)
	{
		if (sprites[i].visibility != 1) nb++;
		// do collision test VISIBILITY_ALWAYS_OFF
	}
I don't have the define VISIBILITY_ALWAYS_OFF so I use 1
nb show the good number of sprite hiding. So I can use SPR_initSprite(&sprites[Nb_Spr - nb] ...

I show my solution if it can help other users

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

Re: Theorical question about the sprites

Post by Stef » Fri Oct 16, 2015 8:28 am

And I doesn't decrement the number of sprite. The variable Nb_Spr.
So I always do "SPR_update(sprites, Nb_Spr);" Nb_Spr always has 5 as value. 1 player sprite + 4 enemy Sprites. The invisible flag let the update doing the work even if Sprite doesn't show anymore.
Exactly this ! You should always update all the sprite and hidden ones will be discarded in the update method.
If I kill two enemy sprites (2 and 3 number sprites). I have an array like that before : SpriteListe(0,1,2,3,4) and after SpriteList(0,1,4,X,X) and (0,1,2,X,X) after sorting frame
I need to use variable who insert the number of sprite Destroy for using SPR_initSprite with the good value : SPR_initSprite(&sprites[newvalue = 3]
I understand your problem, what you can do when you collide a sprite is to store its index in a specific variable.
In the case you explain sprite 2 and 3 become free to allocate new sprite, so just use where you store the first free sprite index (here it's 2) and when you want to remove a new sprite just do :

Code: Select all

firstFreeIndex = min(firstFreeIndex, indexReleased)
So firstFreeIndex will always contains the first index in the sprite list where you can allocate a new sprite.
Then when you allocate a new sprite at this position you can calculate the new firstFreeIndex by doing :

Code: Select all

for (i = firstFreeIndex + 1; i <= Nb_Spr; i++)
{
      // not visible ?
      if (sprites[i].visibility == 0x40000000)
      {
          firstFreeIndex = i;
          break;
      }
}

// no more free position
if (i > Nb_Spr) firstFreeIndex = -1;
VISIBILITY_ALWAYS_OFF = 0x40000000 so you can put the value directly, in next version i will make the constant visible.

dub
Very interested
Posts: 101
Joined: Thu Mar 19, 2015 1:26 pm

Re: Theorical question about the sprites

Post by dub » Fri Oct 16, 2015 8:45 am

Fine. I insert that in my code.

dub
Very interested
Posts: 101
Joined: Thu Mar 19, 2015 1:26 pm

Re: Theorical question about the sprites

Post by dub » Mon Nov 02, 2015 2:05 pm

Again I had to make a mistake : The game slow down when I put 80 sprites in screen game.

Image

I've made some different test :
- One sprite player + 79 bullets moving
- One sprite player + 58 bullets moving + two big sprites (Under 128*128 and 20 software sprites)

The max I can draw on screen is 55 sprites whitout slow down.

You can find all my code / assets here (just the necessary for drawing sprites and control the player) : https://www.dropbox.com/s/x4anzykdksv8o ... 3_test.zip

And my simple code : Now is only slow down when you change the MAX_BULLETS value
Inside my code, I init the screen, the sprites and function to move sprites.

I tried to remove the move functions but doesn't change anything. Because of my functions ps_shootControl() and boss_move(), I remove 128 pixels for the non fix32 value.
It's certainly not normal that the game slows down with only 55 sprites while I do not do tests like collisions.

For the SPR_update, I only use the number of sprites "software" made by SPR_initSprite.

Code: Select all

 
#include "genesis.h"
#include "gfx.h"

#define MAX_SPRITE		80

#define ANIM_STAND		0
#define ANIM_UP			1
#define ANIM_DOWN		2

#define MAX_BULLETS		33		//80	//33	//58

u16   Nb_Spr;
//player
fix32 pl_posX;
fix32 pl_posY;

//Boss
s8 dir = -1;

Sprite sprites[MAX_SPRITE];

//init plans with planb black/ plana transparent
void scr_reinit()
{
	VDP_setScreenHeight224();
    VDP_setScreenWidth320();
	VDP_setTextPlan(PLAN_A);
	
	SYS_disableInts();	
	VDP_setEnable(0);
	
	u16 wm = tbackb.w; 
	u16 hm = tbackb.h; 

	VDP_setPalette(PAL0, tbackb.palette->data); 
	VDP_loadBMPTileData((u32*) tbackb.image,  0, wm / 8, hm / 8, wm / 8 ); 
	
	u16 wma = tbacka.w; 
	u16 hma = tbacka.h; 

	VDP_setPalette(PAL1, tbacka.palette->data); 
	VDP_loadBMPTileData((u32*) tbacka.image,  0, wma / 8, hma / 8, wma / 8 ); 
	
	VDP_fillTileMapRect(VDP_PLAN_B, TILE_ATTR_FULL(PAL0, 0, 0, 0, 0), 0, 0, 320 / 8, 224 / 8);
	VDP_fillTileMapRect(VDP_PLAN_A, TILE_ATTR_FULL(PAL1, 0, 0, 0, 0), 0, 0, 320 / 8, 224 / 8);
		
		
	VDP_setEnable(1);
	SYS_enableInts();
	
}


void spr_init()
{
	Nb_Spr = 0;
	
	//player
	pl_posX = FIX32(20);
	pl_posY = FIX32(120);
	
	VDP_setPalette(PAL2, shmup_sprite.palette->data);
	SPR_initSprite(&sprites[0], &shmup_sprite, fix32ToInt(pl_posX), fix32ToInt(pl_posY), TILE_ATTR(PAL2, FALSE, FALSE, FALSE));
	Nb_Spr ++;
	SPR_setAnim(&sprites[0], ANIM_STAND);
	
	
	//boss
	VDP_setPalette(PAL3, boss01.palette->data);
	SPR_initSprite(&sprites[1], &boss01, fix32ToInt(pl_posX)+64, fix32ToInt(pl_posY), TILE_ATTR(PAL3, FALSE, FALSE, FALSE));
	Nb_Spr ++;
	
	SPR_initSprite(&sprites[2], &boss02, fix32ToInt(pl_posX)+192, fix32ToInt(pl_posY), TILE_ATTR(PAL3, FALSE, FALSE, FALSE));
	Nb_Spr ++;
	
	
	
	//creation des tirs
	u8 i,k;
	k = 0;
	//VDP_setPalette(PAL2, tir_sprite.palette->data);
	for (i=3; i<MAX_BULLETS; i++)
	{
		SPR_initSprite(&sprites[i], &tir_sprite, fix32ToInt(pl_posX)+(k*16), fix32ToInt(pl_posX)+(1*i), TILE_ATTR(PAL2, FALSE, FALSE, FALSE));
		k++;
		if (k > 15) k=0;
	}
	Nb_Spr += (MAX_BULLETS - 3);
	
	
	
}


void ps_shootControl()
{
	u8 i;
	for (i=3; i<MAX_BULLETS; i++)
	{
		sprites[i].x = sprites[i].x - 128 + 6;
		sprites[i].y = sprites[i].y - 128;	//fix32ToInt(ps_posY);
		
		SPR_setPosition( &sprites[i], sprites[i].x, sprites[i].y );	//fix32ToInt(160), fix32ToInt(160) );
			
		if ((sprites[i].x-128) > 320)  sprites[i].x = 0;
		
	}
	
}


//Gameplay player sprite
void gp_handleInput()
{
	
	
	//deplacement vaisseau player si dans l'écran
	u16 value = JOY_readJoypad(JOY_1);
	
	if (value & BUTTON_UP)
	{
		pl_posY += FIX32(-2);
		SPR_setAnim(&sprites[0], ANIM_UP);
	} else if (value & BUTTON_DOWN)
	{
		pl_posY += FIX32(2);
		SPR_setAnim(&sprites[0], ANIM_DOWN);
	} else 
	{
		SPR_setAnim(&sprites[0], ANIM_STAND);
	}
	
	//u8 sprBG = scr_spriteBG();
	//u8 sprBD = scr_spriteBD();
	
	if (value & BUTTON_LEFT) pl_posX += FIX32(-2);
	else if (value & BUTTON_RIGHT) pl_posX += FIX32(2);
	
	SPR_setPosition(&sprites[0], fix32ToInt(pl_posX), fix32ToInt(pl_posY) );
	
}

void boss_move()
{

	//Boss move à créer dans include
	if ( ((sprites[1].y - 128) < 0) || ((sprites[1].y - 128) > 120)  )
	{
		dir *= -1;
	}
	
	sprites[1].x = sprites[1].x - 128;
	sprites[1].y = sprites[1].y - 128 + dir;	//fix32ToInt(ps_posY);
	
	sprites[2].x = sprites[2].x - 128;
	sprites[2].y = sprites[2].y - 128 + dir;
	
	SPR_setPosition(&sprites[1], sprites[1].x, sprites[1].y );
	SPR_setPosition(&sprites[2], sprites[2].x, sprites[2].y );
	
}

void gp_JoyHandler( u16 joy, u16 changed, u16 state)
{
    if (joy == JOY_1)
    {
        if (state & BUTTON_START)
        {
            //player 1 press START button
        }
        else if (changed & BUTTON_START)
        {
            //player 1 released START button  

			
        }
		
		
		
		if (changed & state & BUTTON_A) 
		{				
			//ps_shootFire();
		}
		
		
    }
	
	
	
}

int main()
{
    
	JOY_init();
    JOY_setEventHandler( &gp_JoyHandler );
	
	//VDP_setScrollingMode (HSCROLL_PLANE, VSCROLL_PLANE);

	SPR_init(384);	//256);
	
	
	scr_reinit();
	spr_init();
	//src_changeEtatScreen(1);
	//src_loadPlan(scr_Etat);
	
	
	char str[2];
	intToStr(Nb_Spr, str, 1);
	//to verify the transparence
	VDP_drawText(str, 1, 1);
	
    while(1)
    {
		
			gp_handleInput();
			ps_shootControl();
			boss_move();
		
		SPR_update(sprites, Nb_Spr);
		
		
        VDP_waitVSync();		
		
    }
	return (0);
}

I continue my test and add a fps counter with :

Code: Select all

char str[3];
uintToStr(getFPS(), str, 3);
VDP_drawText(str, 1, 1);
I have 60 fps with only 10 in max_bullets. So it's run at full speed with one sprite player + 24 sprites for big boss and 7 bullets sprites so 32 sprites max. If I add one sprite I fall to 30fps. :cry:

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

Re: Theorical question about the sprites

Post by Stef » Mon Nov 02, 2015 10:59 pm

I did not got the time to read your code source but unfortunately currently the sprite engine in SGDK is slow and i'm unfortunately not surprised that you experience slowdown with many sprites. The thing is that the sprite engine does many things for you and the code is in C, which make things slower.
I plan to optimize it in future, and eventually replace the critical section by assembly code...

dub
Very interested
Posts: 101
Joined: Thu Mar 19, 2015 1:26 pm

Re: Theorical question about the sprites

Post by dub » Tue Nov 03, 2015 6:49 am

:cry:
Ok, that's a bad News.

Don't worry for reading my code.

If I don't use the sprite engine, like create sprite And update myself. Could we have fullspeed with 80 sprites ?
Just to Know before going to asm.

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

Re: Theorical question about the sprites

Post by Stef » Tue Nov 03, 2015 9:13 am

You can indeed achieve better performance that way, it's why you still have the VDP_setSpriteXX methods.
I think it would even be faster to use the VDPSprite structure defined in sprite_eng.h then only work from it, but that requires much more work on your side if you want to handle meta sprite and thing like that. The good new is that the structure mimic the internal VDP sprite structure so you can directly transfer by DMA a VDPSprite array to the VRAM to update the sprite list :)

dub
Very interested
Posts: 101
Joined: Thu Mar 19, 2015 1:26 pm

Re: Theorical question about the sprites

Post by dub » Tue Nov 03, 2015 9:32 am

Thanks I will make a try with that.

We always have lot of work to do to make better game.

nolddor
Very interested
Posts: 102
Joined: Sun Jun 02, 2013 1:35 pm
Location: Spain

Re: Theorical question about the sprites

Post by nolddor » Tue Nov 03, 2015 11:16 am

dub wrote::cry:
Ok, that's a bad News.

Don't worry for reading my code.

If I don't use the sprite engine, like create sprite And update myself. Could we have fullspeed with 80 sprites ?
Just to Know before going to asm.

Yes you can reach 60FPS with 80 Sprites on the screen using VDP_setSpriteXXX Methods instead of using SPR_xxx methods.

I did an starfield with 80 sprites on the screen using VDP_setSpriteXXX and the game run at 60FPS

dub
Very interested
Posts: 101
Joined: Thu Mar 19, 2015 1:26 pm

Re: Theorical question about the sprites

Post by dub » Tue Nov 03, 2015 12:05 pm

Yes you can reach 60FPS with 80 Sprites on the screen using VDP_setSpriteXXX Methods instead of using SPR_xxx methods.
I did an starfield with 80 sprites on the screen using VDP_setSpriteXXX and the game run at 60FPS
Thanks is good news. Can you post or show me an existing post with exemples.


I'm making some test and I have one problem.

I just use the VDP_setSpriteDirect or VDP_setSprite but I have only the first sprite draw on screen.

I test VDP_setSprite like :

Code: Select all

VDP_resetSprites(); 
VDP_setSprite  ( 0, 0, 160,    SPRITE_SIZE(2, 2),    TILE_ATTR_FULL(PAL2, 0, 0, 0, 2), 0 ) ;
VDP_setSprite  ( 1, 60, 160,    SPRITE_SIZE(2, 2),    TILE_ATTR_FULL(PAL2, 0, 0, 0, 6), 0 ) ;
VDP_updateSprites(); 
Or with VDP_setSpriteDirect :

Code: Select all

	VDP_setSpriteDirect  ( 0, 0, 160,    SPRITE_SIZE(2, 2),    TILE_ATTR_FULL(PAL2, 0, 0, 0, 2), 0 ) ;
	VDP_setSpriteDirect  ( 1, 60, 160,    SPRITE_SIZE(2, 2),    TILE_ATTR_FULL(PAL2, 0, 0, 0, 6), 0 ) ;
	 

Image
Image

In the picture, I see my 2 sprites in memory and the tiles are well placed but on screen only one sprite appear.

After I'll use the void VDP_setSpriteP ( u16 index, const SpriteDef * sprite) to use the def struct or I'll create mine.

My "light" code :

Code: Select all

u16 wmt = tir_sprite.w; 
	u16 hmt = tir_sprite.h; 

	VDP_setPalette(PAL2, tir_sprite.palette->data); 
	VDP_loadBMPTileData((u32*) tir_sprite.image,  2, wmt / 8, hmt / 8, wmt / 8 ); 
	VDP_loadBMPTileData((u32*) tir_sprite.image,  6, wmt / 8, hmt / 8, wmt / 8 ); 

	

	VDP_setSpriteDirect  ( 0, 0, 160,    SPRITE_SIZE(2, 2),    TILE_ATTR_FULL(PAL2, 0, 0, 0, 2), 0 ) ;
	VDP_setSpriteDirect  ( 1, 60, 160,    SPRITE_SIZE(2, 2),    TILE_ATTR_FULL(PAL2, 0, 0, 0, 6), 0 ) ;
	
int main()
{
    
    while(1)
    {
        VDP_waitVSync();		
    }
	return (0);
}
	

Post Reply