Autor |
Beitrag |
r@cer
Hält's aus hier
Beiträge: 13
Win 7, Ubuntu 10.10
Delphi 5 Prof., Lazarus
|
Verfasst: Do 07.04.11 01:26
Hallo ...
ich bin noch ein Anfänger was es das Programmieren mit Delphi (und auch allgemein) betrifft. Wir haben in der Schule angefangen das Spiel Minesweeper zu programmieren und ich beschäftige mich gerade zuhause ein wenig damit.
Das heißt ich versuche in dem Programm weiterzukommen, hänge aber gerade an einer gewissen Stelle.
Mein Problem ist Folgendes:
Für die verschiedenen Felder in dem Spiel verwenden wir Images. Und ich versuche gerade die ImageClick-Procedure zu programmieren.
Das heißt, wenn ein Bild angeklickt wird muss das Programm überpüfen, ob eines oder mehrere der angrenzenden Felder eine Mine ist.
ich habe einfach angefangen und lasse das Programm erst einmal überprüfen ob überhaupt eines der Felder eine Mine ist (also ob es vielleicht auch mehrere gibt, interessiert mich erst mal nicht).
Wir haben in der Schule dafür einen sehr schreibaufwendigen aber vom Denken her einfachen Weg gewählt. Nämlich haben wir eine Variable namens "umbebung" vom typ array deklariert:
Delphi-Quelltext 1:
| var umgebung: array[1..25,1..8] of byte; | wie ihr seht gibt es in meinem Spiel auch nur 25 Felder und die maximale Anzahl an benachbarten Feldern ist 8.
in einer butten-procedure habe ich dann folgendes abgetippt (deswegen auch "schreibaufwendig"):
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| umgebung[1,1]:=Image2.tag; umgebung[1,2]:=Image7.tag; umgebung[1,3]:=Image6.tag; umgebung[2,1]:=Image3.tag; umgebung[2,2]:=Image8.tag; umgebung[2,3]:=Image7.tag; umgebung[2,4]:=Image6.tag; | das heißt ich kann die Nachbarfelder jedes geklickten Feldes mit diesen Variablen angeben.
mein Problem liegt nun in der ImageClick-procedure:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| procedure TForm1.ImageClick(Sender: TObject); var i,a:byte; begin for i:=1 to 8 do begin if umgebung[tag,i]=bombenposition[1] then begin a:=1; showmessage(inttostr(a)); end else begin a:=0; showmessage(inttostr(a)); end; end; end; |
das Problem ist, dass ich nicht so richtig weiß wie es mit dem "tag" funktioniert. Also ich weiß nicht genau wie ich dem Programm hier vermitteln soll, welches Bild jetzt genau geklickt wurde. Ich hab mir hier gedacht, dass ich ja eine Schleife verwenden kann, in der für jedes Nachbarfeld (des geklickten Feldes) überprüft wird ob es sich um eine Mine handelt. Und wenn eine Mine existiert, dann lasse ich mir eine showmessage anzeigen, damit ich sehe ob's geklappt hat. also es wird entweder a=1 oder a=0 gezeigt.
Wenn ich das Programm starte, erhalte ich also insgesamt 8 Meldungen (wegen der Schleife) die entweder eine 1 oder eine 0 enthalten. Aber ich bekomme nach jedem Programmstart, bei jedem Bild auf das ich klicke, in der fünften Meldung eine 1 angezeigt und in den restlichen Nullen. Also habe ich es mal an einem konkreten Beispiel probiert für den Fall das ich das zwölfte Bild anklicke. Das heißt ich habe im Code oben das tag durch eine 12 ersetzt: ... umgebung[12,i]=bombenposition[1] ...
übrigens bekomme ich auch bei jedem Programmstart vier meldungen die mir die Positionen der jeweiligen vier minen mitteilen (da ich nur vier Minen verwende). Ich muss in diesem beispiel mit der zwölf also so lange neustarten bis die erste Mine (da ich bombenposition[1] verwende) auf ein Nachbarfeld der 12 fällt. Als dies der Fall war habe ich die zwölf angeklickt und ich bekam wieder meine 8 Meldungen. Diesmal hat es aber funkioniert. Ich bekam eine 1 in der zweiten Meldung, da auch die Mine genau auf dem zweiten Nachbarfeld plaziert war.
das heißt schließlich, dass es mit diesem tag nicht so einfach geht wie ich mir das gedacht habe. ich könnte mir natürlich für jedes der 25 Bilder eine eigene ImageClick-Procedure anlegen und es komplett so programmieren wie ich es auch mit der 12 gemacht hatte, aber das wäre mir dann doch zu aufwändig. Ich muss es also irgendwie schaffen, dem Programm mitzuteilen, welches der Felder gerade angeklickt wurde,
und da wäre ich froh wenn mir hoffentlich jemand aus dem Forum hier ein paar Tipps geben könnte
.... und sorry falls ich etwas zu viel Text für dieses kleine Problem verschwendet habe
lg r@cer
Moderiert von Narses: Delphi-Tags repariert/hinzugefügtModeriert von Narses: Topic aus Multimedia / Grafik verschoben am Do 07.04.2011 um 01:49
|
|
Narses
      

