Entwickler-Ecke

Delphi Tutorials - DelphiX - Snake Tutor


mimi - Do 17.04.03 23:04
Titel: DelphiX - Snake Tutor
Hallo,

hier mein Snake Tutor.

Bevor du das Tutorial list, musst du unbedingt folgendes Tutorial [http://www.delphi-treff.de/content/tutorials/delphixkurs/index.php4?kat=1] lesen. Hier kann man die Grundlagen von DelphiX kennen lernen

Also fangen wir an:

Als erstes startest du Delphi und machst ein Neues Projekt auf.

Dann gehst du zur DelphiX-Seite bei den Komponenten und nimmst: TDXdraw, TDXImageListe, DXTimer.

So jetzt bereiten wir die DXImageList vor: du klickst auf Items und fügst 4 Items hinzu, 1 = Body, 2 = Head, 3 = Wand und 4 = Futter und lädst die einzelnen Bilder rein. Nun legen wir eine Struktur (oder wie die Dinger heißen) an:

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:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
// Karten Infos (a)
const
  MapX   = 39;
  MapY   = 23;
// Karte (b)
  None   = -1;
  Wand   = 3;

// Richtungen (c)
  links  = 0;
  rechts = 1;
  oben   = 2;
  unten  = 3;

type
// 1
  MSnkae = record
    X,Y,richtung,tick:Integer;
    E:array of TPoint;
    KeyDown:Bool
  end;

// 2
  SFutter = record
    x,y,punkte,tex:Integer;
  end;

// 3
  MGkarte = record
    Typ,Tex:Integer;
    Visible:Bool;
  end;

// 4
  MGame = record
    karte: array[0..MapX,0..MapY] of MGkarte;
    Snake:MSnkae;
    futter:array of SFutter;
    FutterIndex:Integer;
  end;

Ich habe die Struktur in einer extra unit gespeichert (wegen des Level Editors, den ich gerade schreibe).

a:
MapX und MapY sind die Kartengrößen. Sie geben an: wie groß die einzelnen Felder sind; wir verwenden hier ein Raster. Jeder Kasten ist 16x16 Pixel groß. Wir haben in diesem Fall: Breite 640 und Höhe 480. Jetzt müssen wir einfach 640 durch die Breite der Kästchen teilen also z.b. so:
640 / 16 = 40 -1 da wir von 0 ausgehen und nicht von 1 muss das -1 genommen werden.

Bei der Höhe ist das das Gleiche. 480 / 16 = 30 - 1 Aber hier ist etwas anders. Im Quellcode steht 23 und nicht 30 drin. Das ist aber schnell erklärt: da wir nicht alles für das Spielfeld haben wollen, sondern noch ein Display einblenden wollen, müssen wir 112 von den 480 abziehen; und so kommen wir auf 23 in Y-Richtung.

b:
None sind leere Felder. Wand ist der Index in der DXImageList. Also hier 3.

c:
Sind die Richtungsangaben.

1:
Für die Schlange: x und y die Position, tick ist das Zeitinterval, in der DXTimer* die Funktion MoveSnake(die wir noch schreiben werden) aufrufen soll. Wenn wir das nicht machen, ist die Schlange in 1 Sekunde in der Wand. e ist der "body array", also die Elemente der Schlange. Kurz: der Schwanz. KeyDown wird in Move_Snake genommen(darauf gehe ich später noch ein)

2:
x und y die Futter-Position, Punkte ist klar, tex ist der pattern Index.

3:
Die Karte: in Typ wird der Feld-Typ gespeichert, also ob es nun eine Wand ist. Visible gibt an, ob der Typ angezeigt werden soll.

4:
Der Hauptrecord: in Karte werden die Objekte drinnen gespeichert (wirst du später noch sehen) Snake enthält alle variablen, die für die Schlange gebraucht werden. Futter für das Futter ;) In FutterIndex wird das aktuelle Futter gespeichert, also die Position, welches Futter er von dem FutterIndex anzeigen soll.

Das sind die Vorbereitungen. Sobald du damit fertig bist, kannst du weiterlesen:

So als erstes schreiben wir die Procedure, die die Schlange zum Bewegen bringt

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:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
procedure SnakeMove;
var
  i:integer;
  check_c:Bool;
begin
  check_c:=False;
