amshegarh Posted August 30, 2019 Share Posted August 30, 2019 Hello, in my project i need to create a lot of sprites (we talking about 500 + something) every frame and destroy in next but alas, it seems that i dont dispose them properly and framerate drops extremely quickly, albeit at start it seems okayish I add each to some sprites container and clear it with sprites_container.removeChildren(); i dont keep references to sprites Id appreciate help regarding this issue ivan.popelyshev 1 Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted August 30, 2019 Share Posted August 30, 2019 We had that bug in previous pixi versions. What version do you use? Update to latest to v4 or v5. Also if you create 500+ srites every frame, I think you have a problem. Why do you need to do it? Welcome to the forums! Quote Link to comment Share on other sites More sharing options...
amshegarh Posted August 30, 2019 Author Share Posted August 30, 2019 Hey, I use pixi.js - v5.1.2, i need them to render map of the game, its also worth noting that 'Texture.js:445 Texture added to the cache with an id [Image43.png] that already had an entry' error pops up a lot (there are more than just one image), i grab textures from a spritesheet (its loaded only once tho) While there is probably a way to avoid creating hundreds of sprites every second via use of zorder (that i want to not do if possible), they must be created at least once and moved/deleted as map is way bigger than screensize, im afraid that this performance drops sooner or later anyway Quote Link to comment Share on other sites More sharing options...
mobileben Posted August 30, 2019 Share Posted August 30, 2019 I would concur with what Ivan stated. If you're creating and destroying that many objects each frame, you have a problem with approach. Think of game code as a magic trick. You really are trying to make something look a certain way using the minimal amounts of resources possible through "slight of hand". Object creation and removal is generally quite expensive ... hence loading screens ?! You may want to consider keeping references to sprites and reuse what you can. I haven't used Pixi.js enough (I'm just starting with it), but the engines I wrote allow re-binding of textures at a low cost to sprites. To reach your objectives, you probably have numerous ways to reduce object lifecycles. If you better describe what you're trying to achieve someone may be able to help you out more. Also if you're seeing that error, you should try and see if you're trying to add the same object twice. With no real code references, it's not very for people to help. ivan.popelyshev 1 Quote Link to comment Share on other sites More sharing options...
amshegarh Posted August 30, 2019 Author Share Posted August 30, 2019 As I mentioned, i have a map, isometric one, that heavily depends on draw order, while i indeed can create limited amount of sprites and change their positions and textures as needed, it would complicate things as now i'll have to manually track and change z-order, right now i just draw them every game cycle in needed order About error, i create sprites like so let sprite = new PIXI.Sprite(sheet.textures[this.cell(i, j).sprite]); since many sprites share the same texture, that might be the issue(?) this.cell...sprite contains only string name of texture as a side question, can i disable sprite in such a way that it doesnt affect performance (but high number of sprites, like 160k) Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted August 30, 2019 Share Posted August 30, 2019 It looks like more tilemap-related question. Tilemaps have two aspects: Algorithm and drawing element. 1. Algorithm. a) draw all the map. Dont do that. While pixi-tilemap can survive it, everything else cant. And for big maps even pixi-tilemap will go down. b) For tiles that dont change you can use following strategy: fill up the certain window around a camera. When camera touches that window edge, erase everything, make new window and fill it. Its the easiest route to get good performance, but usually people dont undersatnd it from first reading. I have a Graphics beginTextureFill tilemap demo in https://github.com/ivanpopelyshev/pixi-starfighter/tree/master/lesson1_5-tilemap for that c) if you have many changing parts, maybe its better to use Chunks. Chunks are difficult to code, especially for tilemaps - you have to separate map to many Graphics object, add new ones that come in screen, and drop ones that are out of your screen, update ones that has changed elements. I dont have pixi demo, but there's my old canvas2d demo : https://github.com/ivanpopelyshev/bombermine-shuffle , caching through extra canvases. 2. Drawing element. a) Sprites . Yeah, you noticed the problem. Of course you can poll them but it affects architecture in a bad way - if you didnt use pools before, it'll be a problem. b) storing stuff in renderTextures. Yeah, it'll eat memory, and it also can be a problem for isometry and in case you are not familiar with the concept. c) Graphics beginTextureFill - good , balanced solution. d) pixi-tilemap plugin: the fastest. the only downside is that the shader does not use rotations and scaling. Everything is 1:1, cant set different scale for tiles. Quote Link to comment Share on other sites More sharing options...
amshegarh Posted August 30, 2019 Author Share Posted August 30, 2019 I do something similar to 1b, but currently it doesnt work very well. My tiles for the most part shouldnt be changed in game, but supposed to be changeable in real time in map and some point changes can occur. I intend to create a sprite for every tile and set visible of all to false, making visible only those that can be seen, how would that work? Given there are 40k+ tiles. What should i know about 2c? 2d idk if it will suit my demands, tiles will have height associated to them, some tiles will have a texture that covers larger area than their own et cetera Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted August 30, 2019 Share Posted August 30, 2019 2c is "clear, refill" solution. You have to FOR through your tile data and fill that graphics with rectangles. If you use 1b, you shouldnt have 40k+ tiles on screen. Just imagine a window that is 2x times width and height of screen: how many tiles will fit there? I think up to 5k if your tiles are small. Its not that pixi tree is slow, the problem is that you need time to optimize and polish hard solutions. 1b 2c is the default balanced choice that I recommend people. Of course there is a problem: Graphics also creates like 3 extra objects for every rectangle, but its lighter than sprite. In my games I use 1c 2d just because I have enough experience to set it up fast. Quote Link to comment Share on other sites More sharing options...
mobileben Posted August 30, 2019 Share Posted August 30, 2019 Just curious, how many visible tiles typically exist on screen? Is that the 500? Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted August 30, 2019 Share Posted August 30, 2019 I just want to add that its N-th time I'm consulting people with a tilemap, and every time I find something new. Though, its not the first time someone is creating that many sprites each frame Quote Link to comment Share on other sites More sharing options...
amshegarh Posted August 31, 2019 Author Share Posted August 31, 2019 40k is amount of ALL tiles on map, visible are somewhere along 500 mark Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted August 31, 2019 Share Posted August 31, 2019 OK, then, you need to figure out for your case how to reuse sprites (just change "texture" field?) or switch to any other in 2. Also, please provide a demo, because right now i really dont know why is your application slowing down. It shouldn't. We fixed several bugs like that before. Quote Link to comment Share on other sites More sharing options...
amshegarh Posted August 31, 2019 Author Share Posted August 31, 2019 i see, i'll prepare some demo but i'll take time to make code behave similarly to how it works right now Quote Link to comment Share on other sites More sharing options...
amshegarh Posted August 31, 2019 Author Share Posted August 31, 2019 Here you go, https://pastebin.com/9xpvVRa3 this is dumbed down version with pretty much only rendering, idk if it even runs, but it should be affected in the same way as my project Data files in case you actually want to start it https://drive.google.com/open?id=1GG1Liec4JoK1urjtW1yIeFePgadIMkkA Quote Link to comment Share on other sites More sharing options...
amshegarh Posted September 1, 2019 Author Share Posted September 1, 2019 Ok there is another issue, i set z-index of sprites, but some still overlap others, despite clearly having lesser zid (i must specify that there are rows of sprites with the same zid, but sprites from the same row can never overlap) Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted September 1, 2019 Share Posted September 1, 2019 Did you enable sorting inside container? Also, sorting tiles can be one more performance problem later. Quote Link to comment Share on other sites More sharing options...
amshegarh Posted September 2, 2019 Author Share Posted September 2, 2019 ok it works now, but why it can be an issue later? does zindex is costly performance wise? Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted September 2, 2019 Share Posted September 2, 2019 any change in zIndex or adding/removing sprites can trigger a sort once a frame. Nothing special, it just javascript sort is kinda slow Also zIndex never works for grandchildren, because it sorts only children of a container. In general, I recommend not to create 500 sprites every frame (60 frames per second). Sprites are lightweight , there are like only 10 objects per sprite, and tens of thousand sprites in a frame are fine, but big per-frame creation just clogs the GC. Quote Link to comment Share on other sites More sharing options...
mobileben Posted September 2, 2019 Share Posted September 2, 2019 One thing you may want to try and do is some more research regarding tile map engines. There are probably some GitHub repos for some. This way you can better learn how others are doing it. I have built tile map and scrollers a while back. The engine core itself was very different, since the engine was C++/OpenGL and specialized to handle it. Whereas in your case, you're using an existing engine and its methods to draw. If you are still truly destroying/creating 500 sprites per frame, you should rewrite your algo now. You definitely want to have a sprite pool you render from. Think of the problem as paging in 1-2 rows or columns. For most cases, those are your deltas. Take the simplified case of moving in the X axis. In this case, as you move to the right, for example, you will eventually hit the point where you will need to page in a column to the right. You can achieve this by simply grabbing the leftmost column and rebinding the texture (no destruction or creation) and updating positioning. Note at this moment I'm ignoring z order. The trick here is your overall tile area needs to be larger than your viewport so one doesn't see either side pop in or out. Now much overdraw will be dependent on individual tile size and the max speed you need to scroll through your map. Your "worse case" will be 2 dimension movement where it triggers both row and column swapping. However if you think about the problem more. You are no longer modifying 500 sprites. Rather in your case, about 150 sprites. Note in your code, you do far more than 500 sprites, you're doing 1250 sprites, but for consistency I'll use 500 as the high end number. This means that for the 350 other sprites, they should be "correct" and don't need adjustment. Now you have to address z order. You could opt to re-build z-order each round. The problem area really are when you need to insert versus append/push, since depending on implementation, that will move memory (unless it's a linked list ... I have't looked at the code). If it is a linked list, then it should be relatively cheap, but based on Ivan's comment, it sounds like it is not. One partial "cheat" you could do for draw order too is to have layer containers in your master container, and use that for your z. Note you'll still need to sort that. The other thing is clever art usage can minimize how much sorting is needed. A thing to look out for is how non-world objects interact. So, for example, if characters can look like they are "behind"/occluded by tiles, you need to have a method to control that draw order. In short: - Look for other tile engines and see if you can find some code to study. You want approach, engine type doesn't matter so much. You need to understand the basics of that type of engine more. - Don't destroy/create per frame. Reuse. In general this is a good rule. If you find yourself creating and destroying objects a lot during normal runtime, you should scrutinize your technique. This is not to say you never can do it. I do have some games where I actually create and destroy on the fly but it is for a handful of objects on a custom C++ engine. - Embrace object management. This is the unfortunate responsibility of the game dev. Sure you want to try and avoid it when possible, but world management ... in particular ones which incorporate a lot of animating visuals need to be managed. ivan.popelyshev and amshegarh 2 Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted September 2, 2019 Share Posted September 2, 2019 I say, just write something else and see if it works mobileben 1 Quote Link to comment Share on other sites More sharing options...
amshegarh Posted September 2, 2019 Author Share Posted September 2, 2019 Very helpful tips, thanks! I changed the way rendering goes, now i create all sprites beforehand(a drawback is that loading is already noticeable, even tho no real sprites are used yet) and put most of them as .visible = false, works rather fine right now, might need reconsidering later. Also, as i said, i already did rendering based on current viewport position, it just didnt make it into demo because i thought it was mostly irrelevant Quote Link to comment Share on other sites More sharing options...
mobileben Posted September 2, 2019 Share Posted September 2, 2019 It isn't unusual for setup to take time. If you don't support loading screens, you may want to consider it now. I only cite this because it does affect some flow and it's often easier to stub it in sooner versus later. Quote Link to comment Share on other sites More sharing options...
amshegarh Posted September 3, 2019 Author Share Posted September 3, 2019 Alright there is another issue, pivot seems to work weirdly(?) i need to set up rotation point in sprite while also having custom anchor, but it just doesnt work the way i expected example: https://www.pixiplayground.com/#/edit/NGUb4kYSI8DXK6O4X5Jmz bunny2 should keep its position, but rotate 90 degrees around pivot point (its centre) but it just does some nonsense :: Apparently after rotation sprite uses original anchor to position itself, this is not ideal but i can work with it Quote Link to comment Share on other sites More sharing options...
Exca Posted September 3, 2019 Share Posted September 3, 2019 Anchor & pivot both affect how rotation happens. You could overcome this by having container and apply pivot point to it and then put the sprite with custom anchor inside it. There might also be some way how to handle that with matrixes or without second container but my knowledge in pixi inner workings is not good enough to suggest anything. Quote Link to comment Share on other sites More sharing options...
JeanLouis Posted September 9, 2023 Share Posted September 9, 2023 In case someone search some answer in this thread one day, Had quite the same problem while dealing with some isometric tile map. I use chuncks of 40x40 tiles, 58x30 pixel each. and I always keep 9 chunck (the one I am looking, plus radius 1 around). Problem is, how do you manage scrolls on the map ? Do you move sprites ? Do you delete them and create new ones ? Do you use some kind of pool of sprites, which you move and hide or show following your needs ? Do you just keep sprites where they are and change they texture ? Here are some tests and performance (on each test, textures are always preloaded). Option 1 (20 to 80 ms each frame) - Each time I need a new chunck, servers send 1600 tiles (40x40), client creates 1600 tiles from textures. When you scroll, the containers are moved using container.x += some value. When a chunck is not needed anymore because too far from camera, delete 1600 sprite and the containers they are grouped in. Option 2 : (0 to 30 ms each frame) - Almost exactly the same than option 1 except that I keep a pool of sprites. When a new chunck is created and need some tiles, it first search in a pool of sprites if somes are already available. If not, the algo create a sprite. When a chunck is deleted, the container is deleted but the 1600 sprites are added to an array containing my pool of sprite. Option 3 : (2 to 4 ms each frame). - I create a scheme of sprites (one per tile) which basically covers all of my screen. They never move, they are created once, and never deleted. Each time I want to scroll, I loop over each sprite and I search in some kind of data structure what kind of ground should be displayed in this sprite (land, shore, water). Once I have this value I just change the texture of the sprite using sprite.texture = "some value"; Fastest is to create sprites in the very beginning and just change their textures. Hope it will helps some future game makers ! 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.