[.net] 2D level editor with GDI+, speed issues

Started by
10 comments, last by GameSQUID 17 years, 11 months ago
Hi, I'm making a 2D level editor (using Sharp Develop), and I'm using GDI+ to show the graphics. While I have some experience in .net and a lot of experience in programming in general, I don't have much experience when it comes to graphical .NET programming. My problem is that each time I draw on my map (which is a panel), it takes a while to update. I know this is because I'm doing it wrong, but I don't know how to do it better. Here's how I do it : Whenever something changes, I loop trough all my layers and build a bitmap for each layer. The layers have a 2D arraylist with references to tile objects, which contain a bitmap (and some other properties that are irrelevant now). So I loop trough the arraylist and draw each tile's bitmap on the layer's bitmap. Then I draw each layer's bitmap to another bitmap, and I draw this to my panel's Graphics-object. I know there must be a much better way to handle this, so any insight would be greatly appreciated. Thanks!
Advertisement
You could use something like Tile Studio to generate code to create the level for you and not have to worry about creating yet another tool for your game. This is what I ended up using for BooGame. It means that you can spend more time working on the final product rather then the tools involved.
Rob Loach [Website] [Projects] [Contact]
I have already tried a number of map editors, including Tile Studio, but haven't found one that suits my needs.
I need to be able to have multiple layers. Mappy, for instance, supports this, but you can only view the current layer and one in the background (onion skin), you can't view them all at the same time.
Tile Studio is worse, because while you can edit different maps, I can't see a way to show them all on top of eachother. Plus, it puts all my tiles in a single row at the bottom, which isn't very convenient for me.
I have a editor built into my 2D GDK Endogine, which supports any number of layers (with parallax movement speed offsets if needed), but the output is an XML file that isn't really *tiled*, as the sprites are not limited to any size, position or rotation.

If you use its snap-to-grid function, it could be used for a tiled approach, and you should be able to parse the XML into an array upon import that suits your engine.

I'll send it over if you're interested (haven't used it in a while, so it might take a day to ensure that my latest architectural changes didn't break it).
Hi,

That would be great. The fact that it isn't fully tile-based isn't a problem, plus I can always parse the xml and make something else out of it.

I would really appreciate it if you could send this to me. You can mail it to squid [-at-] gamesquid [-dot-] com

Thanks!
Well, I finally found a map editor that seems to suit my needs, it's a java based editor called Tiled. I'm still interested in your editor though, it might be even better :)
If it isn't, I'll have to make it better! Seriously, I'm always interested in good features, so if you find it lacking please let me know - even if I don't have time to add the stuff before your deadline, they'll be there for future users.

If you're looking to do isometric stuff, I have an add-on with several features specific to that domain of problems. Not so user-friendly ATM, though.
Quote:Original post by GameSQUID
Whenever something changes, I loop trough all my layers and build a bitmap for each layer. The layers have a 2D arraylist with references to tile objects, which contain a bitmap (and some other properties that are irrelevant now). So I loop trough the arraylist and draw each tile's bitmap on the layer's bitmap. Then I draw each layer's bitmap to another bitmap, and I draw this to my panel's Graphics-object.

I know there must be a much better way to handle this, so any insight would be greatly appreciated.

Thanks!


If you end up fixing your own code then here is what you need to do (If I understand what you are doing correctly.) It sounds like you are redrawing the entire frame from scratch with each update, and this is kind of wastefull since the a great deal of the scene remains the same. Now since you have been creating layered bitmaps in RAM you already know everything you need to do this.

You start by having a set of cached bitmaps. These persist in RAM after drawing so they would probably want to be module level variables, or possibly static (whatever makes sense for your code) Anyway, You update the one layer that has changed, That makes one draw. Then You draw the layers together. The rest of the cached layers will remain untouched and the work will already have been done from the previous run.

You'll continue to use the current code but only when the whole scene needs to be redrawn, For example when the user scrolls and a different part of the map is now visible. When you do have to draw the whole scene, you are creating the layers that will be kept for future use when only part of the scene needs to be updated.

----

An Alternative approach. This is the one I use in my code. You have one panel/picture box/form anything with an image component. You create a graphics object for that image. Then you write a procedure that draws one x,y location. This code draws a tile for each layer at that location on the control's image. This method is passed the graphics object created from the component. Now, when one spot is updated you call this procedure and it updates the relevant parts of the screen. So this is N draws where N is the layer count. Nice and fast. Now when you need to updated the whole screen, You call the procedure inside of nested for loops, each time passing the graphics object that was only created once.

----

The basic idea is to reduce the number of times you call Graphics.Draw* to an absolute minimum. And to reduce the number of times you create a graphics object to Just once if possible. These are the two most expensive operations in GDI+ graphics, and should reduce to a minimum.

Granted I am sure there are faster ways by bitblitting RAM and all sorts of old school stuff, but for an editor that doesn't need blazing speed this should do well enough.

Cheers!
Thanks a lot, zangetsu. I haven't decided yet if I will still make my own editor, but I might, so this is really helpful.
I knew my code was a bit wastefull, but couldn't really think of a better way to do it. But now that I read your post, I'm wondering why I didn't think of that myself :)
To be fair, I did it the slow way first before I found some webpage that I have long since forgotten that described a better way.

This topic is closed to new replies.

Advertisement