// Hier wird geschaut ob die Karten Grenzen erreicht wurden, also ob x = 0, y = 0, x = MapX, y = MapY
  with Game.Snake do begin
    if (X-1 < 0and (game.Snake.richtung = Links) then  check_c:=True;
    if (Y-1 < 0and (game.Snake.richtung = Unten) then  check_c:=True;
    if (X+1 > MapX) and (game.Snake.richtung = rechts) then  check_c:=True;
    if (Y+1 > MapY) and (game.Snake.richtung = Oben) then  check_c:=True;
  end;

// Hier wird geschaut, ob die Schlange mit einem Stein zusammen stoßen könnte,   wenn ja wird check_c auf True gesetzt
  if (Game.karte[Game.Snake.X+1,Game.Snake.y].typ <> None) and (game.Snake.richtung = rechts) then check_c:=True;
  if (Game.karte[Game.Snake.X-1,Game.Snake.y].typ <> None) and (game.Snake.richtung = Links) then check_c:=True;

  if (Game.karte[Game.Snake.X,Game.Snake.y+1].typ <> None) and (game.Snake.richtung = Oben)then check_c:=True;
  if (Game.karte[Game.Snake.X,Game.Snake.y-1].typ <> None) and (game.Snake.richtung = Unten) then check_c:=True;
  
// Wenn Snake Kartengrenzen nicht erreicht hat, und auch nicht gegen eine Wand gestoßen ist: position ändern
  if Check_c = False then begin    
  // Futter wird eingesammelt
    if (Game.futter[Game.FutterIndex].x = Game.Snake.x) and (Game.futter[Game.FutterIndex].y = Game.Snake.y) then begin
      inc(Game.FutterIndex);
      SetLength(Game.Snake.e,high(Game.Snake.e)+2);
      Game.Snake.e[high(Game.Snake.e)]:=Game.Snake.e[high(Game.Snake.e)-1];
    end;
   // die Schlange wird bewegt: 
    case Game.Snake.richtung of
      Rechts: inc(Game.Snake.X);
      Links: dec(Game.Snake.X);
      Oben: inc(Game.Snake.Y);
      Unten: dec(Game.Snake.Y);
    end;
  
    // Neue Position, vom Schwanz erstellen
    for i:=high(Game.Snake.e) downto 1 do
      Game.Snake.E[i]:=Game.Snake.E[i-1];

    // den Snake-Kopf auf die neue Position setzen
    Game.Snake.E[0].x:=Game.Snake.X; Game.Snake.E[0].y:=Game.Snake.Y;
  end;  
end;

Ich denke, die procedure sollte klar sein, oder ?

Weiter geht es: das Wichtigste überhaupt, das Anzeigen der Bilder auf der DXDraw-Komponente:

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:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
procedure TForm1.DXTimer1Timer(Sender: TObject; LagCount: Integer);
var
  i,m,px,py:Integer;
begin
// Bildschrim wird schwarz eingefärbt:
  DXDraw1.Surface.Fill(0);

// Wände werden gezeichnet
  for px:=0 to MapX do begin
    for py:=0 to MapY do begin
      // Wenn Typ = none, wenn tex = none und wenn Visible = true sind, dann wird gezeichnet
      if (Game.karte[px,py].typ <> None) and (Game.karte[px,py].tex <> None) and  (Game.karte[px,py].Visible = True) then 
        DXImageList1.Items[Game.karte[px,py].typ].Draw(DXDraw1.surface,px*16,py*16,Game.karte[px,py].tex);
    end;
  end;

// Timer für die Bewegung der Schlange wird raufgezählt:
  inc(Game.Snake.tick);
  // Wenn eine Taste gedrückt wird, bewegt sich die Schlange schneller also:
  if Game.Snake.KeyDown = True then
    m:=4
  else // wenn keine Taste gedrückt wurde, auf normale Geschwindigkeit schalten:
    m:=10;
    
  // Wenn die Zeit erreicht wurde, bewegt sich die Schlange:
  if Game.Snake.tick >= m then begin
    Game.Snake.tick:=0;
    SnakeMove;
  end;

// Anzeigen vom Snake-Body:
  for i:=1 to HIGH(Game.Snake.e) do
    DXImageList1.Items[1].Draw(DXDraw1.surface,Game.Snake.e[i].x*16,Game.Snake.e[i].y*16,0);

// Anzeigen vom Snake-Head
  DXImageList1.Items[0].Draw(DXDraw1.surface,Game.Snake.x*16,Game.Snake.y*16,0);

// Wenn Futterindex = -1 ist dann wird es übersprungen:
  if Game.FutterIndex <> -1 then begin
    // wenn Futterindex nicht auf -1 ist, wird das Futter angezeigt 
    with Game.futter[Game.FutterIndex] do begin
      if Tex <> -1 then
        DXImageList1.Items[2].Draw(DXDraw1.surface,x*16,y*16,tex);
    end;
  end;
  
// Hiermit werden die Sachen sichtbar gemacht  
  DXDraw1.Flip;
end;

Noch Fragen zum Zeichnen ? Nein? Gut;)

Weiter: jetzt wird alles initialisiert.

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:
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:
procedure TForm1.FormCreate(Sender: TObject);
var
  i,px,py:Integer;
begin
  // Dynamische Arrays werden mit einer Länge initialisiert.
  SetLength(Game.futter,5);
  SetLength(Game.snake.e,5);

// Zum Anfang wird die gesammte Karte auf 0 gesezt, also "nil*"
  for px:=0 to MapX do begin
    for py:=0 to MapY do begin
      Game.karte[px,py].typ:=None;
      Game.karte[px,py].Tex:=None;
      Game.karte[px,py].Visible:=False;      
    end;
  end;
  
// Zum Start wird hier, wie bei der Karte, alles auf "nil*" gesetzt
  for i:=0 to 4 do begin
    with Game.Futter[i] do begin
      x:=-1; y:=-1; punkte:=-1; tex:=-1;
    end;
  end;
  
// Der Snake-Body wird gesetzt:
  Game.Snake.X:=10; Game.Snake.y:=10;
  Game.Snake.e[0].x:=Game.Snake.X; Game.Snake.e[0].y:=Game.Snake.y;
  Game.Snake.e[1].x:=11; Game.Snake.e[1].y:=10;
  Game.Snake.e[2].x:=12; Game.Snake.e[2].y:=10;
  Game.Snake.e[3].x:=13; Game.Snake.e[3].y:=10;
  Game.Snake.e[4].x:=14; Game.Snake.e[4].y:=10;
// die Wiederholungsschleife für SnakeMove im DXTimer wird auf 0 gesezt
  Game.Snake.tick:=0;
// zum Anfang hat man noch keine Taste gedrückt, also wird KeyDown auch auf False gesetzt
  Game.Snake.KeyDown:=False;

// Snake-Futter, wird erstellt: 
  Randomize;
  for i:=0 to 4 do begin
    with Game.Futter[i] do begin
      x:=random(MapX);
      y:=random(MapY);
      tex:=random(2);
    end;
  end;
  game.FutterIndex:=0;

// Wände werden initialisiert
  // Wand oben
  for px:=0 to MapX do begin
    Game.karte[px,0].typ:=Wand;    
    Game.karte[px,0].Tex:=0;
    Game.karte[px,0].Visible:=True;
  end;

  // Wand Unten
  for px:=0 to MapX do begin
    Game.karte[px,MapY].typ:=Wand;    
    Game.karte[px,MapY].Tex:=2;
    Game.karte[px,MapY].Visible:=True;
  end;

  // Wand Links
  for py:=0 to MapY do begin
    Game.karte[0,py].typ:=Wand;
    Game.karte[0,py].Tex:=0;
    Game.karte[0,py].Visible:=True;
  end;

  // Wand Rechts
  for py:=0 to MapY do begin
    Game.karte[MapX,py].typ:=Wand;
    Game.karte[MapX,py].Tex:=2;
    Game.karte[MapX,py].Visible:=True;
  end;

end;

* Nil kann man hier nicht sagen, sondern hier wird alles auf -1 gesetzt, aber zum klaren Verständnis verwende ich nil. Ich hoffe, die "lange" procedure ist dir auch klar.....

Die Schlange bewegt sich schneller wenn eine Taste gedrückt wurde. Nun kommen wir zu der Steuerung der Schlange:

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 TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  // Wenn die Pfeiltaste: Links gedrückt wurde:
  if key = VK_LEFT then begin
    Game.Snake.KeyDown:=True;
    Game.Snake.richtung:=Links;
  end;

  // Wenn die Pfeiltaste: Rechts gedrückt wurde:
  if key = VK_RIGHT then begin
    Game.Snake.KeyDown:=True;
    Game.Snake.richtung:=Rechts;
  end;

  // Wenn die Pfeiltaste: Oben gedrückt wurde:
  if key = VK_DOWN then begin
    Game.Snake.KeyDown:=True;
    Game.Snake.richtung:=Oben;
  end;

  // Wenn die Pfeiltaste: Unten gedrückt wurde:
  if key = VK_UP then begin
    Game.Snake.KeyDown:=True;
    Game.Snake.richtung:=Unten;
  end
end;

Wenn die Taste losgelassen wurde, Schlange auf normale Geschwindigkeit einstellen.

Delphi-Quelltext
1:
2:
3:
4:
5:
procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  Game.Snake.KeyDown:=False;
end;

So. Das wäre es gewesen. Ich hoffe, ich konnte euch helfen ;)

