none
Silverlight Tile Engine (MapEditor)

    Question

  • Dear community,

    I'm currenty building a tile based map editor using Silverlight. The idea is to build an editor with the "Bing or Google Maps experience" (panning / zooming). I'm having some performance issues, which I could need you're help for.

    Current version (screenshot):

    http://img706.imageshack.us/img706/964/tileeditor.png

    Some background information:

    • A map can contain up to 50.000 tiles
    • A map contains 3 layers
    • A tile is 48 x 48 pixels using the png format
    • I'm using pre-defined tile sizes (48, 36, 24, 18, 12), to optimize the memory usage when zooming.
    • The size of the map on my computer is 1200px x 750px

    I already tried the following approaches:

    • Canvas or Grid with image objects

      Create a Canvas or Grid where you dynamically add Image objects to. I tried using canvasses (with an image brush attached to the background) instead of the image objects as well.

      This works fine for large tiles (48px x 48px) which means there are 50 (1200px / 48px) x 25 (750px / 48px) = 1250 objects on the screen. But the smaller the tiles. the more objects on the screen, the lower the performance. Using 24px tiles, there are 5000 tiles on the screen.

    • WriteableBitmap

      Create a large WriteableBitmap in which you write the pixels of the tiles. This works fine with smaller tiles. For instance: 24px tiles result in 50.000 tiles x (24px x 24px) = 31250000 pixels. It takes around 2 seconds to draw all the tiles on the map (not just the active screen) using the Blit from WriteableBitmapExt. The panning is really fast, since it's one giant image.

      The method is really consuming a lot of memory and I can't even draw a map with 48px x 48px tiles. This results in a memory out of exception.

    I also tried loading on demand, as in, loading the tiles that are actually on or near the screen. I found out that that takes to much time when panning around fast. 

    The WriteableBitmap is ideal when using small tiles, and the image objects are really nice when using large tiles. I can't find a right way of doing small and large tiles using the same technology. 

    I hope I gave you guys enough information about the things I'm doing here. I'd like to hear you're thoughts on building a tile based map editor. I could really use some help on this. Thanks!

    Regards,
    Bryan

    Saturday, February 06, 2010 2:15 PM

Answers

  • Ahh, kinda like how Ajaxian does it with css and jquery then (They use divs as canvases). If you could make a sample project, that would be awesome. I am sure I would not be the only one who would love to have that type of resource availible :)

    The sample project (with single objects):
    http://dl.dropbox.com/u/1666558/TileAppDemo.zip

    The sample project (with regions & GPU acceleration):
    http://dl.dropbox.com/u/1666558/TileAppDemoGPU.zip

    You can try different tile sizes, border (buffer), region sizes by setting the variables in Settings.cs

    Any feedback is welcome!

    Regards,
    Bryan

    Tuesday, February 16, 2010 3:33 PM

