Welcome Guest! To enable all features please Login or Register.

Notification

Icon
Error

2 Pages12>
Options
Go to last post Go to first unread
Offline internetfreak  
#1 Posted : Tuesday, May 28, 2013 8:43:35 PM(UTC)
internetfreak

Joined: 12/19/2011(UTC)
Posts: 529

Thanks: 10 times
Was thanked: 16 time(s) in 15 post(s)
Hello everyone,
I'm currently working on something which has to do with tilemaps and I already have functional code which actually render it. Now I only have one problem: Due to the entity system, each Sprite gets immediately added to the entity system but it never gets removed from there to be rendered so with the time I collect many Sprites (over 4-5k) so my FPS obviously drop.
I want to avoid that but I also want a clean solution to do that and here's my problem: How can I achieve the best result?
One thought I already had was to create 3 Sprites (one for each layer, I want to use 3 layers for tiles) which are logically rendered on the same position but with different renderlayers so they seem to overlay themselves.
To have 3 sprites is in my opinion a bit dull, too much sprites. Ealier, when 0.9.5 and lesser were actual, I always fetched a texture loaded with the ContentManager and created a Material2DColored which I then added to the Renderer (I used the Draw() Method since each Material2DColored was able to "draw" itself). Now the Sprite only supports one Image at a time and switching the images on existing sprites is not possible because a Sprite is a class and therefore a reference type so I only change one tile and end up with only one tile due to the fact that the rendering system of delta does not add entites which are already added to the rendering list.

How could I still be able to render my tiles and use as less sprites as possible? I currently store the index of the used tile image to get it from the list of available images and create the sprite with that information and the position of the tile.

I hope it's understandable what I want. One note, I want to stay as clean as possible so I rather want to use things the engine already has instead of deriving engine type to alter their behaviour. Maybe it's possible to clear the rendering list each frame?
Mein Blog: www.internetfreak.net

- Inoffizieller DeltaEngine-Supporter und Tutorialschreiber -

Wanna join the discussion?! Login to your forum accountregister a new account. Or Connect via Facebook Twitter Google

Offline elasto  
#2 Posted : Wednesday, May 29, 2013 3:17:03 AM(UTC)
elasto

Joined: 8/23/2011(UTC)
Posts: 245

Thanks: 6 times
Was thanked: 12 time(s) in 11 post(s)
Hi internetfreak

I'm not sure I follow exactly what you are looking to do but here's a couple of thoughts on what you've said:

Quote:
Due to the entity system, each Sprite gets immediately added to the entity system but it never gets removed from there to be rendered so with the time I collect many Sprites (over 4-5k) so my FPS obviously drop.


Previously Entities were not added to the EntitySystem by default and now they are - this is because probably 95%+ of the time someone creates an Entity they actually want to make use of it straightaway. However, it's still possible to add and remove Entities from the EntitySystem on demand (including at creation) by simply changing the IsActive flag:

var sprite = new Sprite(...) { IsActive = false }; // Creating a sprite that does not render


var sprite = new Sprite(...); // This sprite is rendering
...
sprite.IsActive = false; // We stop this sprite rendering



You should not be seeing any framerate drop over time so long as you are inactivating sprites that are no longer wanted.

---

On a side-note, though it isn't really applicable here, if you wanted the Sprite to stay active in the EntitySystem but not render - let's say it had some internal values it was updating - eg. the Sprite is an enemy creep that has health that is regen'ing - instead of setting it to inactive you could just remove the Render EntityHandler:

sprite.Remove<Sprite.Render>(); // Stops this sprite rendering but all other handlers keep on processing
...
sprite.Add<Sprite.Render>(); // Restarts rendering of this sprite


(Looking at this, I think I might like to change the names of those methods; I think the following reads more natually:

sprite.Stop<Sprite.Render>(); // Stops this sprite rendering but all other handlers keep on processing
...
sprite.Start<Sprite.Render>(); // Restarts rendering of this sprite


Maybe expect to see that changed in the next couple of releases!)

---

Quote:
Now the Sprite only supports one Image at a time and switching the images on existing sprites is not possible because a Sprite is a class and therefore a reference type so I only change one tile and end up with only one tile due to the fact that the rendering system of delta does not add entites which are already added to the rendering list.


