Need help with creating a Sprite Array to pass to SPR_update

SGDK only sub forum

Moderator: Stef

Post Reply
BroOfTheSun
Interested
Posts: 33
Joined: Fri Dec 12, 2014 2:41 am
Location: USA - Chicago, IL

Need help with creating a Sprite Array to pass to SPR_update

Post by BroOfTheSun » Sat Jan 10, 2015 7:23 pm

Hi, I'm having some trouble with the SPR_update() function and creating the Sprite array to pass to that function. I'm trying to create the Sprite array in a way where it is dynamic based on the number of Sprites I want to draw. The Sprite array has memory allocated for a max of 5 sprites. Anyways, here's how I'm trying to do this:

Code: Select all

void SE_SetDrawList(char **drawkeys, int numSprites) {
	Object *obj;
	
	int i;
	int x = 0;
	for( i = 0; i < numSprites; i++ ) {
		if( (obj = Table_Get(tblObjects, drawkeys[i])) != NULL) {
			drawlist[x] = *(obj->sprite);
			SPR_initSprite(&drawlist[x], obj->spritedef, obj->posX, obj->posY, TILE_ATTR(PAL0, TRUE, obj->flipH, obj->flipV));
			x++;
		}
	}
}
Some background info:
- This function will be used to create the initial Sprite array to pass to SPR_update. The array is initialized in another function, and I've allocated enough memory for a MAX# of sprites (5 i think). I want to then add/remove sprites to this array.
- numSprites is the number of sprites I want to draw.
- An Object holds information for an object I want to draw, such as the position, velocity, and pointers to the sprite definition and sprite (I need this for updating positions in other functions). I created a hashtable to hold different objects, and can retrieve object info from this table.
- Drawkeys is a char array, which I can add/remove keys to. I use this char array to control what sprites to add/remove for drawing. I can grab the necessary info by comparing a key to a table of Objects, and grab the Object with the right key.
- drawlist is the array of sprites I need to pass to SPR_update(), and what I'm trying to set in this function. Drawlist is declared as extern in this source file, since it is being used across multiple files. I use drawkeys to lookup the object info, grab the sprite pointer for the object, initialize the sprite, then add the sprite to my array of sprites (drawlist).

First, I don't know why this isn't working with SPR_update. I can get it to work for one sprite, if I remove the for loop and make the following change:

Code: Select all

...
drawlist = obj->sprite;
SPR_initSprite(drawlist, obj->spritedef, obj->posX, obj->posY, TILE_ATTR(PAL0, TRUE, obj->flipH, obj->flipV));
...

Also, I'm sure there are ways to optimize this code, or take another route to drawing my sprites. This is what I've come up with so far. I'm still messing around with the program, and testing out what I can do.

BroOfTheSun
Interested
Posts: 33
Joined: Fri Dec 12, 2014 2:41 am
Location: USA - Chicago, IL

Post by BroOfTheSun » Mon Jan 12, 2015 2:18 pm

In case others are interested, I was able to resolve this issue by changing how I first initialize the sprite list. Before, I was creating it as a pointer. Now, I'm creating it as an array with a fixed length. With some additional changes to code, that seems to work with creating multiple sprites. I can post code if needed.

tryphon
Very interested
Posts: 316
Joined: Sat Aug 17, 2013 9:38 pm
Location: France

Post by tryphon » Mon Jan 12, 2015 4:42 pm

I'm interested by code. I postponed it for the moment but I'm struggling too with the SPR engine :)

BroOfTheSun
Interested
Posts: 33
Joined: Fri Dec 12, 2014 2:41 am
Location: USA - Chicago, IL

Post by BroOfTheSun » Tue Jan 13, 2015 12:26 am

So here's the method I'm using to create the Sprite Array, and pass it to SPR_update(). First, I have a global file where I can declare my sprite array, and an int to hold how many sprites I want to draw. The array has a fixed length. The array holds a number of sprites that I will reference when I need to draw them. Let's call this file Global.h. I use the extern keyword in other source files to reference this sprite array and int.

Global.h

Code: Select all

...
Sprite SpriteArray[NUMOFSPRITES];
int numOfSprites;
...
This Sprite Array is passed to SPR_update() to draw sprites as needed. This code is in the main loop:

main

Code: Select all