All replies

  • How do you copy the tile pixels to the large bitmap. Do you know the Blit() method from the WriteableBitmapEx project? SilverMap - A Silverlight Tile Map using WriteableBitmap for Games uses it to copy (blit) the tiles to the larger bitmap.

    Saturday, February 06, 2010 2:23 PM
  • I did, with a huge performance boost. But it is a fact that I can't create a 50.000 tile bitmap using 48px tiles.

    Saturday, February 06, 2010 2:38 PM
  • So the real problem here is you hold these 50k images in memory which is causing an OOM Exception. Just think about how the others do it: They stream just what they need from the server to the client. You should create a nice data structure and think about how to stream such huge amout of data to the client.

    But why don't you use DeepZoom for this task. It's there and it works.

    Saturday, February 06, 2010 2:45 PM
  • My concept is a little different than what you're describing there.

    I'm using a palette (300 png images) which are embedded in the client.

    The maps are defined using XML. I already overcome the problem with the xml (which is 4mb and stored on the server). Zipping the xml server side results in a 150kb file instead of 4mb.

    The exception is thrown when creating the WriteableBitmap. It's impossible to create a WriteableBitmap with 10.000 x 30.000 pixels. Besides, I want to actually edit the map real-time, so deep zoom is out of the question I think.

    Since the WriteableBitmap is the best way of getting some good performance, I'd like to hear you're thoughts on finding a work-around on the OOM exception

    Saturday, February 06, 2010 2:54 PM
  •  I also did with high performance boost.

    Saturday, February 06, 2010 3:01 PM
  • I've updated my first post with a screenshot of the editor. That's with 24px x 24px tiles.

    Saturday, February 06, 2010 3:05 PM
  • When you create a WriteableBitmap of the size 10000 x 30000 you are actually creating a HUGE int array that needs 1.11758708953857421875 GB of memory! And that's hitting the memory limit for a 32 Bit .Net process.

    So the answer is, you can't create such a large Bitmap in memory. Instead you have to split it in smaller parts that are somehow stored and loaded.

    Saturday, February 06, 2010 3:18 PM
  • How did u calculate that number?

    I'm having no problems at all creating a 20.000 x 5.000 WriteableBitmap. This results in 100mb of memory (bases on taskmanager).

    There are not that many tiles filled in though .. So I think the WriteableBitmap only consumes memory for the actual pixels filled.

    I think I already got the solution for my problem .. I'll just create smaller maps .. haha

    Saturday, February 06, 2010 3:26 PM
  • 20k * 5k pixels are 95 MB so this is right.
    The WriteableBitmap uses ARGB colors and stores each pixel as an integer value in the Pixels array. So just calculate 10000 * 30000 to get the Array length and multiply it by 4 to get the number of bytes = 1.1 GB.
    So as I wrote above you should create smaller pieces that are not all kept in memory.
    Saturday, February 06, 2010 3:56 PM
  • I think instead of using DeepZoom, consider using IsolatedStorage and dynamically load and save portion of the tiles to IS.  This way you have access to the map in real time and be able to overcome the memory problem.
    Saturday, February 06, 2010 5:05 PM
  • It seems overkill to me to create a bitmap of 10,000 pixels in width when your screen can not view that, unless you have some kind of monster screen.

    If you want to zoom why not resize each tile when you blit them, rather than writing to giant bitmap and trying to resize the whole thing.

    You only want to work within the active area or view port and only draw within that size of a bitmap, you will get much better performance even with all the math to recalculate each tile than a massive bitmap.

    Saturday, February 06, 2010 9:05 PM
  • Keep in mind that when you add UIElements to a Canvas, the Canvas becomes one large image. So if you add 25 x 16 tiles to a Canvas, you are in fact creating one large image 1200 x 768px. So if you move the Canvas, it will actually be quite fast compared to moving each tile individually. What you need to do is create larger tiles from the smaller ones. Try and picture that for a moment. So you have these 48x48 tiles. Alone, you are managing a lot of transformations on the screen. A lot of processing power is consumed. So create regions (ie: Canvas objects) of 5x5 tiles, or 240 x 240px tiles. Now your screen only has about 15 larger tiles to worry about. That's far more manageable. Do you see where I'm going here? The idea is you'll have 5 x 3 larger tiles on the main display, with a couple more larger tiles adjacent to the screen edges to stream in the next part of the world that's about to be visualized. You never create new regions, you ALWAYS reuse the ones you have. Just redraw them when needed.

    Next you have to have a scene graph. A scene graph will partition your world in smaller pieces (right down to the tile) so that you can quickly find something and do something with it. A grid based scene graph will suit you well here. You can google for more details on how that's going to work, but I'm confident you'll understand it quite well. In general, this scene graph is going to do a couple things for you.

    1) As you walk around the world, the scene graph will tell you a new region needs to be rendered. You'll take the adjacent region  (remember, this is the larger tile containing 5x5 tiles), render the smaller tiles on it, then transform the region as the player moves around.

    2) It will manage your collision detection. A large group of untraversable tiles will count as only a single collection check rather than individually checking against each tile.

    3) It will handle your pathing. The A* algorithm and grid based scene graphs go together like brother and sister.

    4) It will manage on-screen states and off-screen states. Areas not seen do not have to have active states. A monster wouldn't need to be AI controlled if it's 5+ regions away. Though you may activate something if it's only 1 region away.

    Sunday, February 07, 2010 12:28 AM
  • Thanks everyone for giving me feedback, I really appreciate it. 

    @ksleung
    I never heard of the IsolatedStorage, but that really seems something to check out!

    @lionsguard
    I tried such things before, as I mentioned in the first post. I know a basic tile engine works like that. As you can see in the screenshot, I'm using scrollbars to move around the map, this results in very fast transitions. The way I tried it before, was using my own code for drawing. Since the Blit from WriteableBitmap is tree to four times as fast, maybe that will actually work. I'll try it!

    @TheNut
    Adding multiple UI elements to a Canvas doesn't result in a simple large image. Try adding 10.000 small Images to the screen, and move that screen around. You'll notice it'll lagg. When you create an actual bitmap using the WriteableBitmap, the performance is a lot beter.

    As for the rest, remember I'm not making a game. I'm making a MapEditor.

    Thanks,

    Bryan

    Sunday, February 07, 2010 7:04 AM
  • So, I've tried doing the ViewPort thing with moderate results.

    What I did:

    • Create a Canvas with a WriteableBitmap attached to the background using a ImageBrush.
    • Make them both the size of the viewport
    • When the value of the slider changes, redraw the whole screen using the Blit from WriteableBitmapExt

    I used the following code: 

    for (int z = 0; z <= 2; z++)
    {
        for (int x = this.ViewPort.TopLeft.TileX; x <= this.ViewPort.BottomRight.TileX; x++)
        {
            for (int y = this.ViewPort.TopLeft.TileY; y <= this.ViewPort.BottomRight.TileY; y++)
            {
                string key = x + "," + y + "," + z;
                if (this.Tiles.ContainsKey(key))
                {
                    this.DrawTile(this.Tiles[key], false);
                }
            }
        }
    }
    private void DrawTile(Tile tile, bool redrawBackground)
    {
        string codeForCache = tile.Id + "," + TileSize;
        this.background.Blit(new Rect((tile.X * TileSize) - this.MapScrollHorizontal.Value, (tile.Y * TileSize) - this.MapScrollVertical.Value, TileSize, TileSize), DataHelper.Instance.CashedTiles[codeForCache].Data, tileRect);
    }

    which is pretty straight forward ..

    When scrolling, I get around 11 FPS, which is reasonable, but too slow for me. I think I'll just go with the bigger WriteableBitmaps. The maps are migrated from an older system, which includes spaces for no reason. If I remove those spaces, my maps become reasonable small (15% of what they are now).

    Thanks for all of your help! I hope to go live with this editor within a month, by then, I'll post a link!

    Regards,

    Bryan

    Sunday, February 07, 2010 8:29 AM
  • Bryan, it does when you enable GPU acceleration and set the CacheMode to BitmapCache. The result is a single image that is GPU accelerated. From my own test results, this gained me the most FPS and faster load times.
    Sunday, February 07, 2010 9:02 AM
  • I just did some tests (again), and I noticed that the moving performance is pretty good. The thing I'm struggling with though, is the load performance. I didn't notice any difference in load time between "with GPU acceleration" and without. With the load time I mean the time to load an image on the screen.

    The load times are way higher than when using the WritableBitmap.

    Canvas with images:

    it takes 160ms for 34 x 17 tiles using 48px images which is 0.28ms / tile
    it takes 650ms for 68 x 34 tiles using 24px images which is 0.28ms / tile

    WriteableBitmap

    it takes 2.5s for 265 x 107 tiles using 24px images which is 0.08ms / tile

    Sunday, February 07, 2010 10:21 AM
  • I just found this post on the internet:

    http://blogs.silverlight.net/blogs/msnow/archive/2009/06/29/game-programming-with-silverlight.aspx

    It's about a book from Mike Snow which covers gaming and even his map editor. I think I'm gonna read that book! =)

    Sunday, February 07, 2010 10:39 AM
  • How is your data structure setup? In my engine, creating a canvas with 1000 256x128 32bpp images take ~0.77 seconds both with WriteableBitmap and Canvas children. The pirmary advantage to the Canvas however is with dirty rendering. If I only update one of the elements in the canvas, the timings change. My benchmark then becomes 0.06 seconds whereas a more clever approach with the WriteableBitmap must be used, otherwise a full refresh would cost you another ~0.77 seconds.
    Sunday, February 07, 2010 11:05 AM
  • I'm using this code for testing: 

    int xTiles, yTiles;
    private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        DateTime dt = DateTime.Now;
    
        //Clear
        MapCanvas.Children.Clear();
    
        // 48px
        //xTiles = 34;
        //yTiles = 17;
    
        // 24px
        xTiles = 68;
        yTiles = 34;
    
        // Width
        MapCanvas.Width = xTiles * TileSize;
        MapCanvas.Height = yTiles * TileSize;
    
        this.DrawTilesCanvas(xTiles, yTiles, 0, 0);
    
        double ms = DateTime.Now.Subtract(dt).TotalMilliseconds;
    }
    
    public void DrawTilesCanvas(int xTiles, int yTiles, int xOffset, int yOffset)
    {
        for (int z = 0; z <= 2; z++)
        {
            for (int x = 0 + xOffset; x < xTiles + xOffset; x++)
            {
                for (int y = 0 + yOffset; y < yTiles + yOffset; y++)
                {
                    string key = String.Format(x + "," + y);
    
                    Image image = new Image() { Width = TileSize, Height = TileSize };
                    image.Source = new BitmapImage(new Uri("Tiles/1.png", UriKind.Relative));
    
                    Canvas.SetLeft(image, x * TileSize);
                    Canvas.SetTop(image, y * TileSize);
    
                    MapCanvas.Children.Add(image);
                }
            }
        }
    }
     
    Sunday, February 07, 2010 2:15 PM
  • Image image = new Image() { Width = TileSize, Height = TileSize };
    image.Source = new BitmapImage(new Uri("Tiles/1.png", UriKind.Relative));

     
    That would be your problem there. Not only are you fetching the image hundreds of times, you're creating copies of it. Your memory allocation must jump through the roof with that.

    What you should do is pre-load ImageBrush objects (tiles) you need into an array. Load once, use everywhere. From there, you create canvas objects and assign their background, width, and height. Pseudocode follows.

     

    // Initialize
    for all tiles that need to be shown
    {
    	BitmapSource source = new BitmapSource("url");
    	ImageBrush brush = new ImageBrush();
    	brush.ImageSource = source;
    	brush.AlignmentX = AlignmentX.Left;
    	brush.AlignmentY = AlignmentY.Top;
    	array.push(brush);
    }
    	
    // Create regions
    for each region
    {
    	for each tile
    	{
    		Canvas canvas = new Canvas();
    		canvas.Background = array[my_tile_id];
    		// Transform canvas. Set (x, y) and width / height.
    		
    		parent_canvas.Children.Add(canvas);
    	}
    }

    Now in the future, you only have to loop through the children of the region's canvas and change the child's background to the proper tile. Silverlight will manage the dirty rendering.

    Sunday, February 07, 2010 3:43 PM
  • I actually tried storing the brushes in a list (Dictionary), for the same reason you're describing. For some reason it was actually slower than the methode I posted before. Based on that, I took the following conclusion: "when using a single brush for multiple objects, it draws them in series (after eachother). When using a new instance of a brush for each object, it draws them parallel". I guess this is complete nonsence .. haha

    If you're saying this should be faster, I'll just try it again, maybe I just messed up the last time. Will post my results tonight!

    Thanks for taking the time to help me out!

    Monday, February 08, 2010 2:51 AM
  • I couldn't agree more with "TheNut". Creating an Image and load the content it in each iteration is overkill.

    I would use a Dictionary<string, Image> to cache the unique textures, where the string is your unique key (image name for example).

    Monday, February 08, 2010 4:00 AM
  • So, I've set-up a very basic project using the drawing method you described, with GPU acceleration enabled. The drawing part is much faster, and the memory consumption is drastically lower! But when panning (moving the map), the framerate drops to around 5fps. I just don't know why ..

    Download:
    http://dl.dropbox.com/u/1666558/MapEditorTest.zip

    TheNut, I would really appreciate it if you could just take a look at it. I think a Canvas with children is the way to go, but I want to get a good performance out of it.

    Regards,

    Bryan

    Monday, February 08, 2010 3:09 PM
  • Hey Bryan,

    Sorry for the delay. The reason your frame rates are bad is because you are dealing with one large image. This is very heavyweight on the video card, even with GPU acceleration enabled. Most video cards today lose out on their hardware acceleration once you pass a certain threshold (usually 4096x4096), but Silverlight seems to have a stricter requirement.

    As I mentioned before, you need to further split up your scene into regions. Each region is a group of tiles that forms a larger image, thus instead of dealing with 100 x 100 tiles, you deal with 10 x 10 regions, where each region has 10 x 10 tiles. you should also limit the amount of off-screen regions. So when you work on your map editor / tile engine, you should only have one set of off-screen regions wrapped along the edges of your map that will be smoothly scrolled in as you move. Don't load in 100 x 100 regions because you'll lose the performance you're trying to get.

    Here's an updated version of your code. With the changes, I get roughly 30 - 45 fps on my Pentium D 3GHz

    1) Remove the CacheMode from your ScrollViewer in the XAML code. It is added dynamically in code.

    2) You can play around with the count / xTiles / yTiles to see how certain configurations affect the performance.

     

    int xTiles = 10;
    int yTiles = 10;
    int count = 8;
    
    // Regions in the x-axis
    for (int w = 0; w <= count; w++)
    {
    	// Regions in the y-axis
    	for (int z = 0; z <= count; z++)
    	{
    		// Create region and set its cache mode
    		Canvas region = new Canvas();
    		region.CacheMode = new BitmapCache();
    
    		for (int y = 0; y < yTiles; y++)
    		{
    			for (int x = 0; x < xTiles; x++)
    			{
    				// Initialize
    				Canvas tile = new Canvas() { Width = TileSize, Height = TileSize };
    
    				// Background
    				tile.Background = imageBrush;
    
    				// Position
    				Canvas.SetZIndex(tile, z);
    				Canvas.SetLeft(tile, x * TileSize);
    				Canvas.SetTop(tile, y * TileSize);
    
    				// Draw
    				region.Children.Add(tile);
    			}
    		}
    		region.Width = TileSize * xTiles;
    		region.Height = TileSize * yTiles;
    		Canvas.SetLeft(region, z * region.Width);
    		Canvas.SetTop(region, w * region.Height);
    
    		MapTileCanvas.Children.Add(region);
    	}
    }
    MapTileCanvas.Width = TileSize * xTiles * count;
    MapTileCanvas.Height = TileSize * yTiles * count;
      
    Friday, February 12, 2010 8:50 AM
  • You're right, this is indeed fast! Didn't thought the region stuff would actually make such a difference. Now I just need to implement the viewport render, to reduce the memory usage. Thanks bigtime! Regards, Bryan
    Saturday, February 13, 2010 4:13 PM
  • This has been a very informational thread for me. I am working on a tile based game myself, turn based, after attempting it in Torque X and XNA. I like the approach given by TheNut, but am wondering, if you wanted to use say 256x128 32bit images, would you use this same approach?

    Although I would love to use 64x64 tiles, I plan on using maps made in dunjdinni such as this:

    http://www.dundjinni.com/forums/uploads/TheSim/Z2A_cavelower8_2.jpg

    It would seem in my case, that trying to do the approach above with 64x64 bit tiles would be rough, as most tiles are unique. Aggregating it into 256x128 would seem to make more sense to me in this case. I came upon this thread though and am wondering if using the region approach, and a viewport that is 75% of the users width/height, is something that could work.

    At my resolution of say 1680x1050, the viewport is around 1280x640 (75%), which is a 5x5 grid of 256x128 images. Would you suggest a 7x7 grid be rendered using the above approach, and then as the player moves (its turn based, so there is no rapid scrolling requirement), I just keep populating the outer ring of regions not viewable in the viewport? Any reply is appreciated.

    Monday, February 15, 2010 9:49 AM
  • GPU acceleration is the best choise when ur doing transformations on image based objects.

    What I would do in you're case, since you're handling a reasonable amount of tiles on the screen (20 x 10 = 200 tiles) is:

    • Create a Dictionairy with unique brushes
    • Create a giant canvas with a width and height equal to your map
    • Create a ViewPort which is the active screen 
    • Tells the giant canvas to render the right tiles (remove the tiles which are not visible!), based on the viewport.
    • Create a border around the ViewPort, which functions as a buffer for the tiles to load.
    • When moving, move the giant canvas, update the viewport, update the tiles

    The buffer is crucial! This means you only have to update the canvas (based on the viewport) when moved > 64pixels

    You could also try to implement a double buffered engine with 2 WriteableBitmaps. WriteableBitmaps also come in handy when dealing with backgrounds (multiple small objects) and such. Remember to use the Blit from WriteableBitmapExt when implementing the WriteableBitmap.

    Monday, February 15, 2010 10:58 AM
  • Hmm, that would mean 200 brushes, as those arent easily reused tiles. I am unfamiliar with the impact of large canvases, would a 500x500 level meaning a width of  500X256 = 128,000 be feasible?

    Monday, February 15, 2010 11:33 AM
  • How I solved my own problem (since I'm dealing with multiple sizes):

    • Create larger tiles (Canvas) which are 96x96 pixels.
    • Fill these tiles with smaller tiles using WritableBitmap Blit.

    What this solves:

    • I always have the same reasonable amount of tiles (objects) on the screen, instead of all those small image objects.
    • I don't have to implement the GPU Acceleration
    • The memory consumption is very low, since those 96x96 tiles are blitted.
    • It's easy to implement a viewport (virtual camera) with on-screen-tiles-rendering only, which wasn't possible with the oversized WriteableBitmap
    Monday, February 15, 2010 11:54 AM
  • I don't think that would be any problem. Remember you don't have to specify the width and height of the canvas in order to use it. And from what I know, the Canvas object doesn't have such restrictions. If it does, create multiple.

    I also don't think you need the region and GPU acceleration implementation. You're dealing with relatively large tiles (64px),

    Monday, February 15, 2010 12:09 PM
  • Hmm, good points. I could cut up my maps into 256x128 chunks, which would make it easier tilewise to deal with, would mean roughly 5x5  on screen worst case scenario, or 25 tiles. For interaction, I can create a logical grid(not the silverlight grid) to use (64x64) that fits the viewport. If I use canvas then, and blit to that, and only blit what can be seen, it sounds like that may be ideal given your suggestions. If I dont need to set the height or width of the canvas, this sounds like it would work like a champ. Ill test it out this week.Thank you for the suggestions.

    Monday, February 15, 2010 1:30 PM
  • My solution works perfect for my situation, where the tile size vary from 12px to 48px. Which means I can have from 500 up to 10.000 tiles on the screen.

    Since you're only using 64px tiles, you'll be just fine by drawing them separately (without the regions). This results in ~200 tiles on the screen.

    Of course you could implement the region stuff, but I think it's overkill.

    Monday, February 15, 2010 3:09 PM
  • Ahh ok. Would you suggest a canvas as the background (width and height not specified), and another canvas as the viewport, where the underlying canvas had a writeablebitmap that mapped to the size of the viewport?  It sounds like I could then just blit the 200 tiles when the character moves (they would have move points, it wouldnt be rapid scrolling). I did some testing of blitting 200 tiles to a writeablebitmap, and it was around 48 milliseconds, but it was pulling the images externally from a url via webclient.

    Monday, February 15, 2010 4:20 PM
  • I think I answered my own question.Ok, going to test some scenarios out, I have a much better grasp now of which direction to head in.

    Monday, February 15, 2010 9:48 PM
  • To be honest, I think blitting the entire scene every transformation, might be just an overkill. Remember that the ViewPort is just a class with a TopLeft and BottomRight coordinate.

    I'd try this:

    • Create a Canvas which acts as a an overall container (e.q. LayoutRoot)
    • Put the Rectangle Clip on that container, so you only show the right content. In most cases, use the Canvas.Width and Canvas.Height for the Clip. (Silverlight doesn't have the "ClipToBounds" from WPF)
    • Inside that overall container, put a Canvas: TileContainer, which will contain all your tiles
    • When moving:
      • Use Canvas.SetLeft and Canvas.SetTop on the TileContainer to move the scene
      • Update the ViewPort (which is are your map coordinates), based on the TileContainer location.
      • Remove the tiles which are out of range (e.q. tiles on the left, which moving right)
      • Add the new tiles (e.q. tiles on the right, when moving right.

    An example of drawing tiles based on the viewport (note: I used notepad). This is just for a start.

    int xStart = this.ViewPort.TopLeft.X;
    int yStart = this.ViewPort.TopLeft.Y;
    int xEnd = this.ViewPort.BottomRight.X;
    int yEnd = this.ViewPort.BottomRight.Y;
    
    for (int x = xStart; x <= xEnd; x++)
    {
       for (int y = yStart; y <= yEnd; y++)
       {
          string key = x + "," + y;
          if (!this.TilesOnScreen.Contains(key))
          {
             Canvas tile = new Canvas() { Width = 64; Height = 64; }
    
             // todo: apply and imagebrush to the background
    
             Canvas.SetLeft(tile, x * 64);
             Canvas.SetTop(tile, y * 64);
    
             this.TileContainer.Children.Add(tile);
    
             this.TilesOnScreen.Add(key);
          }
       }
    }  

    This means you only have to draw a couple of tiles when moving around. Remember you have to remove the ones you're not using anymore. I could set-up a basic project for you when I get home later today, only if you want that is.

    Tuesday, February 16, 2010 2:14 AM
  • Ahh, kinda like how Ajaxian does it with css and jquery then (They use divs as canvases). If you could make a sample project, that would be awesome. I am sure I would not be the only one who would love to have that type of resource availible :)

    Tuesday, February 16, 2010 2:52 AM
  • Ahh, kinda like how Ajaxian does it with css and jquery then (They use divs as canvases). If you could make a sample project, that would be awesome. I am sure I would not be the only one who would love to have that type of resource availible :)

    The sample project (with single objects):
    http://dl.dropbox.com/u/1666558/TileAppDemo.zip

    The sample project (with regions & GPU acceleration):
    http://dl.dropbox.com/u/1666558/TileAppDemoGPU.zip

    You can try different tile sizes, border (buffer), region sizes by setting the variables in Settings.cs

    Any feedback is welcome!

    Regards,
    Bryan

    Tuesday, February 16, 2010 3:33 PM
  • Wow, that is kickass! Lot of good stuff in there to digest. That is exactly what I am wanting to do, performance is pretty snappy on the single object one (the one I tested). Thank you for the effort Bryan!Cool

    Tuesday, February 16, 2010 10:16 PM
  • I have had time to use the concepts from the single object and integrate it into my project. It works, however I am finding that if you use external image files, and use web client to download them, you can see the images as they are downloaded and put on the canvas. My maps tiles are unique, so it is downloading 200 ish tiles at 64x64. The sample project uses internal images, and there are only two, so performance is snappy.

     

    I am thinking of doing a preload of some sort, and using the browsers natural caching of images. Has anyone run into this scenario where using lots of external images causes a slow draw on the screen?

    Monday, February 22, 2010 9:19 PM