Moderiert von user profile iconKlabautermann: Code durch Delphi-Tags ersetzt.


Lhid - Sa 13.12.03 21:26

Meinung und mich grundlegend geändert-> alte beiträge gelöscht


mimi - Sa 13.12.03 23:27

was für fehler ???


CABALxx - Sa 07.02.04 00:24
Titel: Re: DelphiX - Snake Tutor
cooles tut =) :lol:


mimi - Sa 07.02.04 22:06

danke :)
ich werde evtl, noch eins machen aber mit GLXTreem *G*


Johannes Maier - Mi 14.04.04 13:37

edit: hat sich erledigt!


F34r0fTh3D4rk - So 24.10.04 14:22

bei mir sind da auch so um die 10 - 15 fehler :?


F34r0fTh3D4rk - So 24.10.04 14:25

bitte den ganzen SC, plz 8)


mimi - So 24.10.04 15:32

> bitte den ganzen SC, plz
was meinst du damit ???


F34r0fTh3D4rk - So 24.10.04 17:31

SourceCode

Ich denke, dass viele die gleichen Probleme haben .... :?


mimi - So 24.10.04 19:02

den habe ich leider nicht mehr bzw. ich müsste erst auf meine sicherungen schauen. aber was für ein problem habt ihr???
evtl. schreibe ich ein neues(hätte nicht gedacht das delphiX so viel genutzt wird)

ich möchte ja immer noch(mal sehen wann ich dazu komme)
so eine art delphiX Lexikon schreiben da sollen Tutor rein, tipps erfahrungen und sowas
z.b. auch geschiechte und sowas halt, alles was mit DelphiX zu tuen hat