I don't entirely follow but let me attempt to answer:

To start with, changing the image on an existing Sprite is possible and easy, it's just:

sprite.Image = content.Load<Image>("New Image");

Yes, you can't add the same entity more than once, but you wouldn't want to. A Sprite can only be in one place at a time; You can't render one Sprite in multiple places in a single frame.

What I think you're getting at is you're worried about having lots of Sprites all using the same Image, worrying that it'll be inefficient - but don't worry, Images are cached; If two Sprites have the same Image they share it; the Image hasn't been loaded twice or stored twice internally or anything. And if two Sprites start with the same Image you can make one have a different Image without affecting the other.

Using two Sprites with the same Image is very much like making two Material2D draw calls with the same Material2D. So just go ahead and create as many Sprites as you need.


Hope this helps clear a couple of things up :)

Edited by user Wednesday, May 29, 2013 3:31:54 AM(UTC)  | Reason: (Code tags were acting weird so had to change to italics!)

Offline internetfreak  
#3 Posted : Wednesday, May 29, 2013 9:32:23 AM(UTC)
internetfreak

Joined: 12/19/2011(UTC)
Posts: 529

Thanks: 10 times
Was thanked: 16 time(s) in 15 post(s)
Hey PG, thanks for your answer
It seems that I expressed my problem a bit too confusing, sorry for that :D
Your answer is still helpful but it doesn't solve everything. Some of your details (like cached content) are already known by me, others are new.
Anyway, here's again my problem, this time a bit better ;)

I have a tilemap, let's say it's 20*15 tiles big. Each tile (I call it Cell because it fits the meaning better than "tile") has a position. I also have three layers for images to create a look like in other RPGs where there's the ground and on the ground there's a house or a tree or something else. Each cell has currently three integers (one for each layer) referring to the index of the image which is used on that layer (Images are stored differently in another class).
Earlier, I only needed to iterate through all cells (or at least all visible cells but I didn't have any camera class so it was basically all cells which were iterated and therefore I only used map dimensions which fitted the window) and get the texture index to resolve what image I need to draw. With that image, I created a Material2DColored, set the position to the position of that cell and changed the renderlayer of each material according to the layer it should be and drew it using Draw(). In the end, I got my desired result (I also have screenshots from that moment on my blog and also here in the forum but I think you know what I mean ;) )

Now with the Sprite class, I would basically do the same (and the only change would be that I have to add it to the renderer). The problem is that the Sprite class is now an entity and I have no control about rendering like before where I could be sure that the rendering list is empty and only all things are drawn which I added to the list.
With that problem in mind, I need to improve my code design. I could simply create 3 Sprites per cell to have all cells and their respective sprite but imo it's a bit too messy regarding memory etc even though the images are only loaded once.
I also would have to deactivate all sprites first and only activate all entites of the cells which are eligible for drawing (i.e those which are at least partly visible on the screen). It's a bit too much in my eyes and I have thoughts about performance if I have to compute visible cells each frame.
What I need is therefore something which could act like before so I can create only sprites for the visible cells and add them for rendering. That's the reason why I asked


I hope it's a bit more clear this time, I'm german and I have some problems to write in english (it works the most time but there are also times where I have trouble to write what I want to say)
I also don't like to get too technical about my projects first (all my projects are treated as secret until I decide it's time to release more informations) and that's why I often try to express my problems in a more general way, the disadvantage is often that my text is too confusing ;)
Still I hope you or someone else can help me, you can also contact me per PM or IM and I will probably share some more details with you (I don't want to do it in the publicity because it should be a surprise what I'm currently doing^^)
Mein Blog: www.internetfreak.net

- Inoffizieller DeltaEngine-Supporter und Tutorialschreiber -
Offline elasto  
#4 Posted : Wednesday, May 29, 2013 1:23:18 PM(UTC)
elasto

Joined: 8/23/2011(UTC)
Posts: 245

