Difference between revisions of "Developing with Graphics/de"

From Lazarus wiki
Jump to navigationJump to search
Line 167: Line 167:
 
Viele Programme zeichnen ihre Ausgabe als 2D Grafik in die GUI. Wenn diese Grafiken schnell geändert werden müssen, werden sie bald einem Problem begegnen: sich schnell ändernde Grafiken flimmern oft auf dem Bildschirm. Das passiert, weil der Zeichenprozess Zeit benötigt und der Benutzer deshalb manchmal ein vollständiges Bild, manchmal aber auch nur ein teilweise gezeichnetes Bild sieht.  
 
Viele Programme zeichnen ihre Ausgabe als 2D Grafik in die GUI. Wenn diese Grafiken schnell geändert werden müssen, werden sie bald einem Problem begegnen: sich schnell ändernde Grafiken flimmern oft auf dem Bildschirm. Das passiert, weil der Zeichenprozess Zeit benötigt und der Benutzer deshalb manchmal ein vollständiges Bild, manchmal aber auch nur ein teilweise gezeichnetes Bild sieht.  
  
Aber wie kann ich das Flimmern vermeiden und das beste Zeichentempo erreichen? Natürlich können sie mit Hardwarebeschleunigung unter Verwendung von OpenGL arbeiten, aber dieser Ansatz ist für kleine Programme oder alte Computer ziemlich ungeeignet. Dieses Tutorial will sich auf das Zeichnen in ein TCanvas konzentrieren. Wenn sie Hilfe brauchen zu OpenGL, werfen sie einen Blick auf das Beispiel, das mit Lazarus geliefert wird oder [[GLScene]]. Sie können auch A.J. Venter's Gamepack verwenden, das eine doppelt gepufferte Zeichenfläche (double-buffered canvas) und eine Sprite-Komponente bereitstellt.
+
Aber wie kann ich das Flimmern vermeiden und das beste Zeichentempo erreichen? Natürlich können sie mit Hardwarebeschleunigung unter Verwendung von OpenGL arbeiten, aber dieser Ansatz ist für kleine Programme oder alte Computer ziemlich ungeeignet. Dieses Tutorial konzentriert sich auf das Zeichnen in ein TCanvas. Wenn Sie Hilfe brauchen zu OpenGL, werfen Sie einen Blick auf das Beispiel, das mit Lazarus geliefert wird oder auf [[GLScene]]. Sie können auch A.J. Venter's Gamepack verwenden, das eine doppelt gepufferte Zeichenfläche (double-buffered canvas) und eine Sprite-Komponente bereitstellt.
  
 
Jetzt wollen wir die Optionen untersuchen, die wir für das Zeichnen auf eine Zeichenfläche (Canvas) haben:
 
