MicahHauge Posted July 31, 2016 Share Posted July 31, 2016 Hey guys! I'm pretty new to this forum and to PIXI.js so please excuse me if I'm posting in the wrong place. I am creating a game similar to guitar hero, but for piano (basically a synthesia clone). Here is a link to my JSFiddle I have the basics setup how I want, but I am running into some performance issues. I need the game to run at a solid framerate with up to ~10,000 notes in a level (not all being displayed at the same time of course). Currently, the note graphics are created and added to the stage within a group and animated downward. When they are added, their visible property is set to false and is only set to true when the are within the view. Here is my animation loop: function animate() { gameTime = performance.now() / 1000 - startTime; // CULLING loop // loop to go through all notes and see if they should currently be visible for (i = 0; i < numNotes; i++) { // if the note should be visible, make it visible if (gameTime + offset > notes[i].startTime && gameTime < notes[i].stopTime + offset) { if (notes[i].graphic.visible == false) { notes[i].graphic.visible = true; } } // if the note should not be visible, set visible to false else if (notes[i].graphic.visible == true) { notes[i].graphic.visible = false; } } // set y pos based on gameTime group.y = (ySlope * -1 * gameTime); // or set it manually // group.y += 8; renderer.render(stage); requestAnimationFrame(animate); } The frame rate is currently not where I want it to be, so I am hoping that someone can show me where I can make some optimizations. Feel free to play around with the JSFiddle. Thanks, Micah Quote Link to comment Share on other sites More sharing options...
Fatalist Posted July 31, 2016 Share Posted July 31, 2016 Use sprites instead of Graphics. To create texture from Graphics -> https://pixijs.github.io/docs/PIXI.Graphics.html#generateTexture Quote Link to comment Share on other sites More sharing options...
MicahHauge Posted July 31, 2016 Author Share Posted July 31, 2016 @Fatalist I followed your recommendation of using sprites instead of Graphics but it still stutters. Here is a link to the updated JSFiddle. Please let me know if I can make any further optimizations. Thanks, Micah Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted July 31, 2016 Share Posted July 31, 2016 Please use the same texture for all the sprites. Current implementation creates new texture for every sprite. Quote Link to comment Share on other sites More sharing options...
Milton Posted July 31, 2016 Share Posted July 31, 2016 You're doing for (i = 0; i < numNotes; i++) { ... } every frame. I'm sure you can optimize that to about 100 sprites instead of 15000. Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted July 31, 2016 Share Posted July 31, 2016 @Milton I think it can handle that, but different textures issue is main problem MicahHauge 1 Quote Link to comment Share on other sites More sharing options...
MicahHauge Posted August 1, 2016 Author Share Posted August 1, 2016 @Milton @ivan.popelyshev I think that is a great recommendation but notes must be able to have varying lengths like so: JSFiddle. Because of this, it makes a sprite for every note. Would sprite batching help in this situation? Or is there some way that I can adjust the length of a sprite without messing up dimensions? Thanks, Micah Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted August 1, 2016 Share Posted August 1, 2016 1 hour ago, MicahHauge said: @Milton @ivan.popelyshev I think that is a great recommendation but notes must be able to have varying lengths like so: JSFiddle. Because of this, it makes a sprite for every note. Would sprite batching help in this situation? Or is there some way that I can adjust the length of a sprite without messing up dimensions? You can create three textures out of one: one for the top, one for middle and one for bottom. Then for each note, create three sprites, adjust the height of second sprite. Look at Texture constructor to understand what I mean: https://github.com/pixijs/pixi.js/blob/dev/src/core/textures/Texture.js . you can make one texture out of other this way : var demoTex = new Texture(oldTexture.baseTexture, new PIXI.Rectangle(x, y, width, height)); //create three textures there: ... //and now create a note var note = new PIXI.Container(); note.addChild(new PIXI.Sprite(topTexture)); note.addChild(new PIXI.Sprite(middleTexture)); note.addChild(new PIXI.Sprite(bottomTexture)); node.children[1].position.y = 10; node.children[1].height = noteHeight - 20; node.children[2].position.y = noteHeight - 10; Please create only three textures, don't do 10000*3 MicahHauge 1 Quote Link to comment Share on other sites More sharing options...
MicahHauge Posted August 1, 2016 Author Share Posted August 1, 2016 @ivan.popelyshev Thank you for your quick and helpful response. I adjusted my code so that only one texture is created and used for all the sprites. Here is a link to the JSFiddle. It seems a bit faster, but unfortunately stuttering is still occurring. Because of this, I have not yet implemented your three texture approach so all note lengths are the same. I would like to get it running smoothly with fixed note lengths before adding the functionality for variably lengths. Any idea why it is still stuttering? Thanks again for your help, Micah Quote Link to comment Share on other sites More sharing options...
Milton Posted August 1, 2016 Share Posted August 1, 2016 I think your idea of just adding 15000 sprites to a container and scrolling that is not very optimal. Only add them when needed (visible, maybe index them on startTime?). That means your loop will also be optimal, instead of the 15000 you're doing now. Quote Link to comment Share on other sites More sharing options...
Fatalist Posted August 2, 2016 Share Posted August 2, 2016 17 hours ago, MicahHauge said: It seems a bit faster, but unfortunately stuttering is still occurring. I thinks that's because of browser vsync problem. If anybody knows how to fix that - would love to know how. Such small stuttering is apparent on every example of scrolling I've seen. In real games it's usually not noticeable because usually there are more visual elements and movement is not constant and linear. Now if you're making something like Piano Tiles - then it is going to be noticeable probably... Quote Link to comment Share on other sites More sharing options...
Milton Posted August 2, 2016 Share Posted August 2, 2016 3 minutes ago, Fatalist said: I thinks that's because of browser vsync problem. Please. The 'problem' is with the insane "let's just add 15000 sprites to a container, and scroll that'". There is no need for scrolling. Only draw the sprites needed, and you can pull this of on a Z80. This is just bad programming. Quote Link to comment Share on other sites More sharing options...
Fatalist Posted August 2, 2016 Share Posted August 2, 2016 17 minutes ago, Milton said: Only draw the sprites needed That's exactly what that code does. It runs at 60fps, but visually, stutters a little, every few seconds. It may not happen on every browser/OS/hardware. Quote Link to comment Share on other sites More sharing options...
Milton Posted August 2, 2016 Share Posted August 2, 2016 Nope. It draws all 15000 of them on a container, and then loops all 15000 of them each and every frame, playing around with visibility. I couldn't think of a more stupid solution... I can write this on a C64 with 60 FPS... Quote Link to comment Share on other sites More sharing options...
Fatalist Posted August 2, 2016 Share Posted August 2, 2016 6 minutes ago, Milton said: playing around with visibility Setting visible to false = not drawing the sprite. Quote Link to comment Share on other sites More sharing options...
Milton Posted August 2, 2016 Share Posted August 2, 2016 9 minutes ago, Fatalist said: Setting visible to false = not drawing the sprite. Duh. That doesn't help the container that has already had 15000 sprites added to it. Let's increase the notes to 1 million. You're just going to add them up front? What game adds all 'enemies' up front? Add them when needed... Quote Link to comment Share on other sites More sharing options...
Fatalist Posted August 2, 2016 Share Posted August 2, 2016 23 minutes ago, Milton said: Duh. That doesn't help the container that has already had 15000 sprites added to it. So PIXI needs to loop through 15000 objects every frame and check the .visible property. 15000 checks is not that many. If it was million - then yeah, something more complex would be needed. Anyway, FPS is not a problem here - that code should run at 60fps pretty much everywhere. Quote Link to comment Share on other sites More sharing options...
Milton Posted August 2, 2016 Share Posted August 2, 2016 Complex? Just index on startTime. That way you only loop the needed notes. About a 100 or so. Who cares how many notes there are. A trillion still doesn't matter. If you need to lookup Zygote in a dictionary, do you start at Aardvark? The stutter is because of scrolling a huge container containing 15000 sprites, and checking 15000 objects every frame. You can't write it worse... Quote Link to comment Share on other sites More sharing options...
MicahHauge Posted August 2, 2016 Author Share Posted August 2, 2016 @Milton Thank you for this recommendation. I have adjusted my code so that the sprites are only added to the stage when they should be visible, and are removed from the stage otherwise. Here is a link to the JSFiddle. It now runs much smoother than it did before, but stuttering still occurs occasionally. You are right in that it would run faster if the loop did not check every note in the array each frame, but am having a bit of trouble implementing this. What do you mean by index on startTime? The array of notes is already sorted by startTime (least to greatest) if that makes it easer. Feel free to play around with the JSFiddle and post your changes. Quote Link to comment Share on other sites More sharing options...
MicahHauge Posted August 2, 2016 Author Share Posted August 2, 2016 4 hours ago, Fatalist said: It runs at 60fps, but visually, stutters a little, every few seconds. It may not happen on every browser/OS/hardware. This is true. It isn't a constant poor frame rate, it is just a stutter every few seconds. I have noticed that it runs better on Windows than it does on Mac OS and Linux. Also, There is a small amount of stuttering occasionally even when only ~100 note objects are created, especially on Linux. This may be due to most linux drivers having poor WebGL support though. Quote Link to comment Share on other sites More sharing options...
Fatalist Posted August 2, 2016 Share Posted August 2, 2016 I just tested on Android and it's perfectly smooth. https://www.vsynctester.com/ - If a browser does not pass this test, then it's going to have some stutter, even with one sprite. Quote Link to comment Share on other sites More sharing options...
Milton Posted August 2, 2016 Share Posted August 2, 2016 I'm not going to do your work You learn by doing it yourself. You have an array of notes that you can't access by startTime (only by a useless counter). Let's say you use notes[startTime].push(note). Make sure startTime starts with 0 (and is an integer), just so you don't get a crazy big array. That way you can just loop from notes[gameTime] to notes[gameTime + screenHeight]. Where gameTime == 0 means the first note(s). (I assume every 1 gameTime is 1 Y pixel, don't know if that's true...) And I wouldn't scroll the container, just keep a Y position, and draw the notes at the right positions (try implementing UP/DOWN instead of using gameTime) . Like a vertical 'scrolling' game. Enemies don't scroll, only background maps do. Your container should be no bigger than your viewport. That should definitely fix any stutter. MicahHauge 1 Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted August 2, 2016 Share Posted August 2, 2016 I dont think removeChild/addChild helped a lot, only a bit. The problem is that you are somehow creating too many objects. You have to profile your memory and fine where is it "leaking". Though, it is not a leak, it is just GC overuse UPD. I'm wrong, everything is ok with your memory. UPD. "else if (notes[ i ].inStage) { group.removeChild(notes [ i ].sprite); }" you forgot "notes [ i ] .inStage = false" there. But that's small thing MicahHauge 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.