cmagoun Posted September 11, 2018 Share Posted September 11, 2018 Greetings, I am just learning pixijs and I have a question: I am experimenting with writing a game, using pixi as the rendering engine. In my game I am trying as best as possible to have the act of drawing be a function of the game state. So, instead of issuing commands and changing the position and texture of individual sprites, I just alter the entities in my game, and the draw system knows how to draw them. Currently, this is implemented by a system that runs in between the game state being updated, and pixi rendering the stage. Something like this: function gameLoop() { requestAnimationFrame(gameLoop); update(); draw(); app.render(app.stage); } Where game draw essentially removes children from the stage, loops through entities that need to be drawn, creates sprites with the correct properties, and re-adds them to the stage. In practice this looks like: draw() { this.container.removeChildren(); const entities = this.game.entities(); entities.forEach(e => { const sprite = this.spriteMap.getSprite(e, this.game.cm); this.container.addChild(sprite); }); } Is there a performance hit to removing/adding sprites to the scene each frame? Is there a better way to do this, while still avoiding having the game logic directly manipulate sprite positions/textures? Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted September 11, 2018 Share Posted September 11, 2018 I use that small snippet in my games. I call it in the end of update iteration. var j = 0; for (var i=0;i<children.length;i++) { if (children[i].dead) { //remove it from animation loop and other things } else { children[j++] = children[i]; } } children.length = j; Quote Link to comment Share on other sites More sharing options...
cmagoun Posted September 11, 2018 Author Share Posted September 11, 2018 Thanks for the reply -- I appreciate any help I can get! Following your example, I changed my scene-drawing code to look like this: drawEntities() { const entities = this.game.cm.entitiesWith("sprite", DIRTY); entities.forEach(e => { const sprite = this.spriteMap.getSprite(e, this.game.cm); if(e.isToBeDestroyed()) {this.container.removeChild(sprite); return;} this.container.addChild(sprite); }); } spriteMap.getSprite handles setting the sprite properties based on the entity's current state. In addition, I added a dirty check on my entities that allows me see ONLY entities that need to be redrawn. In addition, I added isToBeDestroyed() which keeps track of who needs to be removed from the container. I do have one other question: I am using container.addChild when a sprite needs to be redrawn. It doesn't seem like there are any bad effects to adding the same sprite over and over to the container. Indeed, it seems like the length of the container's children stays constant as I redraw. Are PIXI Sprites somehow keyed so as not to be duplicated within a container? I am very pleased that this syntax works, but I am curious. Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted September 11, 2018 Share Posted September 11, 2018 That's completely different code. I recommend to read https://mitpress.mit.edu/books/introduction-algorithms-third-edition . "children[j++] = children" is not addChild. Single removeChild takes O(N) time. Also, "game.cm.entitiesWith" - i dont know anything about it. I work with children of container. Quote Link to comment Share on other sites More sharing options...
xerver Posted September 12, 2018 Share Posted September 12, 2018 To answer your original question: Yes, adding/removing all your sprites every frame is expensive. Instead, track state and only change the minimum amount you have to. If a sprite exists between two frames, then it shouldn't be removed then added again. Ivan's example was to show you he isn't changing the scene tree at all unless he needs to. When something dies, it gets removed. When it is new, it gets added. Otherwise, no change. Quote Link to comment Share on other sites More sharing options...
cmagoun Posted September 12, 2018 Author Share Posted September 12, 2018 Yes, I see that, and based on Ivan's example, I am no longer clearing the scene and then re-adding the sprites. Instead, I am checking for entities that have been changed since the last frame, refreshing their sprite's properties (that is the "getSprite" call). I am still using add/removeChild at the moment, and the performance is fine right now because my scenes are small. I am unlikely to have 100s of moving sprites. My case is a turn-based board-gameish game, so maybe 20 things moving at the most? That means almost no entities are "dirty" in a loop, and I am thus only iterating over the 6 or so things that are moving at any given time. If my situation changes, I will roll up the children array as Ivan showed. Thanks again for the assistance, Chris xerver 1 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.