tutorials.de Buch-Aktion 05/2012
Like Tree3Danke
  • 1 Beitrag von CSANecromancer
  • 1 Beitrag von CSANecromancer
  • 1 Beitrag von CSANecromancer
ERLEDIGT
JA
ANTWORTEN
14
ZUGRIFFE
2040
EMPFEHLEN
  • An Twitter übertragen
  • An Facebook übertragen
AUF DIESES THEMA
ANTWORTEN
  1. #1
    HarryXVI HarryXVI ist offline Mitglied Gold
    Registriert seit
    Apr 2008
    Beiträge
    108
    Ich habe einen neuen Typen deklariert:
    Code :
    1
    2
    3
    4
    
    type TSpielfigur = class(TImage)
         private
         pos: array[1..819,1..396] of integer;
         end;

    Jetzt gibt es zwei Probleme:
    1. pos ist ein zweidimensionales Array, ich möchte einer Speicherposition zwei Werte gleichzeitig zuweisen (z.B. pos[5,8] := 32,36 o.ä.). Wie könnte man das machen?

    2.
    Code :
    1
    2
    3
    4
    5
    6
    
    Figur := TSpielfigur.Create(Spielfeld);
    Figur.Picture.Icon.LoadFromFile('C:\Delphi-Programme\Icons\Smiley2.ico');
    Figur.Picture.Icon.Height := 33;
    Figur.Picture.Icon.Width := 33;
    Figur.Left := 32; Figur.Top := 176;
    Figur.Visible := true;

    Ich erstelle eine Komponente vom Typ TSpielfigur und lade ein Bild vom Typ TIcon. Höhe, Breite und Position auf dem Formular werden festgelegt. Trotzdem wird das Icon auf dem Formular nicht sichtbar. Was ist da los und wie kann man es beheben?
     

  2. #2
    Registriert seit
    Mar 2004
    Beiträge
    441
    Zitat Zitat von HarryXVI Beitrag anzeigen
    Ich habe einen neuen Typen deklariert:
    1. pos ist ein zweidimensionales Array, ich möchte einer Speicherposition zwei Werte gleichzeitig zuweisen (z.B. pos[5,8] := 32,36 o.ä.). Wie könnte man das machen?
    Gar nicht. Denn dein Array ist ein Array (wenn auch zweidimensional) von Integern und ein Integer kann per definitionem nur einen (Ganzzahl-) Wert aufnehmen. Ich habe keine Ahnung, was du mit deinem Array bezweckst, aber eventuell kann dir TPoint bei dem helfen, was du vorhast.

    Zitat Zitat von HarryXVI Beitrag anzeigen
    Ich erstelle eine Komponente vom Typ TSpielfigur und lade ein Bild vom Typ TIcon. Höhe, Breite und Position auf dem Formular werden festgelegt. Trotzdem wird das Icon auf dem Formular nicht sichtbar. Was ist da los und wie kann man es beheben?
    Wow. Also mit TIcon innerhalb von TPictures (innerhalb von Timages) habe ich noch nicht gearbeitet, aber ich hatte schon ziemlich oft den Fall, daß das "Image" nicht angezeigt wird. Der Grund lag zu 99% darin, daß die TBitmap des TPicture des TImage entweder nil war oder Width, Height auf 0,0 standen.
    Von daher habe ich mir die direkte Arbeit mit TBitmaps angewöhnt und verwende TImages normalerweise nur noch als Viewports (insbesondere für schnelle Skalierungen). Seitdem hatte ich keinen Ärger mehr mit nicht angezeigten Bildern.

    Als schnelle Lösung kannst du mal folgendes probieren:
    Code :
    1
    2
    3
    
    Figur.Picture.Bitmap.Width := Figur.Picture.Icon.Width;
    Figur.Picture.Bitmap.Height := Figur.Picture.Icon.Height;
    Figur.Picture.Bitmap.Canvas.Draw(0, 0, Figur.Picture.Icon);
    Ist allerdings ungetestet. Bin nicht mehr am Arbeitsrechner.
     

  3. #3
    HarryXVI HarryXVI ist offline Mitglied Gold
    Registriert seit
    Apr 2008
    Beiträge
    108
    Also, ich habe jetzt auf Bitmap umgestellt (auch das Bildchen ist eine Bitmap).

    Code :
    1
    2
    3
    4
    5
    6
    
    Figur.Picture.Bitmap.LoadFromFile('C:\Delphi-Programme\Icons\Smiley2.bmp');
    Figur.Picture.Bitmap.Height := 33;
    Figur.Picture.Bitmap.Width := 33;
    if Figur.Picture.Bitmap.Empty = true 
       then ShowMessage('Bitmap leer') 
    else  Figur.Picture.Bitmap.Canvas.Draw(32, 176, Figur.Picture.Bitmap);

    Laut if-Abfrage ist die Bitmap nicht leer, aber es wird trotzdem nichts gezeichnet. Ich dachte erst, es könnte an der Zeichenfläche liegen, deshalb habe ich das Formular die Bitmap zeichnen lassen:

    Code :
    1
    
    Spielfeld.Canvas.Draw(32,176,Figur.Picture.Bitmap);
    Jetzt sagt der Compiler, das wäre eine Adressverletzung. Warum?
     

  4. #4
    Registriert seit
    Mar 2004
    Beiträge
    441
    Zitat Zitat von HarryXVI Beitrag anzeigen
    Jetzt sagt der Compiler, das wäre eine Adressverletzung. Warum?
    Keine Ahnung.
    Zeichnest du im OnCreate?
    Referenzierst du ein self im OnCreate?
    Ist Spielfeld nicht nur definiert sondern auch instantiiert?
    Ist Figur nicht nur definiert sondern auch instantiiert?
    Ist Figur.Picture nicht nur definiert sondern auch instantiiert?
    Ist Figur.Picture.Bitmap nicht nur definiert sondern auch instantiiert?

    All dies kann dir der Debugger beantworten.
     

  5. #5
    HarryXVI HarryXVI ist offline Mitglied Gold
    Registriert seit
    Apr 2008
    Beiträge
    108
    habe jetzt den Typ TSpielfigur von TBitmap abgeleitet
    Code :
    1
    2
    3
    4
    
     type TSpielfigur = class(TBitmap)
         private
          pos: TPoint;
         end;

    Dann habe ich eine Prozedur geschrieben, die das Bild erstellen soll (damit FormCreate nicht zu voll wird).
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    procedure TSpielfeld.bild_einrichtung;
    begin
    Figur := TSpielfigur.Create;
    Figur.pos.X := 32;
    Figur.pos.Y := 176;
    Figur.LoadFromFile('C:\Delphi-Programme\Icons\Smiley2.bmp');
    Figur.Height := 33;
    Figur.Width := 33;
    Figur.Canvas.Draw(32, 176, Figur);
    end;

    Sieht nach Augenwischerei aus, ist es vielleicht auch, aber selbst mit Spielfigur als direkte Bitmap funktioniert es nicht. CSANecromancer, ich weiß, du gibst ungern Sourcecodes, aber wie machst du es generell, wenn du ein Bild von dem Programm erstellen und anzeigen lassen willst?
     

  6. #6
    Registriert seit
    Mar 2004
    Beiträge
    441
    Zitat Zitat von HarryXVI Beitrag anzeigen
    ich weiß, du gibst ungern Sourcecodes
    Das liegt in 9 von 10 Fällen daran, daß derjenige, der nach dem Source fragt, mit an Sicherheit grenzender Wahrscheinlichkeit nichts damit anfangen kann, weil eine 1-Zeilen-Lösung für komplexe Probleme erwartet wird.

    Zitat Zitat von HarryXVI Beitrag anzeigen
    aber wie machst du es generell, wenn du ein Bild von dem Programm erstellen und anzeigen lassen willst?
    Ich denke, an der Stelle sollte ich mal ein paar Takte darüber ablassen, wie ich die graphischen Komponenten von Delphi betrachte und kennen gelernt habe.

    Der unterste Level ist der TCanvas. So ziemlich jede visuelle und/oder graphische Komponente hat einen TCanvas. Egal ob TImage, TPicture, TBitmap, TShape, TPaintBox, TForm, TButton etc.pp., überall gibt es einen TCanvas, mittels dem gezeichnet werden kann.
    Einige Leute zeichnen direkt auf den TCanvas des Hauptformulars, doch ich war noch nie ein Fan davon. Denn zwischen Zeichnen und Anzeigen liegt ein deutlicher Unterschied, wie du ja auch schon festgestellt hast.

    Ok, wozu sind dann die anderen graphischen Komponenten gut?

    TBitmap ermöglicht die einfachsten Lade- und Speicheroptionen für die einfachste Bildart überhaupt, eine unkomprimierte Bitmap. D.h. jeder Pixel der Bitmap wird im Idealfall (24 Bit Farbtiefe) durch 3 Byte repräsentiert: Rot, Grün, Blau. Klar gibt's da noch Feinheiten, aber um die nachzulesen gibt's ja die Onlinehilfe.
    TPicture kapselt die TBitmap und ermöglicht erweiterte Lade- und Speicheroptionen. Schau dir auch das mal in der Onlinehilfe an, da ist sehr schön beschrieben, welche Eigenschaften und Methoden TPicture selbst mitbringt und welche von TBitmap oder TCanvas stammen.
    TImage wiederum kapselt ein TPicture und bietet v.a. folgende Möglichkeiten: Bildproportionen verankern, Bild zentriert in einem Bereich anzeigen, Bild skalieren (und das sehr schnell). Den Rest von TImage habe ich noch nicht so intensiv verwendet.

    Am Rande noch: Mit TShape lassen sich einfachste geometrische Figuren darstellen und TPaintBox soll einfach nur dafür sorgen, daß nicht unmittelbar auf den Canvas der TForm gepinselt wird sondern auf einen festgelegten Bereich - nämlich die TPaintBox.

    Dann werfen wir mal einen genaueren Blick auf TImage. Timage beinhaltet TPicture - und einen TCanvas. Jup, das TImage hat einen eigenen TCanvas. Und auch das TPicture hat einen eigenen TCanvas. Und die TBitmap im TPicture im TImage hat auch einen eigenen TCanvas! Was soll denn der Blödsinn?

    TImage
    |
    +---> TCanvas
    |
    +--->TPicture
    |
    +---> TCanvas
    |
    +---> TBitmap
    |
    +---> TCanvas

    Welches ist jetzt der richtige?
    Du kannst dir das grob vereinfacht so vorstellen:
    Den TCanvas von TPicture kannst du vergessen. Der hat keinen echten Wert. Der TCanvas von TBitmap ist das, was an TImage zur Darstellung weitergereicht wird. Bevor TImage aber das Bild in TBitmap anzeigt, wird es noch umgewandelt (skaliert, zentriert, proportioniert usw., was TImage halt so gemäß seiner Einstellungen mit dem Bild macht). Wenn TImage dann endlich fertig ist mit dem Verwursten der Bilddaten, dann werden die an den TCanvas von TImage durchgereicht und auf den Bildschirm gezeichnet.

    Klar soweit? (im Ton von Cpt. Jack Sparrow)

    Nachdem ich mich mal durch diesen Wust durchgewühlt hatte, habe ich zwei Dinge beschlossen:
    1. Soweit und wann immer möglich, bearbeite ich Bilddaten als TBitmap.
    2. Ich zeichne niemals direkt auf einen TForm.Canvas, sondern verwende als Anzeigefläche immer ein TImage. Denn mit diesem TImage kann ich die Anzeige noch ein wenig steuern und sehr viel bequemer erweitern als wenn alles im TForm in einem Haufen vorliegt.

    Damit ist der allererste Teile deiner Frage beantwortet.

    Den Smily würde ich also (für's Erste) als Bitmap speichern.
    Auf das Formular würde ich ein TImage knallen. Dieses heisst bei mir normalerweise "Image". Sehr phantasielos, ich weiß. Aber da ich in der Regel nur ein einziges Image verwende, ist es dann doch eindeutig.

    Zum Laden und Anzeigen des Smilys würde ich dann so vorgehen:
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    
    prodecure ShowSmily;
    var
      bmSmily: TBitmap;
    begin
      bmSmily := TBitmap.Create;
      bmSmily.LoadFromFile('smily.bmp');
      // Nach dem Laden ist kein explizites Zuweisen von Width und Height erforderlich.
      // Diese werden implizit durch das Laden des bmp-Files gesetzt
     
      // Ich sitze jetzt gerade nicht am Compiler, deswegen kann ich nicht
      // ausprobieren, ob die TBitmap unten in TImage defaultmässig schon
      // existiert. Daher diese "Nummer Sicher"
      if Image.Picture = nil then
        Image.Picture := TPicture.Create;
      if Image.Picture.Bitmap := nil then
        Image.Picture.Bitmap := TBitmap.Create;
     
      // Ok, furzegal, was ist, ich habe jetzt mal meine Bitmap mit dem Smily
      // und es sind alle Ebenen von TImage eingerichtet. Auch wenn die Bitmap
      // von TImage nichts anzeigt, weil bislang weder eine Bitmap geladen noch
      // die Dimensionen der Bitmap eingerichtet worden sind.
     
      Image.Picture.Bitmap.Assign(bmSmily);
      // Tadaaa! Jetzt wäre schon mal der Smily in der Bitmap des Image.
      // Ich habe aber schlechte Erfahrungen mit Assign gemacht, vor allem, 
      // wenn das Ursprungsobjekt, wie in diesem Falle die bmSmily am
      // Prozedurende wieder aufgeräumt wird. 
     
      // Aus diesem Grund bevorzuge ich das explizite Kopieren der Bilddaten
      // und deren explizite Zuweisung.
      Image.Picture.Bitmap.Width := bmSmily.Width;
      Image.Picture.Bitmap.Height := bmSmily.Height;
      Image.Picture.Bitmap.Canvas.CopyRect(Rect(0, 0, bmSmily.Width - 1, bmSmily.Height - 1), bmSmily, Rect(0, 0, bmSmily.Width - 1, bmSmily.Height - 1));
      
      // Da jetzt die Bilddaten von bmSmily ganz ausdrücklich kopiert und damit 
      // vervielfältigt wurden, sind die Ursprungsdaten nicht mehr notwendig.
      FreeAndNil(bmSmily);
     
      // Kann aber immer noch sein, daß der Smily nicht korrekt angezeigt wird.
      // Das ist u.a. davon abhängig, was alles im Hintergrund auf dem Rechner
      // läuft, welche Prozeßpriorität dieses Programm hier hat usw.
      // Da mir das aber alles zu blöd ist, sage ich dem Programm mit Brachialgewalt
      // "Hallo, da wurde ein neues Bild geladen, zeige das gefälligst an!":
      Image.Invalidate;
     
      // Oder alternativ:
      Image.Refresh;
    end;
    Mit dem Source kannst du jetzt eine beliebige Bitmap laden und anzeigen. Bewegen ist aber wieder eine andere Baustelle.

    Wenn's um Animation geht, kommen mir sehr viele Leute immer gleich mit OpenGL, DirectX und wasweissichnichtalles an. Und erklären mich dann für irre, wenn ich behaupte, daß sich am Prinzip der Animation seit 1906 nichts Grundlegendes geändert hat.
    Das Prinzip ist bis heute das gleich:
    - Hintergrund zeichnen
    - Smily auf den Hintergrund zeichnen
    - Hintergrund neu zeichnen
    - Smily versetzt auf den Hintergrund zeichnen
    - Hintergrund neu zeichnen
    - Smily noch etwas weiter versetzt auf den Hintergrund zeichnen
    usw.usf.
    Und das Ganze richtig schnell. Je schneller es geht, desto flüssiger erscheint die Animation (genau das drückt der Begriff "frames per second" aus, der aber wiederum so ziemlich jedem Gamer bekannt ist...)

    Mist, daß der Smily im Codestück weiter oben direkt in den Hintergrund (nämlich die TBitmap des TPicture des TImage) gezeichnet wurde.
    Aus diesem Grunde arbeite ich normal mit mehreren Bitmaps: Eine Bitmap für den Hintergrund, eine Bitmap für den Smily, eine Bitmap zum Zusammenführen des Ganzen. Und dann wird das Zusammengeführte in die Bitmap des TImage geleitet und fertig ist der Käse.

    Hier ein einfacher, unkommentierter Source, der dieses Geschehen veranschaulichen soll:
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    
    procedure Demo;
    var
      bmBackground: TBitmap;
      bmSmily: TBitmap;
      bmBlitter: TBitmap;
      i: Integer;
    begin
      if Image.Picture = nil then
        Image.Picture := TPicture.Create;
      if Image.Picture.Bitmap = nil then
        Image.Picture.Bitmap := TBitmap.Create;
      Image.Picture.Bitmap.Width := 800;
      Image.Picture.Bitmap.Height := 600;
      Image.Width := 800;
      Image.Height := 800;
     
      bmBackground := TBitmap.Create;
      bmBackground.LoadFromFile('background.bmp');
     
      bmSmily := TBitmap.Create;
      bmSmily.LoadFromFile('smily.bmp');
     
      bmBlitter := TBitmap.Create;
      bmBlitter.Width := Image.Picture.Bitmap.Width;
      bmBlitter.Height := Image.Picture.Bitmap.Height;
     
      for i := 0 to 700 do
      begin
        bmBlitter.Canvas.CopyRect(Rect(0, 0, bmBackground.Width - 1, bmBackground.Height - 1), bmBackground, Rect(0, 0, bmBackground.Width - 1, bmBackground.Height - 1);
        bmBlitter.Canvas.CopyRect(Rect(i, 50, i + bmSmily.Width, 50 + bmSmily.Height), bmSmily, Rect(0, 0, bmSmily.Width - 1, bmSmily.Height - 1));
        Image.Picture.Bitmap.Canvas.CopyRect(Rect(0, 0, bmBlitter.Width - 1, bmBlitter.Height - 1), bmBlitter, Rect(0, 0, bmBlitter.Width - 1, bmBlitter.Height - 1));
        Image.Refresh;
      end;
     
      FreeAndNil(bmBackground);
      FreeAndNil(bmSmily);
      FreeAndNil(bmBlitter);
    end;

    Wie im Sourcekommentar weiter oben erwähnt, habe ich gerade keinen Compiler zur Hand zum Austesten, aber ich bin mit ziemlich sicher, daß die Sources funktionieren oder wenn dann nur geringe Fehler drin sind (z.B. bin ich mir mit den -1 bei den Dimensionierungen der CopyRects gerade nicht 100% sicher).

    Ich hoffe, das hilft jetzt etwas weiter.
    HarryXVI bedankt sich. 

  7. #7
    HarryXVI HarryXVI ist offline Mitglied Gold
    Registriert seit
    Apr 2008
    Beiträge
    108
    Zitat Zitat von CSANecromancer
    bmBlitter.Canvas.CopyRect(Rect(0, 0, bmBackground.Width - 1, bmBackground.Height - 1), bmBackground, Rect(0, 0, bmBackground.Width - 1, bmBackground.Height - 1);
    da kannst du als zweiten Parameter, nicht die Bitmap nehmen, da CopyRect hier einen Canvas verlangt. Aber mit Assign klappts bei mir, deshalb ist das jetzt nicht das Problem.

    Dein Prinzip mit der Bilderstellung zur Laufzeit habe ich verstanden, kann es auch gut anwenden. Aber ich verstehe nicht, wie das mit der Animation klappen soll. Könntest du deinen Sourcecode da vielleicht ein wenig kommentieren? Dann wäre ich einen Schritt weiter und könnte es selbstständig anwenden.
     

  8. #8
    Registriert seit
    Mar 2004
    Beiträge
    441
    Zitat Zitat von HarryXVI Beitrag anzeigen
    da kannst du als zweiten Parameter, nicht die Bitmap nehmen, da CopyRect hier einen Canvas verlangt.
    Ist ja kein Problem, dann gibst du halt statt bmBackground bmBackground.Canvas an.

    Zitat Zitat von HarryXVI Beitrag anzeigen
    Aber ich verstehe nicht, wie das mit der Animation klappen soll. Könntest du deinen Sourcecode da vielleicht ein wenig kommentieren?
    Ausnahmsweise, weil ich mir vorstellen kann, daß das alles etwas schnell war.

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    
    procedure Demo;
    var
      bmBackground: TBitmap;
      bmSmily: TBitmap;
      bmBlitter: TBitmap;
      i: Integer;
    begin
      // Zu Beginn des ganzen Gekrempels gehe ich mal davon aus, daß Image
      // noch überhaupt nicht richtig eingerichtet ist. Daher hier wieder die Instantierung
      // aller Ebenen von Image.
      if Image.Picture = nil then
        Image.Picture := TPicture.Create;
      if Image.Picture.Bitmap = nil then
        Image.Picture.Bitmap := TBitmap.Create;
      Image.Picture.Bitmap.Width := 800;
      Image.Picture.Bitmap.Height := 600;
     
      // Bloß weil die im Hintergrund liegende Bitmap von Image mit der Größe
      // 800x600 eingerichtet worden ist, heißt das noch lange nicht, daß die sichtbare
      // Fläche von Image auch schon ein bestimmtes Ausmaß hat.
      // Ich will aber nicht nur eine 800x600 Bitmap anzeigen, ich will sie auch im
      // Originalformat 800x600 anzeigen, weswegen das Image eine entsprechende
      // Größe braucht.
      Image.Width := 800;
      Image.Height := 800;
     
      // Jetzt lade ich mir ein x-beliebiges Hintergrundbild...
      bmBackground := TBitmap.Create;
      bmBackground.LoadFromFile('background.bmp');
     
      // ...und natürlich auch den Smily
      bmSmily := TBitmap.Create;
      bmSmily.LoadFromFile('smily.bmp');
     
      // Der Blitter ist das Bild (genauer: Die Bitmap), wo ich Hintergrund
      // und Smily miteinander verschmelze, um dann das Ergebnis von Image
      // anzeigen zu lassen. Logisch, daß der Blitter damit die gleiche Größe
      // braucht wie die Bitmap des Image.
      bmBlitter := TBitmap.Create;
      bmBlitter.Width := Image.Picture.Bitmap.Width;
      bmBlitter.Height := Image.Picture.Bitmap.Height;
     
      // Es sollen 700 "Animations"-Schritte durchlaufen werden, genauer formuliert
      // soll der Smily von links nach rechts 700 Pixel weit verschoben werden.
      for i := 0 to 700 do
      begin
        // Als allererstes muß ein sauberer Hintergrund aufgebaut werden.
        // Nochmal: Im Blitter wird alles zusammen gebaut. Deswegen wird hier
        // der Hintergrund auf die Bitmap des Blitters kopiert.
        bmBlitter.Canvas.CopyRect(Rect(0, 0, bmBackground.Width - 1, bmBackground.Height - 1), bmBackground.Canvas, Rect(0, 0, bmBackground.Width - 1, bmBackground.Height - 1);
     
         // Nur ein leerer Hintergrund ist zu langweilig, deswegen wird hier noch der
         // Smily auf den Blitter kopiert. Wenn die komischen Koordinaten und das i
        // völlig unbekannt und nicht nachvollziehbar erscheinen:
        // Onlinehilfe, Suchbegriff CopyRect
        bmBlitter.Canvas.CopyRect(Rect(i, 50, i + bmSmily.Width, 50 + bmSmily.Height), bmSmily.Canvas, Rect(0, 0, bmSmily.Width - 1, bmSmily.Height - 1));
     
        // Der Hintergrund ist im Blitter gelandet, der Smily ist im Blitter gelandet,
        // das Bild ist aufgebaut und kann angezeigt werden. Dazu wird einfach der 
        // Blitter in die Bitmap des Image kopiert.
        Image.Picture.Bitmap.Canvas.CopyRect(Rect(0, 0, bmBlitter.Width - 1, bmBlitter.Height - 1), bmBlitter.Canvas, Rect(0, 0, bmBlitter.Width - 1, bmBlitter.Height - 1));
     
        // Abschließend muß dem Programm noch mitgeteilt werden, daß sich das
        // Image geändert hat.
        Image.Refresh;
      end;
     
      // Aufräumen der Resourcen nach Gebrauch nicht vergessen
      FreeAndNil(bmBackground);
      FreeAndNil(bmSmily);
      FreeAndNil(bmBlitter);
    end;
    HarryXVI bedankt sich. 

  9. #9
    Registriert seit
    Mar 2004
    Beiträge
    441
    Zitat Zitat von HarryXVI Beitrag anzeigen
    aber wie machst du es generell, wenn du ein Bild von dem Programm erstellen und anzeigen lassen willst?
    Wie ich mit Bildern generell umgehe, habe ich dir ja bereits geschrieben. Aber ich fand das, was du da machen willst, ganz witzig und habe mir deswegen jetzt mal was gebastelt (was es sicher schon zigtausendfach und viel performanter und eleganter als fertige Komponenten gibt): Eine eigene Sprite-Klasse.

    Und da es auch um Sourcecodes geht, hier einfach mal die Sources sowohl des Demo-Programms als auch des Sprites.

    Demoprogramm, Hauptformular:
    Name: Main
    KeyPreview: true

    Darauf gehört ein TImage mit folgenden Eigenschaften platziert:
    Name: Main
    Align: alClient
    Picture: (irgendein Bild laden. Ich habe ein Wallpaper geladen).

    Ebenfalls auf das Formular gehört noch ein TButton mit folgenden Eigenschaften:
    Name: btDemo
    Caption: Demo starten

    Wenn du es dir noch etwas einfacher machen willst, dann richtest du schon mal folgende Ereignismethoden ein:
    Main.OnCreate
    Main.OnClose
    Main.OnKeyDown
    Main.Demo.OnClick (die Buttonmethode)

    Hier der Source der Main:
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    
    unit Dialogs.Main;
     
    interface uses
      Classes,
      Controls,
      Dialogs,
      ExtCtrls,
      Forms,
      Graphics,
      Jpeg,
      Messages,
      StdCtrls,
      SysUtils,
      Variants,
      Windows,
     
      Data.Sprite;
     
     
    type
      TMain = class(TForm)
        btDemo: TButton;
        Image: TImage;
        procedure btDemoClick(Sender: TObject);
        procedure FormCreate(Sender: TObject);
        procedure FormClose(Sender: TObject; var Action: TCloseAction);
        procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
     
      private
        Sprite: TSprite;
     
      end;
     
    var
      Main: TMain;
     
    implementation
     
    {$R *.dfm}
     
    procedure TMain.FormCreate(Sender: TObject);
    begin
      // Damit die Animation etwas flackerfreier läuft
      self.DoubleBuffered := true;
     
      Sprite := TSprite.Create;
    end;
     
     
    procedure TMain.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
      FreeAndNil(Sprite);
    end;
     
     
    procedure TMain.btDemoClick(Sender: TObject);
    begin
      Sprite.Load('sprite.bmp');
      Sprite.Width := 32;
      Sprite.Height := 32;
      Sprite.Position.X := Round(ClientWidth / 2);
      Sprite.Position.Y := Round(ClientHeight / 2);
     
      // Das Sprite wird direkt auf dem Canvas der Form angezeigt
      Sprite.Canvas := self.Canvas;
      Sprite.SetSpeed(100);
     
      // Die einzelnen Frames des Sprites festlegen
      Sprite.SetFrame(0, 0, 0);
      Sprite.SetFrame(1, 32, 0);
      Sprite.SetFrame(2, 64, 0);
      Sprite.SetFrame(3, 96, 0);
     
      // Transparenz ist Magenta (so definiert durch 0/0 der Spritebitmap)
      Sprite.SetTransparency(Point(0, 0));
     
      Sprite.Show;
    end;
     
     
    procedure TMain.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    begin
      // Q
      if Key =  81 then
      begin
        Sprite.Left(3);
        Key := 0;
      end;
     
      // W
      if Key =  87 then
      begin
        Sprite.Right(3);
        Key := 0;
      end;
     
      // A
      if Key =  65 then
      begin
        Sprite.Up(3);
        Key := 0;
      end;
     
      // Y
      if Key =  89 then
      begin
        Sprite.Down(3);
        Key := 0;
      end;
     
      // Space blendet das Sprite ein und aus.
      if Key =  32 then
      begin
        Key := 0;
     
        if Sprite.Visible = true then
          Sprite.Hide
        else
          Sprite.Show;
      end;
    end;
     
     
    end.

    Und hier der Source der Spriteklasse ("Data.Sprite.pas"):
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    457
    458
    459
    460
    461
    462
    463
    
    {*-----------------------------------------------------------------------------
      Klasse zur Darstellung von Sprites
    -----------------------------------------------------------------------------*}
    unit Data.Sprite;
     
    interface uses
     
      Controls,
      ExtCtrls,
      Graphics,
      SysUtils,
      Types,
      Windows;
     
     
    type
    {*-----------------------------------------------------------------------------
      Klassendefinition eines Sprites
    -----------------------------------------------------------------------------*}
      TSprite = class(TObject)
     
        private
          m_Bitmap: Graphics.TBitmap;                         /// Bitmap mit allen Frames des Sprites
          m_Background: Graphics.TBitmap;                     /// Buffer für den Hintergrund des Sprites
          m_Mask: Graphics.TBitmap;                           /// Bildmaske für alle Frames zur transparenten Anzeige
          m_Blitter: Graphics.TBitmap;                        /// Buffer zum Zusammenbauen des Sprites
          m_Transparency: TColor;                             /// Transparenzfarbe des Sprites
     
          m_FramePos: array[0..15] of TPoint;                 /// Positionen der einzelnen Frames in der Spritebitmap
          m_FrameIndex: Byte;                                 /// Index des aktuell angezeigten Frames
          m_FrameMax: Byte;                                   /// Index des maximalen Animationsframes
     
          m_Timer: TTimer;                                    /// Animationstimer
          m_Ascending: boolean;                               /// Animationsrichtungsflag (aufsteigend, absteigend)
     
          m_Visible: boolean;                                 /// Sichtbarkeitsflag des Sprites
     
          m_Width: Byte;                                      /// Breite des Sprites in Pixeln
          m_Height: Byte;                                     /// Höhe des Sprites in Pixeln
     
          procedure ShowFrame;                                /// Anzeige eines einzelnen Frames
          procedure SpriteTimer(Sender: TObject);             /// Ereignismethode für den Animationstimer
          procedure MoveBy(p_nX: Integer; p_nY: Integer);     /// Bewegen des Sprites
     
          procedure SetWidth(p_nValue: Byte);                 /// Festlegen der Spritebreite
          procedure SetHeight(p_nValue: Byte);                /// Festlegen der Spritehöhe
     
        public
          Position: TPoint;                                   /// Position des Sprites auf dem Darstellungs-Canvas
          Canvas: TCanvas;                                    /// Handle auf den Canvas, auf dem das Sprite dargestellt werden soll
     
          constructor Create;
          destructor Free;
     
          procedure Load(const p_strFileName: String);
          procedure SetFrame(const p_nIndex: Integer; const p_nX: Integer; const p_nY: Integer);
          procedure SetSpeed(const p_nSpeed: Integer);
          procedure SetTransparency(const p_Point: TPoint);
          procedure Show;
          procedure Hide;
          procedure Left(p_nValue: Integer);
          procedure Right(p_nValue: Integer);
          procedure Up(p_nValue: Integer);
          procedure Down(p_nValue: Integer);
     
          property Visible: boolean read m_Visible;           /// Lesezugriff auf das Visibility-Flag
          property Width: Byte read m_Width write SetWidth;   /// Angepasster Schreibzugriff auf die Breite
          property Height: Byte read m_Height write SetHeight;/// Angepasster Schreibzugriff auf die Höhe
      end;
     
     
    implementation
     
     
    {*-----------------------------------------------------------------------------
      Konstruktor
    -----------------------------------------------------------------------------*}
    constructor TSprite.Create;
    var
      i: Integer;
    begin
      // Erstellen des Timers für eine evtl. Spriteanimation
      m_Timer := TTimer.Create(nil);
      m_Timer.Enabled := false;
      m_Timer.OnTimer := self.SpriteTimer;
     
      // Zyklusreihenfolge für eine Animation
      m_Ascending := true;
     
      // Startindex des Frames für die Animation
      m_FrameIndex := 0;
     
      // Anzahl der Spriteanimationsschritte
      m_FrameMax := 0;
     
      // Erstellen der Spritebitmap
      m_Bitmap := Graphics.TBitmap.Create;
      m_Bitmap.Width := 0;
      m_Bitmap.Height := 0;
     
      // Erstellen der Maskenbitmap
      m_Mask := Graphics.TBitmap.Create;
      m_Mask.Width := 0;
      m_Mask.Height := 0;
     
      // Speicher für den Hintergrund, vor dem das Sprite dargestellt wird
      m_BackGround := Graphics.TBitmap.Create;
      m_BackGround.Width := 0;
      m_BackGround.Height := 0;
     
      // Speicher für den Aufbau des Sprites (v.a. für Transparaenz)
      m_Blitter := Graphics.TBitmap.Create;
      m_Blitter.Width := 0;
      m_Blitter.Height := 0;
     
      // Startposition des Sprites
      Position := Point(0, 0);
     
      // Extractionkoordinaten für die einzelnen Frames
      for i := 0 to 15 do
        m_FramePos[i] := Point(-1, -1);
     
      // Standardmässig ist das Sprite nicht sichtbar
      m_Visible := false;
    end;
     
     
    {*-----------------------------------------------------------------------------
      Destruktor
     
      Auflösen verwendeter Resourcen
    -----------------------------------------------------------------------------*}
    destructor TSprite.Free;
    begin
      // Deaktivieren und Löschen des Timers
      m_Timer.Enabled := false;
      FreeAndNil(m_Timer);
     
      // Löschen aller Bitmaps
      FreeAndNil(m_Bitmap);
      FreeAndNil(m_Mask);
      FreeAndNil(m_Background);
      FreeAndNil(m_Blitter);
    end;
     
     
    {*-----------------------------------------------------------------------------
      Laden des Sprites
    -----------------------------------------------------------------------------*}
    procedure TSprite.Load(const p_strFileName: String);
    begin
        if FileExists(p_strFileName) then
          m_Bitmap.LoadFromFile(p_strFileName);
    end;
     
     
    {*-----------------------------------------------------------------------------
      Wenn die Spritebreite festgelegt wird (Property), dann wird auch die
      Blitterbreite entsprechend angepasst.
    -----------------------------------------------------------------------------*}
    procedure TSprite.SetWidth(p_nValue: Byte);
    begin
      if (p_nValue > 0) then
      begin
        m_Width := p_nValue;
        m_Blitter.Width := p_nValue;
      end;
    end;
     
     
    {*-----------------------------------------------------------------------------
      Wenn die Spritehöhe festgelegt wird (Property), dann wird auch die
      Blitterhöhe entsprechend angepasst.
    -----------------------------------------------------------------------------*}
    procedure TSprite.SetHeight(p_nValue: Byte);
    begin
      if (p_nValue > 0) then
      begin
        m_Height := p_nValue;
        m_Blitter.Height := p_nValue;
      end;
    end;
     
     
    {*-----------------------------------------------------------------------------
      Festlegen der Framepositionen in der Spritebitmap
    -----------------------------------------------------------------------------*}
    procedure TSprite.SetFrame(const p_nIndex: Integer; const p_nX: Integer; const p_nY: Integer);
    var
      i: Integer;
    begin
      if (p_nIndex >= 0) or (p_nIndex <= 15) then
        // Die Frameposition wird festgelegt
        m_FramePos[p_nIndex] := Point(p_nX, p_nY);
     
      // Automatische Berechnung des Maximalframes
      m_FrameMax := 0;
      for i := 0 to 15 do
        if m_FramePos[i].X = -1 then
          break;
      m_FrameMax := i - 1;
    end;
     
     
    {*-----------------------------------------------------------------------------
      Animationsgeschiwndigkeit ändern
    -----------------------------------------------------------------------------*}
    procedure TSprite.SetSpeed(const p_nSpeed: Integer);
    begin
      m_Timer.Enabled := false;
      m_Timer.Interval := p_nSpeed;
      if m_Timer.Interval > 0 then
        m_Timer.Enabled := true;
    end;
     
     
    {*-----------------------------------------------------------------------------
      Transparenz einstellen
    -----------------------------------------------------------------------------*}
    procedure TSprite.SetTransparency(const p_Point: TPoint);
    var
      x, y: Integer;
    begin
      // Die Transparenzfarbe ist diejenige in der Spritebitmap, auf die mit der
      // Methode gezeigt wird. Alle entsprechend gefärbten Pixel der Spritebitmap
      // gelten daraufhin als transparent.
      m_Transparency := m_Bitmap.Canvas.Pixels[p_Point.X, p_Point.Y];
      m_Mask.Width := m_Bitmap.Width;
      m_Mask.Height := m_Bitmap.Height;
     
      // Jedes reine Schwarz (RGB 0/0/0) wird durch ein "Fast-Schwarz" (RGB 0, 0, 1)
      // ersetzt und jedes Transparenzpixel durch ein reines Schwarz
      for y := 0 to m_Bitmap.Height do
      begin
        for x := 0 to m_Bitmap.Width do
        begin
          if m_Bitmap.Canvas.Pixels[x, y] = clBlack then
            m_Bitmap.Canvas.Pixels[x, y] := RGB(0, 0, 1);
     
          if m_Bitmap.Canvas.Pixels[x, y] = m_Transparency then
            m_Bitmap.Canvas.Pixels[x, y] := clBlack;
        end;
      end;
     
      // Jetzt wird die Maske aufgebaut: Jedes sichtbare Pixel wird schwarz,
      // jedes transparente Pixel wird Weiß.
      for y := 0 to m_Bitmap.Height do
      begin
        for x := 0 to m_Bitmap.Width do
        begin
          if m_Bitmap.Canvas.Pixels[x, y] <> clBlack then
            m_Mask.Canvas.Pixels[x, y] := clBlack
          else
            m_Mask.Canvas.Pixels[x, y] := clWhite;
        end;
      end;
    end;
     
     
    {*-----------------------------------------------------------------------------
      Spriteanimation über den Timer
    -----------------------------------------------------------------------------*}
    procedure TSprite.SpriteTimer(Sender: TObject);
    begin
      if m_FrameMax > 0 then
      begin
        // Aufsteigende Animationsfolge
        if m_Ascending then
        begin
          if m_FrameIndex < m_FrameMax then
            Inc(m_FrameIndex)
          else
            m_Ascending := false;
        end
        // Abteigende Animationsfolge
        else
        begin
          if m_FrameIndex > 0 then
            Dec(m_FrameIndex)
          else
            m_Ascending := true;
        end;
      end;
      
      ShowFrame;
    end;
     
     
    {*-----------------------------------------------------------------------------
      Anzeige eines einzelnen Spriteframes
    -----------------------------------------------------------------------------*}
    procedure TSprite.ShowFrame;
    var
      rtScreen: TRect;
      rtSprite: TRect;
      rtFrame: TRect;
    begin
      // Die Anzeige erfolgt nur, wenn ein Zielcanvas vorgegeben wurde
      if Canvas <> nil then
      begin
        // Rectangle für Position auf dem Zielcanvas
        rtScreen := Rect(Position.X, Position.Y, (Position.X + m_Width), (Position.Y + m_Height));
     
        // Rectangle für einfache Spriteposition
        rtSprite := Rect(0, 0, Width, Height);
     
        // Rectangle für Frame innerhalb der Spriebitmap
        rtFrame := Rect(m_FramePos[m_FrameIndex].X , m_FramePos[m_FrameIndex].Y, m_FramePos[m_FrameIndex].X + m_Width, m_FramePos[m_FrameIndex].Y + m_Height);
     
        // Falls bis jetzt noch kein Hintergrund angelegt wurde, so ist jetzt der
        // letztmögliche Zeitpunkt dafür. Dies kann z.B. beim Bewegen des Sprites
        // geschehen, wenn es verschoben wird.
        if (m_Background.Width = 0) then
        begin
          m_Background.Width := m_Width;
          m_Background.Height := m_Height;
          m_Background.Canvas.CopyMode := cmSrcCopy;
          m_Background.Canvas.CopyRect(rtSprite, Canvas, rtScreen);
        end;
     
        // Das Sprite wird gelöscht, indem der Hintergrund wieder an die Position
        // eingeblendet wird, wo sich das Sprite befand.
        m_Blitter.Canvas.CopyMode := cmSrcCopy;
        m_Blitter.Canvas.CopyRect(rtSprite, m_Background.Canvas, rtSprite);
     
        // Wenn eine Maske existiert, dann soll ein transparentes Sprite angezeigt
        // werden. Dies geschieht durch eine Maske:
        // Das Sprite selbst ist entsprechend in seiner Bitmap bearbeitet worden.
        // Alle auszublendenden Pixel sind Schwarz gefärbt worden und die Maske
        // beinhaltet für alle nicht darzustellenden Pixel die Farbe Weiß.
        // Durch entsprechende booelsche Zeichenoperation (AND-Verknüpfung mit der
        // Maske) werden nur die nicht ausgeblendeten Pixel in den Blitter übertragen.
        if m_Mask.Width > 0 then
        begin
          m_Blitter.Canvas.CopyMode := cmSrcAnd;
          m_Blitter.Canvas.CopyRect(rtSprite, m_Mask.Canvas, rtFrame);
          m_Blitter.Canvas.CopyMode := cmSrcPaint;
        end
        else
          m_Blitter.Canvas.CopyMode := cmSrcCopy;
     
        // Die Zeichenoperationen (Transparenz oder nicht Transparanz, Maske oder nicht Maske)
        // sind bereits eingestellt, es muß nur noch der richtige Frame in den Blitter kopiert werden.
        m_Blitter.Canvas.CopyRect(rtSprite, m_Bitmap.Canvas, rtFrame);
     
        // Der Blitter enthält jetzt das Hintergrundbild und den richtigen Spriteframe, ggf. mit
        // entsprechender Transparenz. Also ab damit auf den Anzeige-Canvas.
        Canvas.CopyRect(rtScreen, m_Blitter.Canvas, rtSprite);
      end;
    end;
     
     
    {*-----------------------------------------------------------------------------
      Generelle Anzeige des Sprites
    -----------------------------------------------------------------------------*}
    procedure TSprite.Show;
    begin
     
      // Wie gehabt: Anzeige nur, wenn auch ein Anzeige-Canvas zugewiesen wurde
      if (Canvas <> nil) then
      begin
        // Falls der Hintergrund noch nicht gespeichert wurde (z.B. bei Erstanzeige des
        // Sprites), dann wird er gespeichert.
        if m_Background.Width = 0 then
        begin
          m_Background.Width := Width;
          m_Background.Height := Height;
          Canvas.CopyMode := cmSrcCopy;
          m_Background.Canvas.CopyRect(Rect(0, 0, Width, Height), Canvas, Rect(Position.X, Position.Y, (Position.X + Width), (Position.Y + Height)));
        end;
     
        // Anzeige des Sprites und aktivieren einer evtl. vorhandenen Animation
        ShowFrame;
        m_Visible := true;
        m_Timer.Enabled := true;
      end;
    end;
     
     
    {*-----------------------------------------------------------------------------
      Sprite verstecken
    -----------------------------------------------------------------------------*}
    procedure TSprite.Hide;
    begin
      // Das Verstecken klappt nur, wenn der Hintergrund gespeichert wurde
      if (m_Background.Width <> 0) and
         (Canvas <> nil) then
      begin
        // Zum Verstecken wird der Hintergrund wieder eingeblendet (ohne Sprite)
        // und die weitere Spriteanzeige unterdrückt.
        Canvas.CopyMode := cmSrcCopy;
        Canvas.CopyRect(Rect(Position.X, Position.Y, (Position.X + Width), (Position.Y + Height)), m_Background.Canvas, Rect(0, 0, Width, Height));
        m_Background.Width := 0;
     
        // Unterdrücken der weiteren Spriteanzeige
        m_Timer.Enabled := false;
        m_Visible := false;
      end;
    end;
     
     
    {*-----------------------------------------------------------------------------
      Spritebewegung
    -----------------------------------------------------------------------------*}
    procedure TSprite.MoveBy(p_nX: Integer; p_nY: Integer);
    var
      ScreenPos: TRect;
    begin
      // Derzeitige Position auf dem Anzeige-Canvas. An dieser Position muß das Sprite
      // gelöscht (also der Hintergrund wieder eingeblendet) werden,
      ScreenPos := Rect(Position.X, Position.Y, (Position.X + Width), (Position.Y + Height));
     
      if (m_Background.Width <> 0) then
      begin
        Canvas.CopyMode := cmSrcCopy;
        Canvas.CopyRect(ScreenPos, m_Background.Canvas, Rect(0, 0, Width, Height));
        m_Background.Width := 0;
      end;
     
      // Danach kann das Sprite passend verschoben und neu angezeigt werden
      Position.X := Position.X + p_nX;
      Position.Y := Position.Y + p_nY;
      ShowFrame;
    end;
     
     
    {*-----------------------------------------------------------------------------
      Sprite nach links bewegen
    -----------------------------------------------------------------------------*}
    procedure TSprite.Left(p_nValue: Integer);
    begin
      MoveBy(-p_nValue, 0);
    end;
     
     
    {*-----------------------------------------------------------------------------
      Sprite nach rechts bewegen
    -----------------------------------------------------------------------------*}
    procedure TSprite.Right(p_nValue: Integer);
    begin
      MoveBy(p_nValue, 0);
    end;
     
     
    {*-----------------------------------------------------------------------------
      Sprite nach oben bewegen
    -----------------------------------------------------------------------------*}
    procedure TSprite.Up(p_nValue: Integer);
    begin
      MoveBy(0, -p_nValue);
    end;
     
     
    {*-----------------------------------------------------------------------------
      Sprite nach unten bewegen
    -----------------------------------------------------------------------------*}
    procedure TSprite.Down(p_nValue: Integer);
    begin
      MoveBy(0, p_nValue);
    end;
     
     
    end.

    Im Anhang findest du noch die von mir verwendete sprite.bmp.

    Viel Spaß beim Basteln und Ausprobieren.
    Miniaturansicht angehängter Grafiken Miniaturansicht angehängter Grafiken neuer Image-Typ-sprite.bmp  
    HarryXVI bedankt sich. 

  10. #10
    HarryXVI HarryXVI ist offline Mitglied Gold
    Registriert seit
    Apr 2008
    Beiträge
    108
    irgendwie wird die Bitmap-Datei, die ich in das Sprite lade, nicht angezeigt. Stattdessen erscheint auf dem Formular der Abschnitt aus dem Fenster, was dahinter liegt (Buchstaben aus dem Quellcode-Fenster). Wie kann das sein?
     

  11. #11
    Registriert seit
    Mar 2004
    Beiträge
    441
    Starte das Ganze mal außerhalb der IDE, ohne break points. Das von dir beschriebene Verhalten hatte ich teilweise auch, wenn ich zwischen IDE und Programm hin- und hergeschaltet habe. Liegt daran, daß die Formulardarstellung dann teilweise durch die IDE unterbrochen wird.
     

  12. #12
    HarryXVI HarryXVI ist offline Mitglied Gold
    Registriert seit
    Apr 2008
    Beiträge
    108
    also SetFrame legt die einzelnen Bilder fest, die hintereinander angezeigt werden...ok.
    Aber wofür sind die Prozeduren "MoveBy", "Left", "Right", "Up", "Down"? Es bewegt sich doch auch, wenn man Frames + Speed festlegt und dann Show aufruft.
     

  13. #13
    Registriert seit
    Mar 2004
    Beiträge
    441
    Mit Speed legst du die Animationsgeschwindigkeit fest, also die Geschwindigkeit, mit der die einzelnen Frames des Sprites angezeigt werden.
    MoveBy ist eine Prozedur in der ich sowohl horizontale als auch vertikale Bewegung zusammengefasst habe. Allerdings ist MoveBy von außen nicht sichtbar.
    Das sind dann Left, Right, Up und Down. Und mit den Parametern gibst du an, wieviele Pixel das Sprite in die jeweilige Richtung bewegt werden soll.

    In diesem Falle: Bewegung != Animation.

    Falls du dir den Source wirklich angeschaut und versucht hast, ihn nachzuvollziehen, dann wird dir nicht entgangen sein, daß du das Sprite in der Demo mit den Tasten Q, W, A und Y steuern und mit Space an- und ausschalten kannst...
     

  14. #14
    HarryXVI HarryXVI ist offline Mitglied Gold
    Registriert seit
    Apr 2008
    Beiträge
    108
    habe mich nun nochmal mit dem programm beschäftigt...ich habe den Smiley nun so als Bitmap eingebunden, wie wir dies am Anfang besprochen haben...Jetzt ist die Hintergrundfarbe des Rechtecks schwarz. Kann man die irgendwie ändern?
     

  15. #15
    HarryXVI HarryXVI ist offline Mitglied Gold
    Registriert seit
    Apr 2008
    Beiträge
    108
    Mir ist da noch was aufgefallen. Ich erstelle also 3 Objekte vom Typ TSprite auf dem Canvas einer Image-Komponente. Die Positionen wähle ich zufällig aus, das führt jedoch dazu, dass sich die Sprites oft überlappen. Wie kann ich überprüfen, ob sich auf einem Pixel schon ein Sprite befindet?
     

Ähnliche Themen

  1. Antworten: 5
    Letzter Beitrag: 30.12.10, 14:06
  2. Antworten: 2
    Letzter Beitrag: 06.07.08, 01:12
  3. image fade und image als link verwenden
    Von phamez im Forum Javascript & Ajax
    Antworten: 5
    Letzter Beitrag: 08.04.07, 12:34
  4. image/jpeg gegen image/pjpeg
    Von achimj im Forum PHP
    Antworten: 2
    Letzter Beitrag: 04.01.05, 20:34
  5. Antworten: 1
    Letzter Beitrag: 02.05.04, 11:59