Jetzt wollen wir die Optionen untersuchen, die wir für das Zeichnen auf eine Zeichenfläche (Canvas) haben:
* [[#Draw to a TImage|Zeichnen in ein TImage]]
+
* [[#Zeichnen in ein TImage|Zeichnen in ein TImage]]
* [[#Draw on the OnPaint event|Draw on the OnPaint event of the form, a TPaintBox or another control]]
+
* [[#Zeichnen im OnPaint-Ereignis des Formulars, der TPaintBox oder einem anderen Control|Zeichnen im OnPaint-Ereignis des Formulars, der TPaintBox oder einem anderen Control]]
* [[#Create a custom control which draws itself|Create a custom control which draws itself]]
+
* [[#Ein CustomControl erzeugen, das sich selbst zeichnet|Ein CustomControl erzeugen, das sich selbst zeichnet]]
* [[#Using A.J. Venter's gamepack|A.J. Venter's Gamepack benutzen]]
+
* [[#A.J. Venter's Gamepack benutzen|A.J. Venter's Gamepack benutzen]]
  
 
=== Zeichnen in ein TImage ===
 
=== Zeichnen in ein TImage ===
Line 202: Line 202:
 
   end;
 
   end;
  
Anmerkung: Bei Image1.OnPaint zeigt Image1.Canvas  to the volatile visible area. Outside of Image1.OnPaint the Image1.Canvas points to Image1.Picture.Bitmap.Canvas.
+
Anmerkung: Bei Image1.OnPaint zeigt Image1.Canvas  auf den flüchtig sichtbaren Bereich. Außerhalb von Image1.OnPaint zeigt Image1.Canvas auf Image1.Picture.Bitmap.Canvas.
  
 
Ein anderes Beispiel:
 
Ein anderes Beispiel:
Line 224: Line 224:
 
</code>
 
</code>
  
==== Painting on the volatile visual area of the TImage ====
+
==== Im flüchtig sichtbaren Bereich einer TImage zeichnen ====
  
You can only paint on this area during OnPaint. OnPaint is eventually called automatically by the LCL when the area was invalidated. You can invalidate manually the area with Image1.Invalidate. This will not call immediately OnPaint and you can call Invalidate as mny times as you want.
+
Sie können nur während des OnPaint-Ereignisses in diesen Bereich zeichnen. OnPaint wird eventuell automatisch von der LCL aufgerufen, wenn der Bereich invalidiert wurde. Sie können den Bereich mit Image1.Invalidate manuell invalidieren. Dies ruft OnPaint nicht unmittelbar auf und Sie können Invalidate so oft Sie wollen aufrufen.
  
 
   procedure TForm.Image1Paint(Sender: TObject);
 
   procedure TForm.Image1Paint(Sender: TObject);
Line 237: Line 237:
 
   end;
 
   end;
  
=== Draw on the OnPaint event ===
+
=== Zeichnen im OnPaint-Ereignis des Formulars, der TPaintBox oder einem anderen Control ===
In this case all the drawing has to be done on the OnPaint event of the form. It doesn't remain on the buffer, like on the TImage.
+
In diesem Fall muss alles Zeichnen im OnPaint-Ereignis des Formulars passieren. Die Elemente bleiben nicht im Buffer erhalten, wie bei TImage.
  
=== Create a custom control which draws itself ===
+
=== Ein CustomControl erzeugen, das sich selbst zeichnet ===
Die Erzeugung eines custom control hat den Vorteil der Strukturing ihres Codes und sie können das Bedienelement wiederverwenden. Dieser Ansatz ist sehr schnell, aber er kann dennoch Flimmern erzeugen if you don't draw to a TBitmap first and then draw to the canvas. In diesem Fall besteht keine Notwendigkeit das OnPaint Ereignis des Bedienelements zu verwenden.
+
Die Erzeugung eines CustomControl hat den Vorteil der Strukturierung ihres Codes und sie können das Bedienelement wiederverwenden. Dieser Ansatz ist sehr schnell, aber er kann dennoch Flimmern erzeugen, wenn Sie nicht erst in ein TBitMap und dann in das Canvas zeichnen. In diesem Fall besteht keine Notwendigkeit das OnPaint Ereignis des Bedienelements zu verwenden.
  
Hier ist ein Beispiel custom control:
+
Hier ist ein Beispiel CustomControl:
  
 
<code>
 
<code>
Line 308: Line 308:
 
</code>
 
</code>
  
Das Setzen von Top und Left auf null ist nicht notwendig, seit dies die Standardposition ist, but is done so to reinforce where the control will be put.
+
Das Setzen von Top und Left auf 0 ist nicht notwendig, da dies die Standardposition ist, aber es ist sinnvoll, um diese Position zu verdeutlichen.
  
 
"MyDrawingControl.Parent := Self;" ist sehr wichtig und sie werden ihr Bedienelement nicht sehen, wenn sie es nicht tun.
 
"MyDrawingControl.Parent := Self;" ist sehr wichtig und sie werden ihr Bedienelement nicht sehen, wenn sie es nicht tun.
Line 314: Line 314:
 
"MyDrawingControl.DoubleBuffered := True;" wird benötigt, um das Flimmern unter Windows zu vermeiden. Es hat keinen Effekt unter gtk.
 
"MyDrawingControl.DoubleBuffered := True;" wird benötigt, um das Flimmern unter Windows zu vermeiden. Es hat keinen Effekt unter gtk.
  
=== Using A.J. Venter's gamepack ===
+
=== A.J. Venter's Gamepack benutzen ===
  
The gamepack approach is to draw everything to one double-buffered canvas, which only gets updated to the visible canvas when you are ready. This takes quite a bit of code, but it has the advantage of being able to do large rapidly changing scenes with multiple sprites on them. If you wish to use this approach, you may be interested in A.J. Venter's gamepack, a set of components for game development in Lazarus, which provides a double-buffered display area component as well as a sprite component, designed to integrate well with one another. Sie können gamepack erhalten mittels subversion:<br />
+
Der Gamepack-Vorstoß bedeutet, alles in ein doppelt gebuffertes Canvas zu zeichnen, dessen sichtbarer Bereich erst dann aktualisiert wird, wenn Sie fertig sind. Dies benötigt etwas mehr Code, aber es schafft die Fähigkeit, große sich dynamisch ändernde Grafiken mit mehreren Elementen zu verarbeiten. Wenn Sie diese Technik verwenden möchten, sollten Sie sich das A.J. Venter's Gamepack ansehen, ein Set von Komponenten zur Entwicklung von Spielen mit Lazarus, das eine doppelt gebufferte Anzeigeflächen-Komponente sowie eine Sprite-Komponente bietet, designed um sich gegenseitig ideal zu intergrieren. Sie können Gamepack mittels subversion erhalten:<br />
 
<code>
 
<code>
 
svn co svn://silentcoder.co.za/lazarus/gamepack
 
svn co svn://silentcoder.co.za/lazarus/gamepack
 
</code>
 
</code>

Revision as of 21:07, 22 September 2008

Deutsch (de) English (en) español (es) français (fr) italiano (it) 日本語 (ja) 한국어 (ko) Nederlands (nl) português (pt) русский (ru) slovenčina (sk) 中文(中国大陆)‎ (zh_CN) 中文(台灣)‎ (zh_TW)

Diese Seite wird der Anfang von Tutorials sein bezüglich der Manipulation von Bitmaps und anderen Grafiken. Da ich kein Grafikprogrammierer bin, lade ich alle ein ihr Wissen zu teilen! Fügen sie einfach einen Link zum nächsten Abschnitt hinzu, fügen eine Seite hinzu und erzeugen ihren eigenen Wiki Artikel.

Auf dieser Seite werden einige allgemeine Informationen geboten.

Andere Grafik Artikel

  • GLScene - Eine Portierung der visual OpenGL graphics Library GLScene
  • TAChart - Chartkomponente für Lazarus
  • PlotPanel - Ähnlich wie TAChart
  • PascalMagick - ein einfach zu verwendentes API für die Kopplung mit ImageMagick, einer freien multiplattform Softwaresammlung um Bitmaps zu erzeugen, zu bearbeiten und zu entwerfen.
  • LazRGBGraphics - Ein Package für fast in memory image processing and pixel manipulations (like scan line).
  • Perlin Noise - Ein Artikel über die Verwendung von Perlin Noise in LCL Anwendungen.

Arbeiten mit TBitmap

Das erste woran sie denken sollten ist, dass Lazarus Plattformunabhängig sein soll. Daher kommen alle Methoden, welche die Windows API Funktionalität nutzen, nicht in Frage. Daher wird eine Methode wie ScanLine nicht von Lazarus unterstützt, weil sie für Geräte-unabhängige Bitmaps gedacht ist und Funktionen von GDI32.dll verwendet.

Geben sie acht, dass, wenn sie nicht die Breite und Höhe ihrer TBitmap spezifizieren, sie die Standardmaße haben wird, welche ziemlich klein sind.

Ein fading Beispiel

Sagen wir sie wollen ein Fadendes Bild erstellen. In Delphi können sie etwas wie dieses tun:

type
  PRGBTripleArray = ^TRGBTripleArray;
  TRGBTripleArray = array[0..32767] of TRGBTriple;

procedure TForm1.FadeIn(aBitMap: TBitMap);
var
  Bitmap, BaseBitmap: TBitmap;
  Row, BaseRow: PRGBTripleArray;
  x, y, step: integer;
begin
  Bitmap := TBitmap.Create;
  try
    Bitmap.PixelFormat := pf32bit;  //  oder pf24bit
    Bitmap.Assign(aBitMap);
    BaseBitmap := TBitmap.Create;
    try
      BaseBitmap.PixelFormat := pf32bit;
      BaseBitmap.Assign(Bitmap);
      for step := 0 to 32 do begin
        for y := 0 to (Bitmap.Height - 1) do begin
          BaseRow := BaseBitmap.Scanline[y];
          Row := Bitmap.Scanline[y];
          for x := 0 to (Bitmap.Width - 1) do begin
            Row[x].rgbtRed := (step * BaseRow[x].rgbtRed) shr 5;
            Row[x].rgbtGreen := (step * BaseRow[x].rgbtGreen) shr 5; // Fading
            Row[x].rgbtBlue := (step * BaseRow[x].rgbtBlue) shr 5;
          end;
        end;
        Form1.Canvas.Draw(0, 0, Bitmap);
        InvalidateRect(Form1.Handle, nil, False);
        RedrawWindow(Form1.Handle, nil, 0, RDW_UPDATENOW);
      end;
    finally
      BaseBitmap.Free;
    end;
  finally
    Bitmap.Free;
  end;
end;

Diese Funktion könnte in Lazarus so implementiert werden:

procedure TForm1.FadeIn(ABitMap: TBitMap);
var
  SrcIntfImg, TempIntfImg: TLazIntfImage;
  ImgHandle,ImgMaskHandle: HBitmap;
  FadeStep: Integer;
  px, py: Integer;
  CurColor: TFPColor;
  TempBitmap: TBitmap;
begin
  SrcIntfImg:=TLazIntfImage.Create(0,0);
  SrcIntfImg.LoadFromBitmap(ABitmap.Handle,ABitmap.MaskHandle);
  TempIntfImg:=TLazIntfImage.Create(0,0);
  TempIntfImg.LoadFromBitmap(ABitmap.Handle,ABitmap.MaskHandle);
  TempBitmap:=TBitmap.Create;
  for FadeStep:=1 to 32 do begin
    for py:=0 to SrcIntfImg.Height-1 do begin
      for px:=0 to SrcIntfImg.Width-1 do begin
        CurColor:=SrcIntfImg.Colors[px,py];
        CurColor.Red:=(CurColor.Red*FadeStep) shr 5;
        CurColor.Green:=(CurColor.Green*FadeStep) shr 5;
        CurColor.Blue:=(CurColor.Blue*FadeStep) shr 5;
        TempIntfImg.Colors[px,py]:=CurColor;
      end;
    end;
    TempIntfImg.CreateBitmap(ImgHandle,ImgMaskHandle,false);
    TempBitmap.Handle:=ImgHandle;
    TempBitmap.MaskHandle:=ImgMaskHandle;
    Canvas.Draw(0,0,TempBitmap);
  end;
  SrcIntfImg.Free;
  TempIntfImg.Free;
  TempBitmap.Free;
end;

Der Lazarus Code auf dieser Seite wurde dem $LazarusPath/examples/lazintfimage/fadein1.lpi Projekt entnommen. Wenn sie einen einfachen Start in die Grafikprogrammierung suchen, dann werfen sie einen näheren Blick auf dieses Beispiel.

Transparent zeichnen mit Bitmaps

Ein neues Feature, implementiert in Lazarus 0.9.11, sind farbtransparente Bitmaps. Bitmap-Dateien (*.BMP) können keine Informationen über Transparenz speichern, aber Sie können dies zur Laufzeit umgehen, indem Sie eine Transparenz-Farbe wählen, mit der Sie die transparenten Bereiche markieren. Bei Win32-Anwendungen ist dies ein üblicher Trick.

Das folgende Beispiel lädt eine Bitmap aus einer Windows Ressource, wählt eine Farbe für die Transparenz (clFuchsia) und zeichnet es auf die Zeichenfläche (Canvas).

procedure MyForm.MyButtonOnClick(Sender: TObject);
var
  buffer: THandle;
  bmp: TBitmap;
  memstream: TMemoryStream;
begin
  bmp := TBitmap.Create;

  buffer := Windows.LoadBitmap(hInstance, MAKEINTRESOURCE(ResourceID));

  if (buffer = 0) then exit; // Fehler beim Laden der Bitmap

  bmp.Handle := buffer;
  memstream := TMemoryStream.create;
  try
    bmp.SaveToStream(memstream);
    memstream.position := 0;
    bmp.LoadFromStream(memstream);
  finally
    memstream.free;
  end;

  bmp.Transparent := True;
  bmp.TransparentColor := clFuchsia;

  MyCanvas.Draw(0, 0, bmp);

  bmp.Free; // Gibt belegte Ressourcen frei
end;

Beachten sie, daß mit TMemoryStream die Speicheroperationen ausgeführt werden. Sie sind notwendig, um das korrekte Laden des Bildes sicherzustellen.

Ein Bildschirmfoto erstellen

Seit Lazarus 0.9.16 können sie die LCL verwenden um plattformunabhängig Bildschirmfotos aufzunehmen. Der folgende Beispielcode zeigt es (funktioniert unter GTK2 und Win32, aber gegenwärtig nicht unter GTK1):

  uses LCLIntf, LCLType;

  ...

var
  MyBitmap: TBitmap
  ScreenDC: HDC;
begin
  MyBitmap := TBitmap.Create;
  ScreenDC := GetDC(0);
  MyBitmap.LoadFromDevice(ScreenDC);
  ReleaseDC(ScreenDC);

  ...

Motion Graphics - Wie man flimmern vermeidet

Viele Programme zeichnen ihre Ausgabe als 2D Grafik in die GUI. Wenn diese Grafiken schnell geändert werden müssen, werden sie bald einem Problem begegnen: sich schnell ändernde Grafiken flimmern oft auf dem Bildschirm. Das passiert, weil der Zeichenprozess Zeit benötigt und der Benutzer deshalb manchmal ein vollständiges Bild, manchmal aber auch nur ein teilweise gezeichnetes Bild sieht.

Aber wie kann ich das Flimmern vermeiden und das beste Zeichentempo erreichen? Natürlich können sie mit Hardwarebeschleunigung unter Verwendung von OpenGL arbeiten, aber dieser Ansatz ist für kleine Programme oder alte Computer ziemlich ungeeignet. Dieses Tutorial konzentriert sich auf das Zeichnen in ein TCanvas. Wenn Sie Hilfe brauchen zu OpenGL, werfen Sie einen Blick auf das Beispiel, das mit Lazarus geliefert wird oder auf GLScene. Sie können auch A.J. Venter's Gamepack verwenden, das eine doppelt gepufferte Zeichenfläche (double-buffered canvas) und eine Sprite-Komponente bereitstellt.

Jetzt wollen wir die Optionen untersuchen, die wir für das Zeichnen auf eine Zeichenfläche (Canvas) haben:

Zeichnen in ein TImage

A TImage-Objekt besteht aus zwei Teilen: Ein TGraphic-Objekt, üblicherweise ein TBitmap, das das persistente Bild und die sichtbare Fläche enthält, die bei jedem OnPaint neu gezeichnet wird. Eine Änderung der Größe von TImage ändert nicht die Größe der Bitmap. Auf die Grafik (oder die Bitmap) kann man über Image1.Picture.Graphic (oder Image1.Picture.Bitmap) zugreifen. Die Zeichenfläche (Canvas) ist Image1.Picture.Bitmap.Canvas. Auf die Zeichenfläche mit dem sichtbaren Bereich eines TImage-Objekts kann man nur über Image1.Canvas zugreifen, während Image1.OnPaint aktiv ist.

Wichtig: Verwenden Sie nie das OnPaint-Event von Image1, um auf die Graphik, das Bild von TImage zu zeichnen. Die Graphik von TImage wird zwischengespeichert, so all you need to do is draw to it from anywhere and the change is there forever. However, if you are constantly redrawing, the image will flicker. In this case you can try the other options. Drawing to a TImage is considered slower then the other approaches.

Ändern der Grösse einer Bitmap in TImage

Anmerkung: Tun Sie das nicht während OnPaint.

 with Image1.Picture.Bitmap do begin
   Width:=100;
   Height:=120;
 end;

Zeichnen auf eine Bitmap in TImage

Anmerkung: Tun Sie das nicht während OnPaint.

 with Image1.Picture.Bitmap.Canvas do begin
   // fill the entire bitmap with red
   Brush.Color:=clRed;
   FillRect(0,0,Width,Height);
 end;

Anmerkung: Bei Image1.OnPaint zeigt Image1.Canvas auf den flüchtig sichtbaren Bereich. Außerhalb von Image1.OnPaint zeigt Image1.Canvas auf Image1.Picture.Bitmap.Canvas.

Ein anderes Beispiel:

procedure TForm1.BitBtn1Click(Sender: TObject);
var
  x, y: Integer;
begin
  // Zeichnet den Hintergrund
  MyImage.Canvas.Pen.Color := clWhite;
  MyImage.Canvas.Rectangle(0, 0, Image.Width, Image.Height);
  
  // Draws squares
  MyImage.Canvas.Pen.Color := clBlack;
  for x := 1 to 8 do
   for y := 1 to 8 do
    MyImage.Canvas.Rectangle(Round((x - 1) * Image.Width / 8), Round((y - 1) * Image.Height / 8),
       Round(x * Image.Width / 8), Round(y * Image.Height / 8));
end;

Im flüchtig sichtbaren Bereich einer TImage zeichnen

Sie können nur während des OnPaint-Ereignisses in diesen Bereich zeichnen. OnPaint wird eventuell automatisch von der LCL aufgerufen, wenn der Bereich invalidiert wurde. Sie können den Bereich mit Image1.Invalidate manuell invalidieren. Dies ruft OnPaint nicht unmittelbar auf und Sie können Invalidate so oft Sie wollen aufrufen.

 procedure TForm.Image1Paint(Sender: TObject);
 begin
   with Image1.Canvas do begin
     // paint a line
     Pen.Color:=clRed;
     Line(0,0,Width,Height);
   end;
 end;

Zeichnen im OnPaint-Ereignis des Formulars, der TPaintBox oder einem anderen Control

In diesem Fall muss alles Zeichnen im OnPaint-Ereignis des Formulars passieren. Die Elemente bleiben nicht im Buffer erhalten, wie bei TImage.

Ein CustomControl erzeugen, das sich selbst zeichnet

Die Erzeugung eines CustomControl hat den Vorteil der Strukturierung ihres Codes und sie können das Bedienelement wiederverwenden. Dieser Ansatz ist sehr schnell, aber er kann dennoch Flimmern erzeugen, wenn Sie nicht erst in ein TBitMap und dann in das Canvas zeichnen. In diesem Fall besteht keine Notwendigkeit das OnPaint Ereignis des Bedienelements zu verwenden.

Hier ist ein Beispiel CustomControl:

uses
  Classes, SysUtils, Controls, Graphics, LCLType;
 
type
  TMyDrawingControl = class(TCustomControl)
  public
    procedure Paint; override;
  end;

implementation

procedure TMyDrawingControl.Paint;
var
  x, y: Integer;
  Bitmap: TBitmap;
begin
  Bitmap := TBitmap.Create;
  try
    // Initialisiert die Bitmap Größe
    Bitmap.Height := Height;
    Bitmap.Width := Width;
 
    // Zeichnet den Hintergrund
    Bitmap.Canvas.Pen.Color := clWhite;
    Bitmap.Canvas.Rectangle(0, 0, Width, Height);

    // Zeichnet squares
    Bitmap.Canvas.Pen.Color := clBlack;
    for x := 1 to 8 do
     for y := 1 to 8 do
      Bitmap.Canvas.Rectangle(Round((x - 1) * Width / 8), Round((y - 1) * Height / 8),
       Round(x * Width / 8), Round(y * Height / 8));
      
    Canvas.Draw(0, 0, Bitmap);
  finally
    Bitmap.Free;
  end;

  inherited Paint;
end;

und wie wir es auf dem Formular erzeugen:

procedure TMyForm.FormCreate(Sender: TObject);
begin
  MyDrawingControl:= TMyDrawingControl.Create(Self);
  MyDrawingControl.Height := 400;
  MyDrawingControl.Width := 500;
  MyDrawingControl.Top := 0;
  MyDrawingControl.Left := 0;
  MyDrawingControl.Parent := Self;
  MyDrawingControl.DoubleBuffered := True;
end;

nur nicht vergessen es zu löschen:

procedure TMyForm.FormDestroy(Sender: TObject);
begin
  MyDrawingControl.Free;
end;

Das Setzen von Top und Left auf 0 ist nicht notwendig, da dies die Standardposition ist, aber es ist sinnvoll, um diese Position zu verdeutlichen.

"MyDrawingControl.Parent := Self;" ist sehr wichtig und sie werden ihr Bedienelement nicht sehen, wenn sie es nicht tun.

"MyDrawingControl.DoubleBuffered := True;" wird benötigt, um das Flimmern unter Windows zu vermeiden. Es hat keinen Effekt unter gtk.

A.J. Venter's Gamepack benutzen

Der Gamepack-Vorstoß bedeutet, alles in ein doppelt gebuffertes Canvas zu zeichnen, dessen sichtbarer Bereich erst dann aktualisiert wird, wenn Sie fertig sind. Dies benötigt etwas mehr Code, aber es schafft die Fähigkeit, große sich dynamisch ändernde Grafiken mit mehreren Elementen zu verarbeiten. Wenn Sie diese Technik verwenden möchten, sollten Sie sich das A.J. Venter's Gamepack ansehen, ein Set von Komponenten zur Entwicklung von Spielen mit Lazarus, das eine doppelt gebufferte Anzeigeflächen-Komponente sowie eine Sprite-Komponente bietet, designed um sich gegenseitig ideal zu intergrieren. Sie können Gamepack mittels subversion erhalten:
svn co svn://silentcoder.co.za/lazarus/gamepack