Thanks: 6 times
Was thanked: 12 time(s) in 11 post(s)
Originally Posted by: internetfreak Go to Quoted Post
I have a tilemap, let's say it's 20*15 tiles big. Each tile (I call it Cell because it fits the meaning better than "tile") has a position. I also have three layers for images to create a look like in other RPGs where there's the ground and on the ground there's a house or a tree or something else. Each cell has currently three integers (one for each layer) referring to the index of the image which is used on that layer (Images are stored differently in another class).
Earlier, I only needed to iterate through all cells (or at least all visible cells but I didn't have any camera class so it was basically all cells which were iterated and therefore I only used map dimensions which fitted the window) and get the texture index to resolve what image I need to draw. With that image, I created a Material2DColored, set the position to the position of that cell and changed the renderlayer of each material according to the layer it should be and drew it using Draw(). In the end, I got my desired result (I also have screenshots from that moment on my blog and also here in the forum but I think you know what I mean ;) )


Sure, if you want to do it this way, it's a little bit messier than before but you still can.

If you look at what Sprite.Render does, it's not very complicated and you can imitate it. Basically, instead of calling Material2D.Draw you call Drawing.DrawQuad. You will also need to copy the method logic to convert the quadratic coordinates to screen coordinates (actually vertices). (And then you've basically cloned Sprite.Render because that's all it does...)

Quote:
Now with the Sprite class, I would basically do the same (and the only change would be that I have to add it to the renderer). The problem is that the Sprite class is now an entity and I have no control about rendering like before where I could be sure that the rendering list is empty and only all things are drawn which I added to the list.


I get what you're saying. Sprites are persistent things: You tell it once to draw an image in a particular place, and it will do it forever more until you tell it to stop. Your way of working is to start from scratch every frame.

Well, the persistence can actually make things simpler. After all, how often does the contents of a Cell/Sprite change? Only if the state of the Cell changes (eg. a tree grows) or if the map scrolls. It could cut down your code from having to do processing every frame to becoming purely events-driven/reactive, which is obviously more efficient as a rule.

Also, by using Sprites, you can leverage the fact the engine will automatically batch draw calls by Image within a RenderLayer (it doesn't do this yet, but it soon will - perhaps even this week). By doing the draw calls yourself, if you had a naive loop that just looped across all cells swapping from one image to the next and back again, that would introduce a far bigger slowdown than anything we're discussing here. The code needs to loop by layer, then by image, then by cell (but you probably knew that :))

Quote:
With that problem in mind, I need to improve my code design. I could simply create 3 Sprites per cell to have all cells and their respective sprite but imo it's a bit too messy regarding memory etc even though the images are only loaded once.


The memory usage is really trivial either way. I mean, even when you did Material2D draw calls, it stored data internally roughly equivalent in size to 20*15*3=900 sprites anyway. Really, you should just code it in whatever way makes your code simplest and cleanest; 900 objects, even done highly inefficiently - which they won't be whatever way you choose - is not going to be any kind of bottleneck :)

Quote:
I also would have to deactivate all sprites first and only activate all entites of the cells which are eligible for drawing (i.e those which are at least partly visible on the screen). It's a bit too much in my eyes and I have thoughts about performance if I have to compute visible cells each frame.


Well, you shouldn't have to compute visible cells every frame. There are basically two ways you could pair up Sprites with Cells:
- A Sprite could represent a fixed area of the screen: When the map scrolls, you update the Image of each Sprite (you don't change anything else about a Sprite like DrawArea/IsActive).
- A Sprite could represent a fixed area of the world: When the map scrolls, you don't update any Sprite Image, you just change which Sprites are Active and Inactive. (If you have no Camera class you also need to update their DrawAreas, but with a suitable Camera class this part isn't necessary.)

(Personally I'd choose the first of those: Having Sprites for each subsection of the screen, and just update the Sprites' Images when the map scrolls or something changes. That way even if the logical map is, like, 1000x1000 tiles you still only have 900 Sprites.)

Basically, by coding reactively/events-based instead of starting from scratch every time, you should find your code becoming simpler and doing less each frame - because, after all, most frames nothing will change.


---

Feel free to throw me a PM or just continue to post in this thread if you wish to discuss things further; I'll be around on and off for the next couple of hours at least :)

- Phil

Edited by user Wednesday, May 29, 2013 1:31:29 PM(UTC)  | Reason: Not specified