F34r0fTh3D4rk - Mo 25.10.04 15:14

die solln mal den delphix sourcecode rausgeben, damit schlaue leute
den verbessern könn, dieses generve von wegen delphix ist *mist*e geht mir
verdammt auf den sack :evil:

ich finde delphix rockt ! :wink:


mimi - Sa 30.10.04 10:58

delphIX ist openSource und jede kann die Qullcode verändern.
was gefält dir dann an delphiX nicht ?
ich nutze es bestimmt schon seit 2 Jahren wenn nicht mehr *G*


F34r0fTh3D4rk - Sa 30.10.04 12:06

im forum nerven mich alle, dass delphiX fürn *popo* ist,
weil es nicht open source ist und ruckelt wie sau ...

Dabei weiß ich auch das delphi open source ist aber :?: :!:
Sowas macht einen bekloppt im kopf :autsch:


mimi - Sa 30.10.04 12:52

also ich finde delphiX auch supper gerade für 2D spiele.
ich habe mir eine kleine klasse geschrieben die den zugrief auf delphiX vereinfacht.
naja wie dem auch sei *G*


F34r0fTh3D4rk - Sa 30.10.04 20:35

ich habe auch nichts gegen delphiX, nur wenn man hier im Forum jemadem eine
Frage stellt, dann fragt der benutzt du DelphiX. Antwort: ja !
Dann kommt gleich: Kannste vergessen, mach es lieber ohne DelphiX,
DelphiX ist unzuverlässig, langsam....

Aber ich komm mit Snake auch net weiter, wie gesagt, ich habe um die 10-15 Fehler :nixweiss:


mimi - Sa 30.10.04 22:43

was für fehler ?
im grunde ist Snake mit DelphiX sehr einfach, ich überleg mir gerade ob ich nicht ein neues Snake erstellen soll problem ist nur: ich habe leide kein WebSpace mehr und könnte es dann nicht hochladen. ich müste es also bei delphipraxis hochladen.

du musst bei snake im grunde nur folgendes machen(das ist der wichtiges teiel)
du hast ein raster jedes feld hat die gleiche größe(16X16)(die schlange auch) es gibst 2 array ein für die map(map:array[0..40,0..39] of TMap). jetzt kannst du ihn per zufall füllen lassen und bei der schlange gehst jetzt weiter:
Snake:array of TPoint;

jetzt erhöst du immer wenn du zusammen gestoßen bis:

if map[Snake[0].x,Snake[0].y].type = Freesen then
.....
und jetzt musst du einfach denn array um eins erhöhen.

das problem ist nur bei der bewegung du muss alle elemente vom array um einen bestimmten wert veränden z.b. so:



Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
const
lings = -1
rechts = +1
oben = -1;
unten = +1

richtung:=Lings;

procedure move;
var
  i:Integer;
begin
  for i:=0 to high(Snake) do begin
    if (richtung = lings) or (richtung = rechts) then
      Snake[i].x:=Snake[i].x+richtung;

    if (richtung = oben) or (richtung = unten) then
      Snake[i].y:=Snake[i}.y+richtung
  end;
end;


das müsste normaler weise gehen(ich habst nicht getestet) wenn es nicht geht werde ich morgen ein kleiens Snake schreiben

ich hoffe du kannst damit was anfangen *G*


F34r0fTh3D4rk - Mo 01.11.04 18:17

danke, und wenn du es geschrieben hast, kannst du ja einen kleinen sourcecode
hier reinschreiben : :eyecrazy:


mimi - Mo 01.11.04 18:48

ich weiß aber noch nicht genau wann ich damit anfangen.
ich wollte ersteinmal ein kleines snake Game schreiben. und daraus dann ein tutor entwickeln, dann kann sich aber hinziehen


F34r0fTh3D4rk - Mo 01.11.04 19:24

ich hab zeit :)


mimi - Mo 08.11.04 17:57

ich habe mich jetzt für ein Sokubahn tutor entschieden vom primzip das gleiche nur das bei Snake eine Schlange da ist und bei Sokubahn nur ein einfacher spiel stein *G*
wenn du glück hast und ich zeit finde könntes es in ca 2 wochen fertig sein(habe aber noch nicht angefangen)

ich wollte nämlich zuers denn qullcode schreiben und den dann im tutor vorstellen und nicht umekehrt *G* (so habe ich es beim Snake Tutor gemacht *G*)


F34r0fTh3D4rk - Mo 08.11.04 21:45

bei manchen snake varianten kommt man ja auch links ins spiel rein, wenn man rechts
rausgeht.


thepaul - Sa 04.12.04 20:43

wo ist denn das tutorial von delphi-treff? kann er irgendwie nich finden! Hoffentlich heben sie das nich bei der zusammenlegung versehentlich gelöscht!


mimi - So 13.02.05 12:25

habe gestern angefangen ein DelphiX tutor projekt zu schreiben.
Evtl. werde ich es gleich noch weiter schreiben, ber hier mal mein inhaltzverzeichnis

Zitat:

Inhaltverzeichnis
- Einführung
Was muss/sollte ich wissen bevor ich DelphiX downloade ?
Wo gibt es DelphiX zum Downloaden ?
Wie installiere ich es, richtig ?

- Erstes DelphiX Projekt
DXDraw
DXImageList
DXTimer

- Erstes Beispiel Sokubahn(Zusammenfassung)
Speichern und verwalten von Objekten ?
Verschieben und Drehen von Objekten
löschen von Objekten
der PatternIndex

- Verschiende Techniken
Scrollen
Minikarte
Levelformat


leider habe ich keinen WebSever wo ich die Beispiel hochladen kann, deshalb müsst ihr(wenn es dann da ist, und ihr das auch wollt*G*) die beispiel einfach selbst schreiben....

Wenn ihr noch vorschläge habt..... Nehme ich sie gerne mit auf


mimi - So 13.02.05 15:17

Da DelphiX eine sehr bekannte und bliebte Komponenten samlung
für 2D Spiele geworden ist, hier mal mein "Tutorial-Projekt".

Es gibt verschiende Thmen jedes Thema ist in unter thmen unterteilet.

Inhaltverzeichnis
- Einführung
Was muss/sollte ich wissen bevor ich DelphiX downloade ?
Wo gibt es DelphiX zum Downloaden ?
Wie installiere ich es, richtig ?

- Erstes DelphiX Projekt
DXDraw
DXImageList
DXTimer

- Erstes Beispiel Sokubahn(Zusammenfassung)
Speichern und verwalten von Objekten ?
Verschieben von Objekten
der PatternIndex

- Verschiende Techniken
Scrollen
Minikarte
Levelformat
Drehen von Objekten


Einführung
Es wird kein DelphiX wissen vorrausgesetzt, aber Delphi solltes du schon können z.b.
was Schleifen oder IF anweisungen sind ebenfalls sollte bekanntt sein was Array sind
(da ist ein sehr wichtiger bestanteil jeder(Fast) anwendung von delphiX sein wird).
Ich werde nicht jede Komponenten beschreiben, es ist ja klar was die
DXTimer oder die DXImageList machen......

Da DelphiX nicht mehr weiter Entwicklet wird verwende ich unDelphiX
http://turbo.gamedev.net/undelphix.asp
das ist der nach fogler von delphiX das ist gleich für die neusten Delphi versionen ausgelegt.

Das Zip Archiv muss entpacken werden( verzeichnis nach wahl) und dieses verzeichnis muss in
Delphi unter dem Menupunkt: "Tools" und auf der Registerkarte "Bibliothek" bei "Bibliothekpfad"
eingetragen werden damit findet Delphi auch die komponenten

Erstes DelphiX Projekt
Jetzt beginen wir mit dem ersten delphiX Projekt:
Als allererstes werden drei Komponenten von DelphiX auf das Form gepackt:
DXDraw, DXTimer, DXImageList

Jetzt wird die DXImageList mit der DXDraw Komponenten verknüpft und zwar mit der Eigenschaft:
DXImageList1.DXDraw:=DXDraw1(geht auch im OI).
Nun muss der Intervall von der DXTimer Komponenten auf 0 gestellt werden.
In normalen Delphi anwendungen ist ja 1 das schnellste bei DelphiX ist 0 das schnellste(jede ms wird
ein Ereignis ausgelöst: das DXTimer Ereignis).

Damit wir nun auch was auf dem Bildschrim sehen müssen wir auch etwas code schreiben.
Du wälst jetzt die DXTimer komponenten aus und dort fügst du ein ereignis hinzu,
OI:ereignise, onTimer(Letztes ereignis). Anschließend wird der Code Editor geöffnet und folgede zeilen werden geschriben:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
procedure TForm1.DXTimer1Timer(Sender: TObject; LagCount: Integer);
begin
  // Fühllt den Hintergrund mit schwarts
  DXDraw1.Surface.Fill(0);
  // Zeichnet das Bild auf dem Bildschrim 
  DXImageList1.Items[0].Draw(DXDraw1.Surface,0,0,0);
  // Gibt das bild auf dem Bilschrim
  DXDraw1.flip
end;



Damit die DXImageListe auch was zeichnen kann muss sie Bilder haben. Bilder werden so hinzugefügt:
Im OI auf Items klicken auf das Dialog was kommt auf das + Symbol klicken und ein Bild duswählen.

Zur Parameter erlärung von der DXImageList:
Items[index].Draw(Dest: TDirectDrawSurface; X, Y,PatternIndex: Integer)
Es gibt auch nach indexOf bei Items dort kannst du einen Namen eingeben das hat den vorteil,
wenn sich die liste verändern musst du nicht alles nach bessern.

Dest: damit DelphiX weißt auf welchen Surface gezeichnet werden soll
X,Y: Die position auf der DXDraw Komponente es geht Oben Linx los
PatternIndex: du verwendes eine Grafik mit mehren gleichgroßen Bildern auch Tiles gennant.
Das geht aber nur wenn du vohrer in der DXImageList unter items die PatternWith und PatternHeight
mit werden fütterst.

