DelphiX einfache Bewegung einer Figur + PixelKollision
So Leute, das ist mein 2. Tutorial, welches sich wiedermal um DelphiX dreht.
Jemand hat sich dieses Tutorial gewünscht und soll es auch bekommen 
 
Fangen wir dann mal an.
(1). Komponenten platzieren und einstellen
- Platziert ein 
DXDraw Objekt auf eurem Formular.
- Stellt dort 
Align auf 
alClient.
- Jetzt noch eine 
DXImageList.
- Dort muss noch per doppelklick das 
DXDraw ausgewählt werden (Bilder fügen wir später hinzu).
- Jetzt noch eine 
DXSpriteEngine, dort das gleiche mit dem 
DXDraw.
- Einen 
DXTimer, mit 
interval 0 (man kann auch andere Werte nehmen, um die FPS einzudämmen, aber so kommt man eben auf die höchste Framezahl und das ist für Kollisionen ganz nützlich).
- Als letztes noch ein 
DXImput
(2). Die richtigen Animationen
- Für dieses Tutorial solltet ihr die beiligenden (Anhang) Animationen verwenden.
- Doppelklick auf das 
DXImageList Objekt und wählt die Bilder aus dem anhang aus.
- Ordnet die Bilder in dieser Reihenfolge:
-das 2. Bild der Animation ist das Bild indem keine Bewegung stattfindet, also die Figur steht, von dem Bild gehen dann alle Bewegungen aus.
- 
TransparentColor der Bilder muss auf 
clFuchsia und 
Transparent auf 
true stehen
- 
Patternwidthund 
Patternheight stellen wir für unser Beispiel auf 
19, das sind Breite un Höhe der einzelnen Bilder.
(2). Die Animation
- So, zu allererst eine neue Klasse:
		                     
             Delphi-Quelltext
                        Delphi-Quelltext                    
           	 										| 1:2:
 3:
 4:
 5:
 6:
 
 | typeTPlayer = class(TImageSprite)
 public
 procedure DoMove(MoveCount: Integer); override;
 procedure DoCollision(Sprite: TSprite; var Done: Boolean); override;
 end;
 | 
		
	  
- 
DoMove wird unsere Bewegung.
- 
DoCollision ist später für die Kollision wichtig.
- Nun zur eigentlichen Bewegung (sieht wilder aus, als es ist):
												| 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 TPlayer.DoMove(MoveCount: Integer);begin
 inherited DoMove(MoveCount);
 AnimStart := 1;
 AnimCount := 0;
 If (isup in GameForm.DXInput1.States) and not (isdown in GameForm.DXInput1.States) and not (isleft in GameForm.DXInput1.States) and not (isright in GameForm.DXInput1.States) then
 with Player1 do
 begin
 image := GameForm.DXImageList1.Items[0];
 AnimStart := 0;
 AnimCount := image.patterncount;
 y := y - 1;
 end;
 If (isdown in GameForm.DXInput1.States) and not (isup in GameForm.DXInput1.States) and not (isleft in GameForm.DXInput1.States) and not (isright in GameForm.DXInput1.States) then
 with Player1 do
 begin
 image := GameForm.DXImageList1.Items[1];
 AnimStart := 0;
 AnimCount := image.patterncount;
 y := y + 1;
 end;
 If (isleft in GameForm.DXInput1.States) and not (isright in GameForm.DXInput1.States) and not (isup in GameForm.DXInput1.States) and not (isdown in GameForm.DXInput1.States) then
 with Player1 do
 begin
 image := GameForm.DXImageList1.Items[2];
 AnimStart := 0;
 AnimCount := image.patterncount;
 x := x - 1;
 end;
 If (isright in GameForm.DXInput1.States) and not (isleft in GameForm.DXInput1.States) and not (isup in GameForm.DXInput1.States) and not (isdown in GameForm.DXInput1.States)  then
 with Player1 do
 begin
 image := GameForm.DXImageList1.Items[3];
 AnimStart := 0;
 AnimCount := image.patterncount;
 x := x + 1;
 end;
 end;
 | 
		
	  
- Also nehmen wir das gewurschtel mal auseindander:
		                     
             Delphi-Quelltext
                        Delphi-Quelltext                    
           	 										| 1:2:
 3:
 
 |   inherited DoMove(MoveCount);    AnimStart := 1;    AnimCount := 0;  					 | 
		
	  
- dann taucht 4 mal sowas hier auf,
		                     
             Delphi-Quelltext
                        Delphi-Quelltext                    
           	 										| 1:2:
 3:
 4:
 5:
 6:
 7:
 8:
 
 |   If (isup in GameForm.DXInput1.States) and not (isdown in GameForm.DXInput1.States) and not (isleft in GameForm.DXInput1.States) and not (isright in GameForm.DXInput1.States) thenwith Player1 do
 begin
 image := GameForm.DXImageList1.Items[0];
 AnimStart := 0;
 AnimCount := image.patterncount;
 y := y - 1;
 end;
 | 
		
	  
- erstmal wird abgefragt, ob nicht schon eine andere Richtungstaste gedrückt wurde, weil dann soll garnischt passieren, es soll nur eine gedrückt sein.
- Die Animation für die Bewegung nach Norden wird geladen (Bild nr 0).
- Dann wird das erste bild der aninmation auf 0 gesetzt.
- und die Animation auf ihre Maximale Länge.
- und das bild wird um die y achse verschoben (es bewegt sich nach oben).
- Aber wir haben noch etwas vergessen ! ja richtig, das Objekt zu erstellen.
- Wir brauchen also eine Globale Variable mit dem Namen 
Player1, das Erstellen ist nicht so wild:
		                     
             Delphi-Quelltext
                        Delphi-Quelltext                    
           	 										| 1:2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
 10:
 11:
 12:
 13:
 14:
 15:
 16:
 17:
 
 | procedure TGameForm.FormCreate(Sender: TObject);begin
 Player1 := TPlayer.Create(DXSpriteEngine1.Engine);    with Player1 do
 begin
 image := dximagelist1.items[1];        AnimStart := 1;
 AnimCount := 0;
 AnimLooped := true;        AnimSpeed := 1/150;        width := image.width;        height := image.height;        x := GameForm.ClientWidth div 2 - width div 2;        y := GameForm.ClientHeight div 2 - width div 2;        z := 1;
 end;
 end;
 | 
		
	  