Beiträge: 10183
Erhaltene Danke: 1256
W10ent
TP3 .. D7pro .. D10.2CE
|
Verfasst: Do 07.04.11 02:39
Moin und  im Forum!
Dein Ansatz hat ein paar grundsätzliche "Probleme", deshalb möchte ich dir mal einen anderen vorstellen.
Erstmal ein paar Definitionen, damit man das später besser anpassen kann (unter die uses-Klausel setzen):
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| const sx = 25; sy = 25; dx = 12; dy = 12; mines = 4; type TForm1 = class(TForm) procedure FormCreate(Sender: TObject); procedure ImageClick(Sender: TObject); private public Field: array[0..sx*sy-1] of TImage; procedure SetImageColor(const i: Integer; const AColor: TColor); end; | Und hinterher gleich die Klassendeklaration des Formulars. Du brauchst in der IDE keine Komponenten drauf zu legen, die Images werden alle beim Programmstart dynamisch auf die Form gebracht.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| procedure TForm1.FormCreate(Sender: TObject); var i: Integer; begin for i := 0 to sx*sy-1 do begin Field[i] := TImage.Create(Self); Field[i].Parent := Self; Field[i].Tag := i; Field[i].Left := (i mod sx) *dx; Field[i].Top := (i div sx) *dy; Field[i].Width := dx; Field[i].Height := dy; Field[i].Picture.Bitmap.Width := dx; Field[i].Picture.Bitmap.Height := dy; Field[i].Picture.Bitmap.PixelFormat := pf24bit; SetImageColor(i, clWhite); Field[i].OnClick := ImageClick; end; end; |
Wenn man auf ein Image geklickt hat, landet man hier. Dabei wird in dem Parameter Sender das Image übergeben, das den Klick ausgelöst hat.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| procedure TForm1.ImageClick(Sender: TObject); var ThisImage: TImage; x, y, ix, iy: Integer; begin ThisImage := Sender as TImage; x := ThisImage.Tag mod sx; y := ThisImage.Tag div sx; SetImageColor(ThisImage.Tag, clRed); for ix := -1 to 1 do for iy := -1 to 1 do if (ix <> 0) or (iy <> 0) then if ( (x+ix) in [0..sx-1] ) and ( (y+iy) in [0..sy-1] ) then SetImageColor(x+ix +(y+iy)*sx, clBlue); ShowMessageFmt('Feld-Nr.: %d, x:%d, y:%d',[ThisImage.Tag, x, y]); end; |
Noch ein bischen Verwaltungskram:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| procedure TForm1.SetImageColor(const i: Integer; const AColor: TColor); begin if (i >= 0) and (i <= High(Field)) then begin Field[i].Picture.Bitmap.Canvas.Brush.Color := AColor; Field[i].Picture.Bitmap.Canvas.Pen.Color := clGray; Field[i].Picture.Bitmap.Canvas.Rectangle(0,0,dx-1,dy-1); end; end; | Schau mal drüber, ob dir klar ist, wie das funktioniert.  Wenn noch Fragen sind, immer her damit.
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
Für diesen Beitrag haben gedankt: r@cer
|
|
r@cer 
Hält's aus hier
Beiträge: 13
Win 7, Ubuntu 10.10
Delphi 5 Prof., Lazarus
|
Verfasst: Sa 16.04.11 19:23
ok vielen Dank für die antwort
Zwar habe ich nicht sofort deinen kompletten Ansatz übernommen, aber es hat mich trotzdem weitergebracht. Z.B. hab ich das mit dem Tag, dank deines Codes jetzt verstanden und habe es folgendermaßen angewandt:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| procedure TForm1.ImageClick(Sender: TObject); var i,j:byte; image_geklickt: TImage; t: integer; begin
image_geklickt := Sender as TImage; t:= image_geklickt.tag; for j:=1 to 4 do begin for i:=1 to 8 do begin if umgebung[t,i]=bombenposition[j] then begin z[j]:=j; end; end; end; end; |
damit hat es funktionniert und ich konnte den groben ablauf des Programms soweit fertig schreiben. Natürlich fehlen noch gewisse Feinheiten wie die Flagge, die bei einem Rechts-Klick erscheint usw.
Nachdem wir es aber in der Schule mit dem Lehrer nochmal etwas aufpoliert haben, sieht diese Prozedur schließlich so aus:
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:
| procedure TForm1.ImageClick(Sender: TObject); var nr,i,j,bombenzahl:byte; bombe_getroffen:boolean; begin bombenzahl:=0; bombe_getroffen:=false; with sender as timage do begin nr:=tag;
for i:=1 to 4 do if bombenposition[i]=nr then begin picture.LoadFromFile('bombe.bmp'); bombe_getroffen:=true; end;
if not bombe_getroffen then begin for i:=1 to 4 do begin for j:=1 to 8 do begin if umgebung[nr,j]=bombenposition[i] then begin inc(bombenzahl) end; end; end; case bombenzahl of 0:picture.LoadFromFile('leer.bmp'); 1:picture.LoadFromFile('1.bmp'); 2:picture.LoadFromFile('2.bmp'); 3:picture.LoadFromFile('3.bmp'); 4:picture.LoadFromFile('4.bmp'); end; end; end; end; |
Da alles funktionniert, und wir den Ablauf des Programms soweit verstanden haben, hat unser Lehrer das Projekt mit uns abgeschlossen. Er hat aber gemeint, dass natürlich jeder für sich dem Programm noch einen Feinschliff verpassen kann.
Also hab ich mir gedacht, dass ich z.B. ein Hauptmenü erstellen kann und dann in dem Hauptmenü (genau wie bei dem Minesweeper von Microsoft Windows) einen Unterpunkt "Spiel starten" und einen mit "Optionen". Ich habe mir das mit den "Optionen" so vorgestellt, dass sich ein neues Fenster öffnet in dem man den Schwierigkeitsgrad auswählen kann und den Sound ein oder ausschalten kann.
Ich bin jetzt auch schon so weit, dass ich einen neuen Frame mit einer Unit2 hinzugefügt habe. Und programmieren wollte ich das folgendermaßen: Ich möchte eine Prozedur für den Reiter "Optionen" erstellen in der durch einen Befehl wie z.B. TForm2.visible:=true; das dazugehörige Fenster erscheint.
Jetzt ist mir aber schon klar, das man das mit so einem Befehl sehr wahrscheinlich nicht zum laufen bringt, da sich die erwähnte Prozedur in Unit1 befindet und man mit dem "Visible-Befehl", soweit ich weiß, nur Objekte (wie Buttons, TImages, Panels usw), die sich auf eben diesem TForm1 befinden, unsichtbar machen kann.
Also mein Problem ist ganz einfach dieses, dass ich eine Unit1 habe in der man das eine Fenster programmiert und eine Unit2 die für das zweite Fenster zuständig ist. Und ich weiß eben nicht, wie man in Unit1 mit einem Befehl das zweite Fenster "steuern" kann.
hoffe erneut auf etwas Hilfe
Gruß r@cer
|
|
jaenicke
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Sa 16.04.11 19:47
r@cer hat folgendes geschrieben : | Ich bin jetzt auch schon so weit, dass ich einen neuen Frame mit einer Unit2 hinzugefügt habe. |
Frame oder Form? Das ist ein Unterschied, ein neues Formular wäre hier ein neues Fenster, ein Frame ist ein Container für mehrere Objekte.
r@cer hat folgendes geschrieben : | einen Befehl wie z.B. TForm2.visible:=true;
[...] man mit dem "Visible-Befehl", soweit ich weiß, nur Objekte (wie Buttons, TImages, Panels usw), die sich auf eben diesem TForm1 befinden, unsichtbar machen kann. |
Doch, das ist schon richtig so.
Wenn du ein zweites Fenster TForm2 hast (vergib besser einen richtigen Namen  ), kannst du das auch so steuern: Delphi-Quelltext 1: 2: 3: 4:
| Form2.Show; Form2.ShowModal; Form2.Hide; ... |
r@cer hat folgendes geschrieben : | Delphi-Quelltext 1: 2:
| 0:picture.LoadFromFile('leer.bmp'); 1:picture.LoadFromFile('1.bmp'); | |
Da fehlt die Pfadangabe, die ist sehr wichtig:
www.delphi-library.d...ewtopic.php?p=499701
|
|
beastofchaos
      
