I am developing zoo simulator project. It contains three thing types to draw: a map, animal environments and the animals themselves. The map is too big to fit on screen, player needs to move screen to see other parts of it. I am using a timer to draw. On its tick, it calls Invalidate()
for the form being drawing on. In ZooForm_Paint
method, I first draw every thing in the map on mapBuffer
Bitmap. Since mapBuffer
is too big to fit on screen, I draw (on screen) the part of mapBuffer
the player is where.
Unfortunately, it seems that drawing everything in the map (although it may not be viewed) on mapBuffer
slows the game. Can I draw my evironments and animals without need to draw entire map first?
How?
My code:
public void DrawGame(Graphics g, ref Point locationOnMap)
{
this.drawBufferMap();
this.drawMapLocation(g, ref locationOnMap);
}
private void drawBufferMap()
{
Bitmap buffer = new Bitmap(this.map.Size.Width, this.map.Size.Height);
开发者_如何转开发 using (Graphics graphics = Graphics.FromImage(buffer))
{
graphics.DrawImageUnscaled(this.map.Picture, new Point()); // draw entire map
foreach (var item in this.zoo.Environments) // draw all env.
{
graphics.DrawImageUnscaled(item.Picture, item.Bounds.Location);
}
foreach (var item in this.zoo.ILocatables) // draw all ILocatables
{
graphics.DrawImageUnscaled(item.Picture, item.Location);
}
}
if (this.mapBuffer != null)
{
this.mapBuffer.Dispose();
}
this.mapBuffer = buffer;
}
private void drawMapLocation(Graphics g, ref Point location)
{
g.DrawImage(this.mapBuffer, new Rectangle(0, 0, viewSize.Width, viewSize.Height),
new Rectangle(location.X, location.Y, viewSize.Width, viewSize.Height), GraphicsUnit.Pixel);
}
I don't think you are going to get any easy solutions. I can offer a few tips and opinions:
- You seem to be creating a new
BitMap
every time you paint the screen. This is definitely not a good idea, as large bitmaps are absolutely huge in terms of memory. What you probably want to do is create one when your game loads, and then simply clear it and repaint it at every frame. I think this is probably one of the bigger performance issues you have. - There are a number of optimisations you could make afterwards. E.g. you are "rendering" the image that you will end up painting to the screen on the user interface thread. If the rendering process takes long, this will be noticeable. Typically this work happens on a background thread, and then the UI thread just checks if it can repaint using the new image. (I am simplifying things greatly here).
- For graphics intensive applications, WinForms is not a particularly good environment, as others have pointed out. You will not get any hardware acceleration at all. Moving to XNA is one option, but if your application is also quite rich in terms of standard WinForms screens and controls, this is probably not an easy option. Another suggested alternative might be WPF, where you might be able to get away with using transformations to move things around, which are hardware accelerated, and are not too dissimilar to a WinForms application (well, you don't need to implement your own buttons, etc).
Hope this helps a bit.
As Daniel pointed out: creating a new bitmap each time you need to draw your map will decrease performance. Reuse the same bitmap over and over instead.
Creating a bitmap larger that you need is also very bad for performance. If you need it to scroll around, then it's fine. But if you paint a new image each time anyway, then you should just create it exactly the same size you need. Then you can call Graphics.TranslateTransform to compensate for the new coordinates so you can leave your existion code unchanged.
This will make it possible for GDI+ to clip your graphics and simply just don't draw things outside your map bitmap - which will speed things up.
精彩评论