- Aber was hat das Z zu bedeuten, wir arbeiten doch nicht in 3d ?
- Nein, das Z zeigt an, in welcher reihenfolge die Bilder gezeichnet werden.
- Das mit dem kleinsten Z als erstes und das mit dem größten als letztes (befindet sich also oben).
- jetzt kommt unser Timer dran:
		                     
             Delphi-Quelltext
                        Delphi-Quelltext                    
           	 										| 1:2:
 3:
 4:
 5:
 6:
 7:
 8:
 
 | procedure TGameForm.DXTimer1Timer(Sender: TObject; LagCount: Integer);begin
 DXInput1.Update;    DXDraw1.Surface.Fill(clBlack);    DXSpriteEngine1.Draw;    DXSpriteEngine1.Move(20);    DXDraw1.Flip;  end;
 | 
		
	  
- Jetzt können wir unsere Figur schon wunderbar bewegen  
 
 
(wenn man DoCollision auskommentiert oder die Prozedur schon hinzufügt)
(3). Kollisionsabfrage
- Jetzt kommt das schwerste von allem die KOLLISIONSABFRAGE
- Keine Angst, es ist einfacher als es klingt, denn es ist schon fast mit nur einem Befehl getan:
		                     
             Delphi-Quelltext
                        Delphi-Quelltext                    
           	 	 
- Diese kommt ans Ende unserer 
DoMove Procedure.
- Warum so wenig Code ?
- Weil DelphiX die Pixelkollision für uns erledigt.
- Nur Brauchen wir erstmal etwas zum Kollidieren:
		                     
             Delphi-Quelltext
                        Delphi-Quelltext                    
           	 										| 1:2:
 3:
 4:
 5:
 
 | typeTBall = class(TImageSprite)
 public
 procedure Contact;
 end;
 | 
		
	  
- Es reicht uns, wenn der Ball statisch ist, glaubt mir einfach, dass es auch funktioniert, wenn sich der Ball bewegt 
 
- Als Bild könnt ihr euch schnell einen Ball malen, mit der hintergrundfarbe clfuchsia (R: 255, G: 0, B: 255);
- Der kommt dann in die ImageList an letzter Stelle, wird als Globale Variable Ball deklariert und wir erweitern unser 
Form.Create:
		                     
             Delphi-Quelltext
                        Delphi-Quelltext                    
           	 										| 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:
 
 | procedure TGameForm.FormCreate(Sender: TObject);begin
 Player1 := TPlayer.Create(DXSpriteEngine1.Engine);
 with Player1 do
 begin
 image := dximagelist1.items[1];
 AnimStart := 1;
 AnimCount := 0;
 AnimLooped := true;
 AnimSpeed := 1/150;
 width := image.width;
 height := image.height;
 x := GameForm.ClientWidth div 2 - width div 2;
 y := GameForm.ClientHeight div 2 - width div 2;
 z := 1;
 end;
 Ball := TBall.Create(DXSpriteEngine1.Engine);
 with Ball do
 begin
 image := dximagelist1.items[4];
 x := 50;
 y := 50;
 width := image.width;
 height := image.height;
 end;
 end;
 | 
		
	  
- und nun zur Kollision:
		                     
             Delphi-Quelltext
                        Delphi-Quelltext                    
           	 										| 1:2:
 3:
 4:
 5:
 
 | procedure TPlayer.DoCollision(Sprite: TSprite; var Done: Boolean);begin
 if Sprite is TBall then
 TBall(Sprite).Contact;
 end;
 | 
		
	  
- Das wars schon, es wird geprüft, ob das objekt ein Ball ist und dann die Kollision auf Seiten des Balls aufgerufen und zwar hier:
		                     
             Delphi-Quelltext
                        Delphi-Quelltext                    
           	 										| 1:2:
 3:
 4:
 
 | procedure TBall.Contact;begin
 beep;
 end;
 | 
		
	  
- Das 
beep ist die Reaktion des Balls auf die Kollision.
- Natürlich können da jetzt alle möglichen sachen rein, zB der Ball stirbt, bzw er verschwindet, das sähe so aus:
		                     
             Delphi-Quelltext
                        Delphi-Quelltext                    
           	 										| 1:2:
 3:
 4:
 5:
 
 | procedure TBall.Contact;begin
 beep;
 dead;
 end;
 | 
		
	  
- dazu müssen wir unseren Timer aber etwas erweitern:
		                     
             Delphi-Quelltext
                        Delphi-Quelltext                    
           	 										| 1:2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
 
 | procedure TGameForm.DXTimer1Timer(Sender: TObject; LagCount: Integer);begin
 DXInput1.Update;
 DXDraw1.Surface.Fill(clBlack);
 DXSpriteEngine1.Dead;
 DXSpriteEngine1.Draw;
 DXSpriteEngine1.Move(20);
 DXDraw1.Flip;
 end;
 | 
		
	  
- Dead übernimmt das freigeben der gestorbenen Sprites
- so jetzt sind wir schon am ende angelangt, ich hoffe, es hat bei euch allen funktioniert, freue mich auf feedback, auch wenn manches etwas durcheinander geraten sein mag 
