locked
Handling Tilesets... with decent performance RRS feed

  • Question

  • Hey,

     I remember when SL1 was out having a look at porting an old project into SL but there was no way to cut up tilesets and having to add them all as child elements and remove them as needed seemed to be dire...

    First off, i grudgingly made a simple tool last time to convert my tilesets into individual images with an XML file to link them all together for SL to load, however this then meant when i wanted to load a level into silverlight i had to first load the level xml file which gave me a tileset xml file, which then gave me X amount of individual images to load. Once i had loaded all these i created a grid of images and gave the image source to the relevent image within the tileset... (Its also worth noting i will be including all the standard optimizations wherever possible, but i dont want to over complicate the post). I also remember reading that none of the image resources would be shared, so every time an image was mapped to use the source from a loaded image it made its own instance of that bitmap data, which made me :(

    Now looking at  the new silverlight 3 beta and that a few more people are jumping on the game development aspect of SL i thought i would give it all another try. Ive been reading first of all about how to split up the tileset so i only need to do 1 external load request instead of 30+, and it looks like the same sort of issues exist... My options from what i can currently see are:

    - Load up the tileset as one big image then use clipping to work out which bit to display (this sounds like its going to cause alot of overhead as you are still ultimatly messing with lets say 128x256 each time you want to display a tile.)

    - Keep them all as seperate smaller images and load them all up individually

    With the addition of writable bitmap im not sure if this would help with the above problems enabling me to cut up the image within there and then create other images from it.

    My other issue is down to the way silverlight has the retained graphics mode, so you dont ever blit things, you just whack them in a canvas or whichever container and just let SL handle them. Now i could easily just dump all the level into the scene and im sure there is some simple 2d translation available to move around the scene. However im just curious if SL would handle the typical quadtree style culling methods for me, so it knows that certain tiles are out of the current screen bounds and doesnt touch them, or would i still need to add a tree of some variety to calculate what to draw each time a movement happens? If i do need to do the latter (which is fine and i was anticipating) which is the best way to do this? as you would have to run through the entire tree each update and either remove children from the scene and add others, or turn their visible flags on and off, which doesnt sound like its going to give a great performance when you have levels that could be > 64x64 in size...

     

    Sorry for all the waffling in there and i know its a bit of a bloated question but i cant find much DIRECTLY on tilesets in SL, which i can understand because it looks like a real pain to do... so any advice on the various questions posed in the above would be great!

    Friday, June 5, 2009 3:53 AM

Answers

  • I had the exact same questions when I started working on a sprite rendering engine.  I did some tests and here's what I found:

    Using a tile set (sprite sheet, as I refer to it), makes drawing VERY FAST.  Just change the clipping region each frame and it will fly.  Hardware acceleration will about double performance, though there are a couple bugs in the SL3 Beta that prevent flipping an image and using a TransformGroup on a hardware accelerated Image element.  I have been told by Microsoft that these issues will be fixed in the RTW.

    As for the matter of automatic culling of images, I did some tests on this, and yes, Silverlight will cull those images not within view and improve drawing performance drastically.  However, rendering performance will improve even more if you add or remove Image elements to the Canvas on your own when they come into/out of view.  Performance is completely unaffected by Image elements that have been instantiated but not added as children to a Canvas.

    WriteableBitmap is fast, but definitely nowhere near as fast as using tile sets.  I can get 50 fully animated sprites on the screen (60 fps) with transparency and scaling, and two large parallax backgrounds scrolling in the background at the same time, all at 60fps no sweat as long as I enable GPU Acceleration.  I can even add an animated writeable bitmap into the mix as a sprite and still get full speed.

    Friday, June 5, 2009 3:11 PM
  • Ah ok.  That sounds like an efficient data structure.  Truth be told, I need to study quad trees a little more as my understanding of them is a little shaky.  There seems to be a lot of variations in the way they are implemented.  I'm pretty sure I understand your implementation though.

    Things are a quite bit different with a hierarchical grid in that when you test an object for collision, you start from the finest grid layer and move upward (and the number of layers is not dynamic).  But if any grid layer is empty, you can effectively skip testing of any cells in that layer.  You can also keep track of the largest non-empty layer of the entire grid, so that you need never even iterate beyond it.  This can all be done elegantly with a bitfield representing which layers are empty and which are not.  You copy this bitfield before iterating through your grid layers, and with each iteration, right shift the value 1 bit.  If the bitfield & 1  == 0, then the current layer is empty and can you skip the current iteration.  If the bitfield == 0, then all remaining layers are empty and you can break.

    Anyway, I'm sure you enjoy minutiae of complex data structures as much as the next guy, so I'll spare you from any more details ;).

    I was indeed proposing a simple low-resolution 2d grid for culling purposes, which would be separate from whatever data structure is used for collision detection.  I figure a simple 2d grid, with each cell using an unsegmented array as a container, may be the ideal data structure for this purpose.  We want fast insertion/removal, and we don't care about compartmentalizing objects by size or precise location since we aren't comparing differently-sized objects against each other.  We just want to know whether large sections of the map-space are overlapping the visible area so we can make their contained objects visible.   There might be better ways of doing this though, and at the moment I have yet to implement the idea, but it's a very simple idea.

    Monday, June 8, 2009 5:34 AM