...
SPR_update(SpriteArray, numOfSprites);
...
I created a type called 'Object', which includes a sprite pointer, as well as other attributes that I need to update for a sprite such as it's position. When I want to draw a sprite, I simply point the Object's sprite to an unused sprite in the array, and update the numOfSprites to say that I want to draw more sprites in SPR_update().

This function initializes a sprite in the array and points the object->sprite to the array's sprite. I use this for when I want to add a new sprite to draw. It currently requires that I rebuild the sprite array (I haven't built it to simply initialize an unused sprite, but that is work for later). I would use this function to create a new sprite, recreate the sprite array, then pass the array back to SPR_update() to draw the new sprites on screen. Drawkeys is a character array that I use to grab the info I need from an object hash table.

Sprites.c

Code: Select all

...
void SE_SetDrawList(char **drawkeys, int numSprites) {
	Object *obj;
	
	int i;
	int x = 0;
	for( i = 0; i < numSprites; i++ ) {
		if( (obj = Table_Get(tblObjects, drawkeys[i])) != NULL) {
			obj = Table_Get(tblObjects, drawkeys[i]);
			obj->sprite = &SpriteArray[x];
			SPR_initSprite(&SpriteArray[x], obj->spritedef, obj->posX, obj->posY, TILE_ATTR(PAL0, TRUE, obj->flipH, obj->flipV));
			obj->drawListPosition = x;
			x++;
		}
	}
}
...
This is still a work in progress, and has issues. I haven't built a way to check if one of the sprites is already in use, so I have to rebuild the array each time I add a new sprite to draw.

Anyways, I hope this helps. There's still a lot of work I have to optimizing my code for performance and memory usage. This is all just a test atm.

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

Post by Stef » Tue Jan 13, 2015 11:48 am

Actually the sprite engine can handle many things for you and you can basically use a large sprite fixed array where the most used sprites are located at the beginning of the array and less used at end.

So for instance if you know you don't need all the sprites at a certain moment you can just do :

Code: Select all

SPR_update(sprites, currentMaxSprite);
instead of :

Code: Select all

SPR_update(sprites, MAX_SPRITE);
Of course it will be faster as the SPR_update(..) method will parse less sprites but still if you want to "disable" some sprite in the array just do :

Code: Select all

SPR_setNeverVisible(&sprites[3], TRUE);
the the parser will quickly discard them.
Also the SPR_update(..) will only allocate visible sprite (not outside screen) into the VDP memory, you don't have to worry about them... if you put them outside visible screen then they are not allocated in VRAM nor in the VDP sprite list.
Last edited by Stef on Tue Jan 13, 2015 2:44 pm, edited 1 time in total.

BroOfTheSun
Interested
Posts: 33
Joined: Fri Dec 12, 2014 2:41 am
Location: USA - Chicago, IL

Post by BroOfTheSun » Tue Jan 13, 2015 2:34 pm

Thanks for the tip Stef. I'm currently looking at incorporating the visibility int on a sprite within my code. I wanted to use that to control if I want to draw a sprite or not. So it's good to know that SPR_update already takes that into account.

I was also looking at how to best initialize each sprites. Now, I initialize each sprite when I want to draw it. I'm going to try initializing each sprite at the start of my main method, and setting the visibility to 0 so that they are ignored by SPR_update, and do not allocate memory to VRAM.

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

Post by Stef » Tue Jan 13, 2015 2:54 pm

Yeah the initialization process can take a bit of time so you want to avoid it when possible ;) I think it can be nice to initialize the sprite array at level init for instance :

Code: Select all

sprites[0] = HUD / fixed stuff
sprites[1] = player1
sprites[2] = player2
sprites[3] = enemy1
sprites[3] = enemy2
sprites[4] = enemy3
sprites[5] = enemy4
sprites[6] = enemy5
sprites[7] = enemy5
sprites[8] = object1
sprites[9] = object2
sprites[10] = object3
sprites[11] = extra1
sprites[12] = extra2
sprites[13] = extra3
...
so basically you will at least do:

Code: Select all

SPR_update(sprites, 11);
and when required (extra enemy, object and anything) :

Code: Select all

SPR_update(sprites, 15);
Currently the SPR_update(..) method can eat a bunch of time but i plan to optimize it and convert to ASM code to make it faster as definitely this code need to be fast !

Post Reply