Damit die ImageList auch mit jpeg arbeiten kann(wie im beispiel) muss der uses die unit Jpeg hinzugefügt werden.

Zur der Flip Funktion: es wird ein Bild in einen Backpuffer geschriben und mit der Flip Funktion auf
den Fornbuffer gezeichnet(jetzt sehen wir das Bild) so wird der Flimmer effegt vermiden der da ist
wenn nicht DoubleBuffered auf True steht.

So damit währe die erste DelphiX Anwendung zu ende jetzt solltes du ein bild sehen.

Erstes Beispiel Sokubahn(Zusammenfassung)
So damit wir das Spiel Sokubahn auch Schreiben können müssen wir und darüber gedanken machen
wie wir die Objekte auf der Karte verwalten die beste und einfachste möglichkeit ist ein 2D Array
da Sokubahn ja nur gleichgroße Objkekte verwendet.

Jetzt muss eine großer der Tiles und der Karter ausgewählt werden.
Ich nehme mal 640 X 480 Pixl(Standart größe vom kleinen Spielen).

Damit wir ein Raster enhalten sollten wir ein gerade Zahl nehmen z.b. 20:
640 div 20 = 32-1(weil die Array fangen ja bei 0 an)
480 div 20 = 24-1

Dies ergbnis Speichern wir in den Konstanten Variablen
MapX = 31
MapY = 23
MapS = 20 // Raster größe

So jetzt fängt das eigentliche Spiele Programieren an. Es geht damit los die Grafiken zusammen zustellen
die man benötigt und wie sollen sie verwaltet werden ?

Ich mache das einfach so:
bei meinen Projekten gibt es im verzeichnis: Image eine datei namens image.txt
dort stehen alle Image drinen die gebraucht weren die Datei ist so aufgebaut:

background.bmp; Verzeichnis namen(muss sich im gleichen verzeichnis befinden wie die datei)
0,0; Die Pattern Größe
B; Der Alias(jedes Item kann ein Namen haben)
clNone Trantzparent Farbe

das ganze sieht jetzt so aus
background.bmp;0,0;B;clNone

Ich habe ein kleines tools geschrieben was diese Dateien erstellen kann.

Jetzt muss dieses Datei geladen werden: DelphiX hat zwar sein eigens Grafik archiv format
nur da ist der Nachteil das dies Dateien immer neu erstellt werden müssen sobalt sich eine Datei ändern
das ist in meinem Format nicht der fall nur du musst es selbst laden d.h. die funktion dafür schreiben.

Wir werden eine Unit erstellen um nützliche funktionen abzuspeichern die nennen wir dann: DX_Tools
So könnte die Funktion aussehem zum laded der Grafiken aussehen damit diese unit auch funktioniert musst du noch folgende
funktion als erstes hinzufügen(die werde ich nicht beschreiben, da sie nichts mit delphiX zu tuen hat).

Ich hoffe du weißst wie man Units erstellt und Funktionen hinzufügt, weil dies werde ich nicht erklären.


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:
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:
function GetToken(aString: String; SepChar: Char; TokenNum: Byte):String;
var
   Token     : String;
   StrLen    : Byte;
   TNum      : Byte;
   TEnd      : Byte;

begin
  StrLen := Length(aString);
  TNum   := 1;
  TEnd   := StrLen;
  while ((TNum <= TokenNum) and (TEnd <> 0)) do begin
    TEnd := Pos(SepChar,aString);
    if TEnd <> 0 then begin
      Token := Copy(aString,1,TEnd-1);
      Delete(aString,1,TEnd);
      Inc(TNum);
    end else Token := aString;
  end;

  if TNum >= TokenNum then
    Result := Token
  else begin
    Result := Format('Fehler: Tokennummer (%s) ist größer als token !',[aString]);
    MessageBox(0,pchar(Result),nil,MB_OK or MB_ICONEXCLAMATION);
  end;
end;

procedure LoadImageToListe(FileName:TFileName; DXImageList:TDXImageList);
var
  i:integer;
  bilder:TStringList;
  str:String;
begin
  // Zum Speichern der Image Datei
  bilder:=TStringList.create;
  bilder.LoadFromFile(FileName);

  // Lädt alle Image Dateien in die DxImageList
  for i:=0 to bilder.count-1 do begin
    DXImageList.Items.Add;
    with DXImageList.Items[i] do begin // Setzt die eigenschaften
      Picture.LoadFromFile(ImageDir + GetToken(Bilder.Strings[i],';',1)); 
      str:=GetToken(bilder.strings[i],';',2);

      PatternHeight:=StrToInt(GetToken( str,',',1));;
      PatternWidth:=StrToInt(GetToken( str,',',2));;

      Name:=GetToken(bilder.Strings[i],';',3);
      Transparent:=True; TransparentColor:=StringToColor(GetToken(bilder.Strings[i],';',4) );

    end;
  end;
end;


Die Funktion sollte verstäntlich sein. Die Kommt nun in die DX_Tools.pas rein. So jetzt geht es weiter, erstelle
ein Verzeichnis Image da drint erstellt du die Dateien