All replies

  • Well, a lot of questions, I can't answer them all but I'll give some of them a try.

    As far as I know, the "best" way of doing frame based animations, is to use "clipping". See this blog post from Silverlightgames101 - http://www.bluerosegames.com/silverlight-games-101/post/Frame-Based-Sprite-Animation-in-Silverlight.aspx it walks you trough making frame based animation using clipping.

    I guess this will be the best approach, as SL3 are coming up, as I think the GPU acceleration will let the GPU handle the rectagle clipping (not 100% sure here). So it should be able to perform pretty good.

    I don't know how Silverlight handles the part of the image that is "out side" the clipping area, but my guess is that it's optimized as good as possible. 

    About running through the entire graphic tree... I don't think that's nessesary. My guess is that Silverlight will handle your elements on the canvas pretty good, you just need to be in control of when they should be removed from the canvas and eventually you need to do that anyway to make your game good to play :)

    About setting the "visible flag". As far as I know, when you set the this.Visibility = Visibility.Collapsed; Silverlight totally skip that element, so it doesn't cost performance.

     

    Well, that were a lot of guessing from my side, hope you can use some of it. I want to share some video links with you as some of them might help answer questions.

    Deep dive into silverlight graphics - http://videos.visitmix.com/MIX09/T17F

    Principles of Silverlight animations - http://videos.visitmix.com/MIX09/T12F

    - Enjoy!

     

    Friday, June 5, 2009 9:43 AM
  •  Oh I forgot. I have a question for you too.

    "Ive been reading first of all about how to split up the tileset"

     Do you have some links you can provide about this?

    Friday, June 5, 2009 9:44 AM
  •  Thanks for the info, i have already seen that tutorial, has the dragon tileset right?

     Do you know off the top of your head if each image SHARES the imagesource or if it makes its own copy for each? as if it does still take its own copy i would be extremely worried if each 32x32 (or whatever size tiles) have their own copy of anything up to 256x256 data... and then the overhead on doing the clipping for each one of those would make me have nightmares for days...

    I dont mind loading the tiles individually, apart from the initial pain from having to write a system for managing what tiles should be loaded and the crazy amount of small load requests it means you can get more caching done, as if 2 levels use 20 tiles and 10 of them are the same then it would be quicker on subsequent calls with the same tiles, rather than each level being restricted to a tileset, it can just pick the tiles it needs... although i was wanting to include animation on them as well so i guess i could use the clipping method and have multiple tile animations in one set... if that makes sense...

    I like the fact that the canvas may do some of the hard work for me (culling entities which are not in the scene etc) but unless its confirmed and is quite good in the way it does it may be a bit slow with alot of tiles.

    On the flip side though having a simple quadtree to seperate out the level and work out what should be rendered each update would be useless for culling as you would have to go through every node in the tree to turn it on/off, whereas with blitting you only blit what you need to so you dont need to worry about doing anything which isnt in the scene. The tree would still be useful for collision detection and some other things, but i dont think im going to gain much performance increase from doing manual culling on it...

     

    As far as previous articles on tilesets i found next to nothing directly on this topic when i started looking, although i think i posted a few threads on these forums about it (if you check through my previous posts), but no one really gave any solid responses... There were quite a few Actionscript tileset examples you could hijack to a degree but as most of the decent ones blitted at some point it didnt help much. There was also a site where some guy was comparing flash to silverlight with various examples and im sure he had a semi decent article indirectly relating to the subject... I guess it would be better for me to have said "I have been looking at articles VAUGLEY related to tileset systems in silverlight"... Splitting them up isnt my primary concern though as thats just going to be a bit of an overhead when loading... its not going to cause any constant performance issues, whereas how i go about displaying them will... It may be slightly faster than having a load of images to do rects with image brush, but im pretty sure that each one of those makes its own copy of the imagebrush object rather than playing nice and sharing with other objects... I was thinking about trying to make some sort of blitting system using the writablebitmap as the buffer and drawing images to there, but i couldnt find a way to get access to a standard image object to pluck out its colour data and draw it onto the buffer, and even if i did there is no telling if it will be any faster... regardless im going to have a go at putting *SOMETHING* together with whats available...

    I cant see making the tileset system being that hard, although it is going to be a bit of a crappy implementation, but i dont think it would be able to handle as much things on screen as i want it to be able to handle, and when you throw in networking, effects, other UI elements i think its going to run like a tin of beans on sandpaper... but i like a challenge :D

    Friday, June 5, 2009 10:28 AM
  • Another option might be to look at my SilverSprite library on CodePlex http://silversprite.codeplex.com

    Although its main purpose is to let you run XNA 2D games in Silverlight, it has a side benefit. Since XNA requires you to draw everything every frame, I had to build in a virtualization layer which handles what images are currently being displayed. So anything that is not drawn in a particular frame will be removed from the canvas until it is needed again.

    One potential drawback is that you would need to write your game (or at least the tile engine) using the XNA programming model. Of course this could be a benefit if you wanted to also sell your game on Xbox Live Community games.

    I'm not sure if it would give you the performance you are looking for or not, but for the most part it seems to perform pretty well. 

    Friday, June 5, 2009 10:44 AM
  •  Hi Bill,

    Im sure you were one of the original guys to help me out when i was looking at this stuff in SL1... ive acctually got a fully functional XNA tileset system that would be great to use in here, but i dont think it would be as easy as just dropping the code in and would have porting issues...Im looking for this project to be web only as its going to involve some element of networking with it, so it wouldnt really be suitable for Xbox, but i guess if i wanted to make it standalone would be worthwhile as i already ahve alot of libs written for this sort of stuff!

    I wouldnt normally mind using a 3rd party library but by the sounds of it, the lib would just be doing what i would be doing but some other stuff on the side which may be useful or may be functionality i dont need. So for the moment i will just make my own *bare bones* implementation, but may give it a look over as it sounds interesting either way.

     

    I may have a look into the C64 emulator and the way that is drawing things to the screen as ive read a few of the guys articles and he seems to know what hes on about and if you can have an emulator and quake running in SL im sure you can have a simple 2d based tileset game...  Has he released the source yet? i know hes using some of the media stream elements (or whatever the movie editing libs are) to draw his elements so maybe that offers some sort of blitting functionality... 

    Friday, June 5, 2009 10:53 AM
  • Scott Hanselman interviewed the C64 guy. You can hear the podcast here: http://www.hanselman.com/blog/HanselminutesPodcast155AC64EmulatorWithSilverlight3ByPeteBrown.aspx

    Just a little FYI :)

     

     

    Friday, June 5, 2009 11:50 AM
  • I had the exact same questions when I started working on a sprite rendering engine.  I did some tests and here's what I found:

    Using a tile set (sprite sheet, as I refer to it), makes drawing VERY FAST.  Just change the clipping region each frame and it will fly.  Hardware acceleration will about double performance, though there are a couple bugs in the SL3 Beta that prevent flipping an image and using a TransformGroup on a hardware accelerated Image element.  I have been told by Microsoft that these issues will be fixed in the RTW.

    As for the matter of automatic culling of images, I did some tests on this, and yes, Silverlight will cull those images not within view and improve drawing performance drastically.  However, rendering performance will improve even more if you add or remove Image elements to the Canvas on your own when they come into/out of view.  Performance is completely unaffected by Image elements that have been instantiated but not added as children to a Canvas.

    WriteableBitmap is fast, but definitely nowhere near as fast as using tile sets.  I can get 50 fully animated sprites on the screen (60 fps) with transparency and scaling, and two large parallax backgrounds scrolling in the background at the same time, all at 60fps no sweat as long as I enable GPU Acceleration.  I can even add an animated writeable bitmap into the mix as a sprite and still get full speed.

    Friday, June 5, 2009 3:11 PM
  •  Hey MooMph,

    I noticed some of your other posts on doing game related stuff in SL, and your questions about if the GPU would take any of the overhead etc. OH and your tip on one of your previous posts about making sure you bitmapcache individual elements and not the container for performance gain is golden.

    I will try and get some of this functionality hammered out today/tomorrow (i need to rejig my DB/Services a bit first) then will no doubt have some more questions :D, do you have any source code available to show what sort of tests you did etc? if not no worries... 

    Saturday, June 6, 2009 7:33 AM
  • I'm glad that you found my previous posts on this topic useful.  I didn't save my earlier tests, and my current configuration is not in a very sharable state, but I can tell you more about the tests I performed.  If you're concerned about culling performance, I would recommend you do some testing of that yourself because I'm not completely confident in my results on that.  Certainly, Silverlight does a good job handling culling on its own.  However, I recollect that there was a small performance penalty for having Silverlight cull many off-screen objects.  Because simply instantiating Image elements does not affect performance, I create all of my sprites at once and add/remove them from the canvas when they move in and out of range, which is a trivial calculation.   But my memory on how thoroughly i tested this is fuzzy.

     In another of my tests, I had one of my sprites' Image element use an unchanging clip region and alternated its source between two sprite sheets each frame.  Performance was beyond terrible.  Now, perhaps this had to do with the large size of the sprite sheet images, or perhaps bitmap caching was causing some overhead every time the image source changed, but I figure that animating with many different image sources, even small, is almost surely going to be slower than using sprite sheets and changing clipping regions.  Sprite sheets are recommended in 2d DirectX development for reasons relating to GPU hardware performance.  I assume the same reasons apply to GPU-accelerated Silverlight.

    To give you a sense of what performance you can get, I currently have a sprite sheet that is 512x1024 and consists of over 350 individual sprites of different dimension.  I have another sprite sheet of similar size with larger sprites.  I have 50 of each (100 sprites total) fully animated and moving on the screen, with different z-indexes, opacity values, and changing scale transforms each frame, plus three very large images scrolling in the background.  The framerate levels out to a consistent 60fps after about 10 seconds, with only occassional little speed bumps.  If I resize the window to cause some of the sprites to be culled, everything renders even more smoothly.  This is, of course, with GPU acceleration enabled.  I'm running Windows 7 x64 on a 2ghz core duo.

    Sunday, June 7, 2009 3:25 AM
  •  Hey,

    No worries, the info in this post is enough for now. I mean i wont notice my main bottlenecks until i have the system up and running, and can then think of the best way to improve on it...Hopefully once i get round to doing the implementation (a bit sidetracked at the moment) i will have some useful findings to help others... 

    At least i know that you took the same train of thought as me, when you were thinking about culling them the only options i could immediatly see were to add/remove or show/hide them from the scene each time the position was updated or something. I think im still going to store them all in a tree, as that way my collision checks and other lookups will be significantly faster... and i may even be able to do some sort of optimization to skip out some of the areas that wouldnt need to be updated every time... anyway im just thinking out loud now... will try and get some stuff done today but im not sure if  iwill have time :(

    Sunday, June 7, 2009 6:57 AM
  • I'm also using a collision detection structure - a hierarchical grid.  I haven't used trees, but I don't think that whatever data structure you use need complicate your ability to manually cull objects from the canvas (I might be misreading you, but it sounded like you were suggesting this).

    I completely forgot, but my plan for determining which objects to cull is not a trivial calculation, since I would have to do that for every object every time the view moves, but to use a very large grid  (separate from my collision detection structure) where each cell is the size of the view and contains an array of all objects contained within.  Needless to say, my game allows for a wide gameplay area and expects a lot of scrolling.  When an object moves, it can be rechecked against the grid.  You can give each object its index into this array for fast removal, and when you remove an object just pop the last object of the array into its place so there's never any segmentation, keeping iteration fast.  Now, whenever your view moves and overlaps another cell, you can quickly iterate over the cells' array and add those objects into the canvas, and vice versa for going out of a cell's range.  Of course, you also need to do checks each frame for any objects that move, but you'll be doing those anyway for collision detection.  This seemed to me a decent compromise between no cullingand making sure every object not in view is culled, since Silverlight seems to do a good job of it anyway as long as there aren't a ton of things off-screen.  My only worry is that adding or removing a large group of objects from the canvas at once is going to cause performance spikes.

    If someone's collision detection structure is a simple grid, it might be easier and more precise to use it to determine cullable objects. A more complex structure like a hierarchical grid or tree will require a lot more checks, however.

    Your idea of changing the visibility property of objects never occurred to me.  That's a good idea, and I wonder how it would compare against adding/removing from the canvas.  At any rate, all this talk of manual culling may be moot if Silverlight does it on its own acceptably fast.

    Sunday, June 7, 2009 1:13 PM
  •  Hey,

    Tree structures are brilliant for almost anything where you only want to get specific data back quickly. Although they get very complicated and alot slower if the data is not static. So for a tileset level they are brilliant, in a quad tree sort of implementation you would just keep subdividing your areas into smaller zones, so if you had a 128x128 area you would basically split it into four 64x64 areas, then when you sub divide them you would then get a 32x32 for each of them... this way when you do collision detection, culling, ai etc you would basically say:

    Im at position 56x102 i need to check if im colliding with a tile, you would first of all enter the tree and then you only follow the tree elements you are contained in, so instead of itterating through a list or a grid of some kind you would only check the areas that would be relevent. This is great when you want to find any surrounding entities, as you can just pass in a rectangle and get a list of entities within that area, making collision detection and AI lookups easier as you only ever get the data you need... and you can easily add in a IEnumerable to expose it as a list if needed.

    I used to just use lists until i was working on a 2d diablo style game where i had levels that were between 32x32 - 256x256 (tileset system) and needed to cope with 100s of entities on screen animating and colliding with the terrain and the player and doing basic AI to avoid danger etc. My first implementation dragged along with just the player and tile collisions (32x32 level) and 100 entities without collisions at 20(ish) fps (i develop on a crappy 12" laptop), then with a simple tree system to manage culling and collision detection it flew up to about 90 fps (uncapped), and would remain about 75+ until i had 256x256 with alot of entities in the level but only about 50-150 on screen at once then it went down to about 60(ish)... So trees can make a MASSIVE difference if used right... but its all about whats best for the task at hand, and if you have moving things it makes things ALOT harder with trees as you have to keep rejigging elements.

    Sunday, June 7, 2009 5:07 PM
  • Tree structures are great and have their place.  Hierarchical grids are extremely similar to quad trees - they are a collection of overlapping grids, subdivided into finer resolution, which allows you to perform collision detection on objects of varying size quickly much like you can with a quad tree.  The difference is that you don't always need to traverse down from the top of layer of the grid, which is usually the least populated, as you will always have to do with a quad tree (or if you're representing objects multiply, you can't skip any intermediary layers between where you start and the bottom).  Instead, in a hierarchical grid, you check from the bottom of the grid up, and if any grid layer is unpopulated, you can use a flag to indicate it's safe to skip.

    It sounds from the way you are describing your quad tree structure that you are representing objects in it multiply (as otherwise you'd always have to check upper layers).  This model will indeed be ideal for static objects that never need to be removed and re-added to the grid, but it will be slow for dynamic objects.  The same could be a applied to a hierarchical grid.  If you are going to have moving objects though, you can implement a quad tree or hierarchical grid that only uses one instance of each object throughout it, and this will speed up insertion/removal times at the expense of a little retrieval time. Then again, there's no reason you can't have two separate grids using each model - one for dynamic objects and the other for static.

    Hierarchical grids can be memory expensive if each grid is represented by a dense array, but you can get around this by using hash tables instead. I recommend you check out the book "Real-Time Collision Detection" by Christer Ericson if you want to learn more about them.

    Monday, June 8, 2009 2:10 AM
  •  Ah im with you, i thought you just meant you had a simple 2D array for lookups, i havent heard of Hierarchical Grids before so will take a look up on them, thanks for the info!

    I dont run it like a typical quadtree... as i started using them for terrain systems i was working on, so the top one would contain an extremely low detailed version of the area, then beneath that it would be a slightly higher detailed version but split up more, then beneath that more detailed again... a bit like mip mapping. So i could choose layers for quality.

    The way i have implemented it in this scenario is that each node has a threshold, so lets say 4. Every time i add data  to the tree it puts it in the relevent container and then when it gets asked to add data that would take it over its threshold it splits the tree and distributes its data amongst its new children, so its only the bottom most nodes in the tree that acctually contain data, the top ones are just like leaf nodes or whatever the term is. So when i traverse the tree all i need to do for each node is:

     

    IEntity findContainedEntity(Rectangle ContainingArea)
    {
       if(hasChildren())
       { return m_Children[findContainingChild()].findContainedEntity(ContainingArea); }
       else
       {
          foreach(IEntity Entity in m_Data)
          { 
             if(Entity.Area.Intersects(ContainingArea))
             { return Entity; }
          } 
       }
    }
     
    Thats not the exact function, but you get the jist of it, so although you go top down the tree, it is still only doing a simple check on each node it hits to see where the next layer it needs to descend to is. Im not sure if thats what you meant or not, if so then forgive me for boring you :D
    Monday, June 8, 2009 3:15 AM
  • Ah ok.  That sounds like an efficient data structure.  Truth be told, I need to study quad trees a little more as my understanding of them is a little shaky.  There seems to be a lot of variations in the way they are implemented.  I'm pretty sure I understand your implementation though.

    Things are a quite bit different with a hierarchical grid in that when you test an object for collision, you start from the finest grid layer and move upward (and the number of layers is not dynamic).  But if any grid layer is empty, you can effectively skip testing of any cells in that layer.  You can also keep track of the largest non-empty layer of the entire grid, so that you need never even iterate beyond it.  This can all be done elegantly with a bitfield representing which layers are empty and which are not.  You copy this bitfield before iterating through your grid layers, and with each iteration, right shift the value 1 bit.  If the bitfield & 1  == 0, then the current layer is empty and can you skip the current iteration.  If the bitfield == 0, then all remaining layers are empty and you can break.

    Anyway, I'm sure you enjoy minutiae of complex data structures as much as the next guy, so I'll spare you from any more details ;).

    I was indeed proposing a simple low-resolution 2d grid for culling purposes, which would be separate from whatever data structure is used for collision detection.  I figure a simple 2d grid, with each cell using an unsegmented array as a container, may be the ideal data structure for this purpose.  We want fast insertion/removal, and we don't care about compartmentalizing objects by size or precise location since we aren't comparing differently-sized objects against each other.  We just want to know whether large sections of the map-space are overlapping the visible area so we can make their contained objects visible.   There might be better ways of doing this though, and at the moment I have yet to implement the idea, but it's a very simple idea.

    Monday, June 8, 2009 5:34 AM
  • I haven't read all the posts in this thread yet, but I'm following it, as I'm kind of in the same boat. I'm doing a new game (see my blog if interested, game is called "Little Longhorn") where I currently use the collision implementation/achitecture Joel Neubeck is using in his article series: http://expression.microsoft.com/en-us/dd279542.aspx Just wanted to share, as his approach sound very much like what you describe here with your "grid" approach. I am not far enough in my game to tell if this actually performs great, but up untill now, it works great. :)
    Monday, June 8, 2009 7:09 AM
  • Qbus, that article describes a uniform grid data structure, which is the simplest of collision detection data structures, but also fast and sufficient if your objects are of a fairly uniform size.  However, if you start to allow greater variations in object size then you probably want to look at other structures, like the quad tree or hierarchical grid.
    Monday, June 8, 2009 8:00 AM
  • Ok, nice to know. Do you have links where I can read and see samples about these two? Not that it's a problem for me right now, as my game isn't that far, but at some point I might need it :) I haven't this complicated collision detection before by my self, so it's pretty new to me.
    Monday, June 8, 2009 8:04 AM
  • Well, that book I mentioned has really been the only resource I've needed.  You can get a glimpse of it here.  It's quite thorough.  Gamedev.net may be another good resource.  Actually, what clued me off to the hierarchical grid structure were some posts by the author on the gamedev forum.  The metanet software tutorials are good at covering the math of narrow-phase collision detection.  However, for broad-phase detection, they're using a uniform grid (they still explain it well).
    Monday, June 8, 2009 8:35 AM
  •  After swapping over to use WritableBitmap as a backbuffer instead of adding them all to the scene my performance has dippied a MASSIVE amount...

    I currently have a Image that is 800x600 in size, and the same sized writable bitmap... now the writable bitmap is only created once, and im simulating a rendering loop, at the moment im only doing 1 redraw every second, so its no where near the 60 frame per second you would expect, but im not after eye bleeding speed i would be happy with 30... Im also only drawing to about 500x500 on the image...

    Anyway im on my crappy laptop, but im currently getting between 15-22 FPS, and im only rendering 262 tiles per re-draw, that would be 210 ground tiles, with 52 tiles drawn on top... I have got the level stored in a quadtree structure so i am only pulling out the viewable tiles each frame and drawing them...

     

    Thats a screenshot of what im rendering, and im just trying to render the simplest of tiles at the moment... this sounds quite odd considering that Moo was getting awesome performance with more tiles than me... how much were you re-drawing?

    Wednesday, June 10, 2009 1:48 PM
  • Do you have BitmapCache and GPU acceleration turned on? You can also set this parameter to get a better idea of what's getting cached:

    <param name="EnableCacheVisualization" value="true" />
    Wednesday, June 10, 2009 1:57 PM
  • Yeah got both enabled, although i dont seem to see anything getting cached... i am on a pants laptop with an intel GMA 915 or something... but i have written XNA games with up to Shader V2, so it should be ok for silverlight... Also the writable bitmap was PRGBA32 or whatever the setting is, whereas now ive set it to RGB32 and i seem to get about 3 more FPS...

    - Edit -

    Just tried removing the quadtree and putting in a list, so im still rendering the same amount, just from the list instead of the quadtree and i notice no FPS difference, which i expected as im rendering exactly the same amount both ways currently, but i can at least mark that off as not being the performance problem... Also tried disabling the 2nd layer, so it is only drawing ground tiles, and i get about 5 fps increase... it seems odd that drawing an extra 52 tiles per second can cost 5 fps...

    Also tried locking the writable bitmap (thread lock) when drawing to make sure there wasnt some cross thread problems, still no performance benefit... then tried locking the bits before drawing everything, but then i just get an error whenever i hit unlock() saying it should go lock(), Invalidate(), unlock() then when i try that it kicks up same error on unlock line... I cant really think of anything else to try...

    Wednesday, June 10, 2009 2:01 PM
  • Rereading mommph's posts it's not clear to me whether he was using WriteableBitmap to get that performance.

    Wednesday, June 10, 2009 2:11 PM
  •  oh, sorry it must have been in the other thread that was kinda linked to this one, Translating UIElements or something like that...

    I wonder if anyone has done a particle system with writable bitmaps... if they have that should show me a bare bones implementation...

    Wednesday, June 10, 2009 2:20 PM
  •  Just rolled back to the old method of just plonking EVERYTHING into the canvas and letting it sort it out... i made sure i put something on EVERY tile in every layer... and here is the result...

     

     

    Stays around 60 frames per second, although im having trouble confining it to only display 800x600 as it just seems to display whatever it wants... anyone know how to do like an overflow: none;

    Wednesday, June 10, 2009 3:16 PM
  •  Ah clipping property, got it sized how i want... ironically this method of putting everything in the canvas seems fastest but most wasteful with memory and variables. Seems to take up less memory though and responds faster... also you get the ability to use each tile as its own UIElement so you can apply events to them.

    The more efficient way of only blitting what you need you would assume to be faster but is EASILY 10x slower than just dumping things in the scene... its crazy... and as much as i hate doing things this way i guess its going to be quickest for now.. hopefully i can unplug this component and replace it with a better way later on...

    Wednesday, June 10, 2009 3:34 PM
  • Grofit,

    Not sure if I'm misreading you, but when I was talking about using WriteableBitmap for tiles (in your thread about translating UIElements), I was talking specifically about static imagery.  For any sort of animated sprites, I use sprite sheets and change clipping regions (as discussed earlier in this thread).

    Wednesday, June 10, 2009 4:39 PM
  •  Yeah, i thought you meant that you were just blitting things to the writable bitmap constantly... it sounds brilliant in theory, and implementation is brilliant, just performance is a sack of crap...

    Wednesday, June 10, 2009 4:49 PM
  • But if you separate your imagery between that which is static and that which is animated, and use the two different drawing methods, you should be able to get very good performance.  You don't want to be redrawing your static tiles each frame, just any sprites that move or are animated.

    Looking at your screenshots, I assume this map you draw isn't animated or anything.  Sure, you'll probably be drawing animated and moving sprites on top of it, but there's no reason that you need to redraw the map itself each frame.  Just draw the map once as a WriteableBitmap, then create some sprites and put them on top.  You can set the sprites' Canvas.ZIndexProperty to ensure the drawing order is correct.

    Wednesday, June 10, 2009 4:59 PM
  •  Yeah, ive currently got a flag on each tile to specify if its dynamic or static, but the thing was that i was using it as a backbuffer so whenever a user moved it would have to redraw all tiles with a given translation... if you imagine it as a 2d scene with a camera, when you move around you are purely moving the camera... while you stay at the center. So i was basically drawing the tiles with an offset, which would mean every time i would have to redraw them all with the new offset anyway...

    I thought of a few other ways to speed up my current implementation which im sure i can still use... which would involve a baking process for all static tiles, so rather than drawing each tile layer individually and each tile individually i could basically flatten the 2 layers apart from where they are animated, then write them to a new image, then just display that... so that could cut down by tile drawn amount by about 1/3, i cant bake them all as the 3rd layer is an overlay...

    I was also toying with the idea of baking them into bigger images, so lets say i have 4x4 static tiles that are 32x32 each and there are 3 layers like described previously. I could bake them onto 2 new 128x128 images (first one being bottom 2 layers together, then top layer), which would then mean there would only be 2 larger child elements in the scene opposed to 16 children elements... not sure if it would be any faster though... i will try playing with that sort of stuff later when i need the performance gain!

    Wednesday, June 10, 2009 5:16 PM
  • The way I do it is to define my static imagery in some data structure that tells me what tiles to draw and where.  Then, depending on the size of your map, split it into a bunch of large WriteableBitmaps (each one the size of the game screen in my case), or just one giant WriteableBitmap.  Render to these bitmaps using your data structure and the WriteableBitmap.Render() function.  Now you've got a bunch of large WriteableBitmaps that contain your static imagery.  You can easily translate them around, as you were describing, and if you've made them large, you'll only be translating a small number of images at a time (if the WriteableBitmaps are the size of your game view, you'll never have more than 4 visible at a time).  There's nothing that would prevent you from adding more layers onto this, like an overlay, or some sort of foreground.

    Maybe there's some confusion about translating the scene.  If you are keeping your character in the center of the screen, but moving the map around underneath it, then you don't need to redraw the map each time it moves, just translate it.  If the map consists of a whole lot of tiles, instead of a small number of large WriteableBitmap(s) onto which you blitted the tiles, then obviously you'll have to move a lot more objects, and this will be slower.  But it's going to be a lot faster than redrawing some backbuffer each frame.

    Wednesday, June 10, 2009 5:25 PM
  •  Just wanted to ressurect this thread a little as ive done some work and found some suprising results...

    And ive also just realised that these forums are a pile of rubbish... do they not have the fabled power of paging... every time i load this thread it takes about 10 seconds to load everything...

     

    ANYWAY... ive got my basic tilesystem up and running and i have sorted out scrolling which isnt as fast as i would have liked but it should do for now... it dips about 10fps from the average fps... so if you get 50 fps normally it would prob go to about 40 while you move...

    I will try and speed that up a little later but i cant see any way to do that, and im on a crappy little 12" laptop with a crappy celeron so im sure that it would be ok on most peoples systems.

    I can keep around 60 FPS while *I* stand still and everything else moves, with a display area of 800x600 with about 300 tiles and about 100 entities on screen moving and updating...

    I can have 1000 entities moving around at the same time with basic AI and about 300 tiles and it is around 20-30 FPS... but im not expecting to ever have more than 100 things on screen...

    Although these things do not really reflect my end performance, as i will have menu overlays, network updates, animation, collision detection etc... However i think it will be possible to get the level size i want with everything else happening without dropping below 45 fps on most low end systems. Should be 60 fps on most systems that have a dual core or higher...

    Monday, June 15, 2009 4:09 PM
  •  As the gaming forum isnt that active thought i would update this post...

     After messing around a bit ive managed to optimize it a bit more by adding a quadtree system with viewable tile caching. So each time you move out of the *free zone* it hides the visible ones and re populates them... well in an intelligent way.. it has a removal queue.. anyway there are a few more things im going to start doing, like image baking to make slightly larger images from the smaller ones and to merge down certain static elements, which i think was described here earlier...

     I wish these forums would page...

    Thursday, June 25, 2009 3:51 PM