Beiträge: 247
Erhaltene Danke: 4
|
Verfasst: Sa 16.04.11 23:34
Bei Pfad-Angabe empfehle ich dir eher die Var path(String) zu erzeugen und dann im FormCreate folgendermaßen zu ermitteln;
Delphi-Quelltext 1:
| path := ExtractFilePath(Application.ExeName); |
Dann muss du deine Prozedur so schreiben:
Delphi-Quelltext 1:
| picture.LoadFromFile(path + 'leer.bmp'); |
Gruß, Thomas
|
|
r@cer 
Hält's aus hier
Beiträge: 13
Win 7, Ubuntu 10.10
Delphi 5 Prof., Lazarus
|
Verfasst: So 17.04.11 10:08
Was eignet sich für mein Vorhaben den besser? - ein Frame oder ein Formular?
Und wo ist der Unterschied?
Aber es hat jetzt mit einem neuen Formular geklappt  . (Ich hatte vorher ein Frame benutzt)
Was die Sache mit dem Pfad betrifft, verstehe ich nicht so richtig für was das gut sein soll, da es ja auch ohne funktionniert. Denn die Bilder liegen alle im selben Ordner, in dem auch die Exe liegt.
Gruß r@cer
|
|
beastofchaos
      
Beiträge: 247
Erhaltene Danke: 4
|
Verfasst: So 17.04.11 10:58
KANN zu Fehlern führen. Angenommen du hast zwei Images. Normalerweise legt man sich alle BIlder in einen extra rdner, genauso alle Sounds/ Datenbanken, etc. - kensnt du sicher von größeren Spielen/ Programmen:
Delphi-Quelltext 1: 2: 3:
| Image1.LoadFormFile('Pictures/Bild1.bmp'); Image2.LoadFormFile('Pictures/Bild2.bmp'); |
Klar känntest du dann bei jedem weitern mal einfach das Pictures am Anfang weglassen, aber um auf Sound etc. zuzugreifen musst du erst wieder in den Exe-ordner (indem du vor den Pfad ein "../" setzt);
Das kann dabei so unübersichtlich werden, dass man am besten von anfang an so arbeitet  Wenn du sowieso alles im Exe-Ordner rumliegen hast, ist das egal, aber wäre gut für eine saubere Lösung vll.
Grüße, Thomas
|
|
jaenicke
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: So 17.04.11 11:01
r@cer hat folgendes geschrieben : | Was die Sache mit dem Pfad betrifft, verstehe ich nicht so richtig für was das gut sein soll, da es ja auch ohne funktionniert. Denn die Bilder liegen alle im selben Ordner, in dem auch die Exe liegt. |
Lesen magst du wohl nicht oder wie? Ich habe es unter dem Link doch ausführlich erklärt inklusive Beispiel...
Dann pack einfach einmal einen Öffnen-Dialog auf dein Formular, zeige den als allererstes in FormCreate an und wähle in dem einfach eine Datei aus einem anderen Verzeichnis aus. Und schon geht gar nichts mehr.
Denn wenn du kein Verzeichnis angibst, wird nicht im Verzeichnis der Exe gesucht, sondern im aktuellen Arbeitsverzeichnis. Und das hat absolut überhaupt gar nichts mit dem Verzeichnis der Exe zu tun...
beastofchaos hat folgendes geschrieben : | Wenn du sowieso alles im Exe-Ordner rumliegen hast, ist das egal |
Nein, eben nicht.
|
|
beastofchaos
      
Beiträge: 247
Erhaltene Danke: 4
|
Verfasst: So 17.04.11 11:10
|
|
Narses
      

Beiträge: 10183
Erhaltene Danke: 1256
W10ent
TP3 .. D7pro .. D10.2CE
|
Verfasst: So 17.04.11 14:07
Moin!
Wir sind jetzt mittlerweile beim dritten Thema, und das sind eindeutig zwei zu viel.
Bitte für jedes Thema einen separaten Thread nutzen, das wird sonst unübersichtlich.  Da das eigentliche Thema des Threads offensichtlich erledigt ist, mache ich mal zu.
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
Dieses Thema ist gesperrt, Du kannst keine Beiträge editieren oder beantworten.
Das Thema wurde von einem Team-Mitglied geschlossen. Wenn du mit der Schließung des Themas nicht einverstanden bist, kontaktiere bitte das Team.
|
|