2016-03-29 9 views
3

Ich mache gerade ein Kachel-basiertes Spiel in C#, aber jedes Mal, wenn ich die Kacheln zeichne, verbraucht es viel CPU, und wenn die Kacheln größer werden (wenn ich das Spiel im Vollbildmodus mache), verbraucht es noch mehr. Das ist meine Tile-Klasse:Wie man Kacheln mit Graphics.Draw effizient rendert?

public class Tiles 
{ 
    //PRIVATE : 

    //variabiles 
    private int XPosition, YPosition; 
    private Image Texture; 
    private bool Colidable; 
    private int SizeW = 32; 
    private int SizeH = 32; 
    private Resizer resizer = new Resizer(); 
    //methods 




    //PUBLIC : 

    //variabiles 


    //methods 

    //CONSTRUCTOR 
    public Tiles(int _x,int _y,Image _i, int _sW = 32, int _sH = 32, bool _c = false) 
    { 
     XPosition = _x;//set position X 
     YPosition = _y;//set position Y 
     SizeW = _sW; 
     SizeH = _sH; 
     Texture = resizer.ResizeImage(_i, SizeW, SizeH) ;// set texture 

     Colidable = _c;//set if the tile is colidable,default : false 
     resizer = null; 
    } 

    //DRAW METHOD 
    //gets graphics object to draw on, adn draws at the position of the tile 
    public void Draw(Graphics _g) 
    { 
     _g.DrawImage(this.Texture, this.XPosition, this.YPosition); 
    } 

    //GET PRIVATE MEBERS 
    //returns if the tile is colidable 
    public bool getColidable() 
    { 

     return this.Colidable; 

    } 
} 

und das ist, wie ich die Fliesen zeichnen:

private void DrawMap(Graphics _g) 
    { 
     //CALLS THE DRAW METHOD OF EACH TILE 
     for (int i = 0; i < MAP_WIDTH; i++) 
     { 
      for (int j = 0; j < MAP_HEIGHT; j++) 
      { 
       Tile[i, j].Draw(_g); 
      } 

     } 

    } 
    bool TilesUpdate = false; 


    private void _Window_Paint(object sender, PaintEventArgs e) 
    { 
     e.Graphics.Clear(Color.Black); 

     if (isGameRunning) 
     { 

      DrawMap(e.Graphics); 
     } 
     else 
     { 
      FullRezolutionBtn.Draw(e.Graphics); 
      BigRezolutionBtn.Draw(e.Graphics); 
      NormalRezolutionBtn.Draw(e.Graphics); 
     } 

    } 


    private void Update_Tick(object sender, EventArgs e) 
    { 
     Invalidate(); 

    } 

ich, dass die Karte 20 x 20 Fliesen sind erwähnen will, und es ist cosuming rund 50% der CPU, wenn es Vollbild ist.

+0

Der Code, den Sie geschrieben haben, sieht gut aus, ich sehe nicht, wie es beschleunigt werden kann. Versuchen Sie, Smart Invaliding und Smart Drawing auszuführen (z. B. nur ungültige Teile zu zeichnen) –

+0

Wie kann ich prüfen, ob ein Teil ungültig ist? –

+0

'e.ClipRectangle.IntersectsWith (part.Rectangle)' –

Antwort

1

verwenden Wie ich in den Kommentaren erwähnt, sollte die Richtung weniger Malerei sein. Eine Möglichkeit besteht darin, Teile des Zeichnungsbereichs nur dann ungültig zu machen und zu zeichnen, wenn sich etwas mit diesem Abschnitt ändert. Windows selbst führt eine solche Optimierung für Steuerelemente/Fenster durch.

Hier ist ein Beispiel. Schauen Sie sich an, wie die Klasse Gadget ihr Rechteck ungültig macht, wenn sich eine Eigenschaft ändert. Dann werden während des Malens nur Rechtecke gezeichnet, die sich mit e.ClipRectange schneiden. Dies reduziert die Anzahl der Zeichenoperationen stark.

using System; 
using System.Drawing; 
using System.Windows.Forms; 

namespace Samples 
{ 
    class Gadget 
    { 
     public readonly Control Canvas; 

     public Gadget(Control canvas) { Canvas = canvas; } 

     private Rectangle bounds; 
     public Rectangle Bounds 
     { 
      get { return bounds; } 
      set 
      { 
       if (bounds == value) return; 
       // NOTE: Invalidate both old and new rectangle 
       Invalidate(); 
       bounds = value; 
       Invalidate(); 
      } 
     } 

     private Color color; 
     public Color Color 
     { 
      get { return color; } 
      set 
      { 
       if (color == value) return; 
       color = value; 
       Invalidate(); 
      } 
     } 

     public void Invalidate() 
     { 
      Canvas.Invalidate(bounds); 
     } 

     public void Draw(Graphics g) 
     { 
      using (var brush = new SolidBrush(color)) 
       g.FillRectangle(brush, bounds); 
     } 
    } 


    static class Program 
    { 
     [STAThread] 
     static void Main() 
     { 
      Application.EnableVisualStyles(); 
      Application.SetCompatibleTextRenderingDefault(false); 

      var form = new Form { WindowState = FormWindowState.Maximized }; 
      int rows = 9, cols = 9; 
      var gadgets = new Gadget[rows, cols]; 
      var rg = new Random(); 
      Color[] colors = { Color.Yellow, Color.Blue, Color.Red, Color.Green, Color.Magenta }; 
      int size = 64; 
      var canvas = form; 
      for (int r = 0, y = 8; r < rows; r++, y += size) 
       for (int c = 0, x = 8; c < cols; c++, x += size) 
        gadgets[r, c] = new Gadget(canvas) { Color = colors[rg.Next(colors.Length)], Bounds = new Rectangle(x, y, size, size) }; 
      int paintCount = 0, drawCount = 0; 
      canvas.Paint += (sender, e) => 
      { 
       paintCount++; 
       for (int r = 0; r < rows; r++) 
       { 
        for (int c = 0; c < cols; c++) 
        { 
         if (e.ClipRectangle.IntersectsWith(gadgets[r, c].Bounds)) 
         { 
          gadgets[r, c].Draw(e.Graphics); 
          drawCount++; 
         } 
        } 
       } 
       form.Text = $"Paint:{paintCount} Draw:{drawCount} of {(long)paintCount * rows * cols}"; 
      }; 
      var timer = new Timer { Interval = 100 }; 
      timer.Tick += (sender, e) => 
      { 
       gadgets[rg.Next(rows), rg.Next(cols)].Color = colors[rg.Next(colors.Length)]; 
      }; 
      timer.Start(); 


      Application.Run(form); 
     } 
    } 
} 
+0

Vielen Dank! Dies ist genau das, was ich gesucht habe! Vielen Dank! –

0

Nicht sicher, wie Ihre Resizer-Klasse funktioniert. Ich denke, es gibt ein Problem, wenn Sie jedes Bild jedes Mal neu sortieren.

Texture = resizer.ResizeImage(_i, SizeW, SizeH) ;// set texture 

ich würde über Zeilen wie diese zur gleichen Zeit aktualisieren, um die Draw-Funktion von Fliesen wie unten

Texture = _i;// set texture but do not resize image now 

ersetzen.

public void Draw(Graphics _g) 
{ 
    //now specify the location and size of the image. 
    _g.DrawImage(Texture , new Rectangle(this.XPosition, this.YPosition, SizeW, SizeH)); 

} 

hoffentlich sollte es die Leistung verbessern. wenn es flackern dann können Sie Double Buffer

Verwandte Themen