Delphi-Quelltext
1:
2:
3:
4:
steine.bmp(40 X 20 also zwei Bilder)
ziele.bmp(20 X 20 also zwei Bilder)
kasten.bmp(20 X 20 also zwei Bilder)
ziele.bmp(20 X 20 also zwei Bilder)


und jetzt erstellt du eine Datei names image.txt und schreibst dort folgendes rein:


Delphi-Quelltext
1:
2:
3:
4:
steine.bmp;20,20;S;clNone
player.bmp;20,20;p;clNone
kasten.bmp;20,20;k;clNone
ziele.bmp;20,20;z;clNone


damit wir auch was sehen werden wir das erste Projekt neu abspeichern und zwar unter Kap2. Wir löschen das
Image aus der DXimageList(Items\ - Symbole und auf OK) und fügen beim erstellen das Formlaures die funktion
LoadImageToList, die sieht dann so aus:


Delphi-Quelltext
1:
2:
3:
4:
procedure TForm1.FormCreate(Sender: TObject);
begin
  LoadImageToListe(GetExeDir + '\Image\image.txt',GetExeDir + '\Image\',DXImageList1);
end;


Complier jetzt mal dein Projekt und Starte es wenn alles gut geht dürftes du jetzt nichts sehen

Jetzt kommt der eignentliche teiel, das Zeichnen von mehren grafiken:
Du füghst ein 2D Array hinzu bei den goblaen variabeln
Map:array[0..MapX,0..MapY] of Integer;
zur bessern übersicht erstellen wir unter const(muss noch hinzugefügt werden über den Typs) die variabeln:
// Wenn die index stimmem kannst du sie so übernehmen ansonst musst du sie anpassen

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
const
  MapX = 31;
  MapY = 23;
  MapS = 20// Raster größe

  None   = -1;
  Stein  = 0;
  Kasten = 2;
  Ziel   = 3;

  // ist verstänlicher, so weiß jeder welche richtung gewünscht ist(alle angeben gehen davon aus das es die 
  // Linke obere ecke vom Zeichenfenseter ist(DXDraw) 
  Lings  = -1;
  Rechts = +1;
  Oben   = -1;
  Unten  = +1;


jetzt fügst du folgende sachen unter private der Forms class hinzu:

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:
    // Unsere Karte ist ein 2D array
    Map:array[0..MapX, 0..MapY] of TMap;

    // Angaben über den Player werden hier gespeichert
    Player:TPlayer;

    // Damit es besser aussieht
    c:string;

    // Löscht die gesammte Karte
    procedure ClearMap;

    // Erstellt eine Map
    procedure CreateMap;

    // Erstellt einen Rand um die Karte
    procedure AddMapRand;

    // Verschieb den Player
    procedure MovePlayer(x,y:Integer);

    // Erstellt Obj
    procedure CreateObj(x,y,typ,tex:Integer);


und so sehen die "sachen" mit leben gefühlt aus

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:
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:
procedure TForm1.CreateObj(x,y,typ,tex:Integer);
begin
  Map[x,y].Typ1:=Typ;
  Map[x,y].Tex1:=Tex;
  if typ = Stein then
    Map[x,y].frei:=False;    
end;

// am besten über OI ereignise und dann doppelt klick auf das DXTimer ereignis
procedure TForm1.DXTimer1Timer(Sender: TObject; LagCount: Integer);
var
  x,y:Integer;
begin
  // Fühllt den Hintergrund mit schwarts
  DXDraw1.Surface.Fill(0);
  // Zeichnet die Karte
  for x:=0 to MapX do begin
    for y:=0 to MapY do begin
      if Map[x,y].Typ1 <> None then
        // *MapS = damit die urspünglichen position angaben wider da sind(Raster to Windows*G*)
        DXImageList1.Items[Map[x,y].typ1].Draw(DXDraw1.Surface,x*MapS,y*MapS,Map[x,y].tex1);
    end;
  end;

  // Der Player wird gezeichnet
  DXImageList1.Items[1].Draw(DXDraw1.Surface,player.x*MapS,player.y*MapS,player.Tex);

  // Gibt das bild auf dem Bilschrim
  DXDraw1.flip
end;
procedure TForm1.MovePlayer(x,y:Integer);
var
  px,py:Integer;
begin
  // Player pos einmal speichern(wegen geschwindigkeit und übersichtlichkeit
  px:=player.x+x;
  py:=player.y+y;
  // ist das der gewünschte kasten begbar ?
  if Map[px,py].frei = True then begin
  // wenn ja, ist das nächste Fehld vom typ kasten ?
    if Map[px,py].typ1 = Kasten then begin
      // dann prüfe ob das zweite fehld vom Player auch noch frei ist
      // wenn ja verschiebe es in der gewünschten richtung
      if Map[px+x,py+y].frei = True then begin
        // Altes Fehld sichern, damit wir es wieder herrstellen können
        Map[px+x,py+y].Typ2:=Map[px+x,py+y].Typ1;
        Map[px+x,py+y].Tex2:=Map[px+x,py+y].Tex1;

        // Angaben vom alten Feld übernehem
        Map[px+x,py+y].Typ1:=Map[px,py].Typ1;
        Map[px+x,py+y].Tex1:=Map[px,py].Tex1;

        // Altes Fehld löschen, aber nur wenn es sich um ein ziel handelt
        if Map[px,py].Typ2 = Ziel then begin
          Map[px,py].Typ1:=Map[px,py].Typ2;
          Map[px,py].Tex1:=Map[px,py].Tex2;
        end
        else begin // wenn nicht löschen
          Map[px,py].Typ1:=None;
          Map[px,py].Tex1:=0;
        end;

        // kasten Fehld wieder frei machen
        Map[px,py].frei:=True;
        // Player position anpassen
        Player.x:=px;
        Player.y:=py;

      end;
    end
    else begin
      // wenn es kein fehld vom typ kasten da ist verschieb die player pos einfach so
      Player.x:=px;
      Player.y:=py;
    end;
  end;
  Form1.Caption:=c +' ' + IntToStr(px) + '\' + IntToStr(py);

end;

procedure TForm1.AddMapRand;
var
  x,y:Integer;
begin
  Randomize;
  for x:=0 to MapX do  // Oben
    CreateObj(x,0,stein,0);

  for x:=0 to MapX do // Unten
   CreateObj(x,MapY,stein,0);

  for y:=0 to Mapy do  // Lings
    CreateObj(0,y,stein,0);

  for y:=0 to MapY do  // Rechts
    CreateObj(Mapx,y,stein,0);
end;

procedure TForm1.CreateMap;
var
  x,y:Integer;
begin
   AddMapRand;
   // Inenleben wird erstellt
   for x:=5 to 20 do
    CreateObj(x,5,stein,1);
    
   for x:=5 to 20 do
    CreateObj(x,20,stein,1);

   for y:=5 to 20 do 
    CreateObj(20,y,stein,1);

   // Kasten werden erstellt
   CreateObj(10,11,Kasten,0);
   CreateObj(11,11,Kasten,0);
   CreateObj(10,12,Kasten,0);

   // Ziele werden erstellt
   CreateObj(28,5,Ziel,0);
   CreateObj(27,20,Ziel,0);
   CreateObj(22,12,Ziel,0);

   Player.x:=2;
   Player.y:=12;
   Player.Tex:=0;      
end;

procedure TForm1.ClearMap;
var
  x,y:Integer;
begin
  // Geht das 2D array in zwei forschleifen durch und setzt
  // Typ1 und Typ2 auf none
  for x:=0 to MapX do begin
    for y:=0 to MapY do begin
      map[x,y].Typ1:=None;
      map[x,y].Typ2:=None;
      map[x,y].Tex1:=None;
      map[x,y].Tex2:=None;
      map[x,y].Frei:=True;
    end;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  c:='Erste DelphiX anwendung';
  LoadImageToListe(GetExeDir + 'Image\image.txt',GetExeDir + '\Image\',DXImageList1);
  ClearMap;
  CreateMap;
end;


Wenn du alles richtig gemacht hast soltles du eine Karte sehen mit einem Rand und einem C in etwa sollte es so aussehen
(habe wie gesagt leider keinen Server so muss ich es halt mit assci zeichen da stellen)


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
------------------
-             z  - 
-  ------        - 
-    .. -  z     - 
-    .  -        - 
-  ------    z   -
------------------

Ich hoffe das wahr verständlich.
Vorschläge, Verbesserungs wünsche und sowas in der art sind erwünscht(bitte nicht über die rechtschreibung reden nur einfach
wenn nötig fehler melden dann kann ich sie beheben)
dieses Totur habe ich in zwei Tagen erstellt wobei ich heute den meisten Teil geschrieben habe ich hoffe es hilft jemmanden weiter


mimi - So 13.02.05 15:18

der letzte Teil kommt später(wenn ich wieder lust dazu habe *G*)


Chris Maslowski - Di 22.02.05 13:56

könntest du mir viellecht mal den ganzen quelltext per e-mail schicken?(chris.maslowski@freenet.de) Das wäre sehr nett. Schon mal danke im voraus


mimi - Di 22.02.05 18:19

kann ich leider erst am wochenende weil ich kein webserver habe sonst könnte ich ihn eifach hochladen *G*


F34r0fTh3D4rk - Mo 28.02.05 17:48

kann jemand mal das tutorial non-dx machen ? EDIT: Bin gerade dabei

noch nefrage: woher krieg ich delphiX für delphi6 ?


mimi - Sa 05.03.05 15:58

das unDelphiX ist dafür auch geiengent, es unterstützt meines wissen 5-7 ....
non-dx ?
ohne delphiX ? ist auch nicht weiter schwirig... so habe ich angefangen bei der spiele entwicklung bei delphi.
Mal sehen ob ich dafür auch ein tutor schreibe


F34r0fTh3D4rk - Sa 05.03.05 15:59

der code ist schon fertig (hier im forum)


mimi - Sa 05.03.05 16:09

und wo ?


F34r0fTh3D4rk - Sa 05.03.05 16:19

http://www.delphi-forum.de/viewtopic.php?t=37562&highlight=&sid=a22684bd9141a49be512be957d293ed4

der code ganz unten