Jump to content

Designing a robust and efficient architecture for grouping sprites in PIXI.js stage


caymanbruce
 Share

Recommended Posts

When I first use PIXI.js I used to put every sprite onto the stage. Then I know that there is a Container class to hold the sprites. So I can add some sprites onto one container and other sprites to another container. After that I can add all the containers onto the stage and PIXI.js will handle the drawing for me. This is a very smart idea because I can use it to group sprites that I may want to scale together or delete together. But on some occasions I still have questions putting them together because I am afraid I may have a bad design. If deleting a container means it also delete everything inside the container, is it a good design to put sprites into a container if I want to delete them as a whole in the future? Does the computer need more resources if I use many levels of containers in my game?

For example, if my player have several segments or several parts, like a plane with some shield or small added laser guns, is it better to group them into one container or just put them into the parent container? If I am building a train, is it better to put all the carriages of the train into a container as a whole, meaning the train is a container, or put them into the parent container?

If robustness and efficiency are the main concern, what design rules should I follow?

Link to comment
Share on other sites

That is more easy to manage sprite positions by grouping them in a container.

Invoke Destroy on a container don't destroy children by default :

http://pixijs.download/dev/docs/PIXI.Container.html#destroy

If you are making a car you won't move the wheels and the car's body distinctly. You shouldn't move all pieces of a gameObject, that is more easier to move only one object.

Link to comment
Share on other sites

I found that running Sprite.destroy() against every object whether its in a container or not is the only safe way to ensure an object is deleted. The reason being you may have a reference to that child object in an object somewhere, and therefore deleting the container that holds that child would cause some failures/bugs in code.

So for example what I do is; everything I draw to pixi, I add a reference to that sprite in an array, e.g. world = []; and then world.push(sprite); Once I'm ready to clean up I run a loop over the array and run the world.destroy() function for each, then clean up the array be just writing world = [];

Therefore, in your train example I would do like so in pseudo code:

train = pixi.container();

trainSprites = [];

createTrain = function() {

sprite1 = new pixi.sprite()....

train.addChild(sprite1);

trainSprites.push(sprite1);

sprite2 = new pixi.sprite()....

train.addChild(sprite2);

trainSprites.push(sprite2);

stage.addChild(train);

};

destroyTrain = function() {

for(var i=0; i < trainSprites.length; i++) {

trainSprites[i].destroy();

}

train.destroy();

trainSprites = [];

};

 

-

 

This would allow you to move all the sprites at the same time by setting train.x, train.y, and when you're ready to destroy it, you run destroyTrain(); which destroys the sprites, resets the array containing sprites, and destroys the container.

Link to comment
Share on other sites

5 hours ago, Jammy said:

I found that running Sprite.destroy() against every object whether its in a container or not is the only safe way to ensure an object is deleted. The reason being you may have a reference to that child object in an object somewhere, and therefore deleting the container that holds that child would cause some failures/bugs in code.

So for example what I do is; everything I draw to pixi, I add a reference to that sprite in an array, e.g. world = []; and then world.push(sprite); Once I'm ready to clean up I run a loop over the array and run the world.destroy() function for each, then clean up the array be just writing world = [];

Therefore, in your train example I would do like so in pseudo code:


train = pixi.container();

trainSprites = [];

createTrain = function() {

sprite1 = new pixi.sprite()....

train.addChild(sprite1);

trainSprites.push(sprite1);

sprite2 = new pixi.sprite()....

train.addChild(sprite2);

trainSprites.push(sprite2);

stage.addChild(train);

};

destroyTrain = function() {

for(var i=0; i < trainSprites.length; i++) {

trainSprites[i].destroy();

}

train.destroy();

trainSprites = [];

};

 

-

 

This would allow you to move all the sprites at the same time by setting train.x, train.y, and when you're ready to destroy it, you run destroyTrain(); which destroys the sprites, resets the array containing sprites, and destroys the container.

Thanks. Suppose I use ES6 ( I like to use ES6 ). If I have a Train class in which I draw the sprites, I can just pass in the parent container, such as "gameScene" or even "stage" to add the sprites as its children. Looks like I don't need to create another Train container in my Train class. Is there any good reason that I have to use a new container in my Train class?

Link to comment
Share on other sites

You're right you really dont have to have the container if you're referencing all the sprites. The only real benefit to the container is if you want to update all the sprites positions/rotations/visibility/mask etc at once, e.g. setting the containers x and y will move all the sprites, whereas without the container you'd have to update each sprite individually.

Link to comment
Share on other sites

Furthermore, what I use containers for in my project is, just basically layers... I have one container for the background and stick all my tiles in there, i have another container for my foreground and stick all my objects in there, then i have one for my UI and i put all my UI elements in there. The benefit of doing this means I can "Pan" my viewport (camera) and basically offset every container except the UI container

Link to comment
Share on other sites

5 minutes ago, Jammy said:

You're right you really dont have to have the container if you're referencing all the sprites. The only real benefit to the container is if you want to update all the sprites positions/rotations/visibility/mask etc at once, e.g. setting the containers x and y will move all the sprites, whereas without the container you'd have to update each sprite individually.

 

2 minutes ago, Jammy said:

Furthermore, what I use containers for in my project is, just basically layers... I have one container for the background and stick all my tiles in there, i have another container for my foreground and stick all my objects in there, then i have one for my UI and i put all my UI elements in there. The benefit of doing this means I can "Pan" my viewport (camera) and basically offset every container except the UI container

Very good point. Maybe I should do that too. I always want to have control to individual sprite so maybe it is unnecessary to use a Container for each player which contains a group of sprites. But if I do use it. I want to know if there is any additional cost? Consider maybe I will have 800 players on the map, which means 800 containers if I use it for each player. I have a vague perception that maybe it's better to reduce the number of containers in the game. 

Link to comment
Share on other sites

Hmm yes.. So I think using containers if in terms of pixi you just have to imagine is probably the same amount of memory as a Sprite, as for updating a container vs a bunch of sprites I'm not actually too sure which is better for performance. I'm also not sure either if having a container impacts draw time. Something I would be interested in knowing myself but it would take a hefty well thought through test to check I think unless the authors get involved.

I hope this video will give you a good idea of how many sprites/objects I'm working with - that aren't within containers (and hopefully it'll put your mind at ease with any performance concerns). https://www.youtube.com/watch?v=8seAgMmY7N0

The video is recorded on my machine which is a bit meatier than the average, but on my old lenovo laptop (4gb ram, i3 2ndgen, 96cuda core) with the same test i find 30+ fps which is nice.

I think the fact you've picked pixi means you can really get a f**k ton of sprites on screen, and then find loads of ways to optimise later, such as cacheAsBitmap, containers, etc.

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...