Autor Beitrag
Shanks
Hält's aus hier
Beiträge: 4

Win XP

BeitragVerfasst: Di 11.04.06 16:11 
Hi,

ich bin neu hier und auch recht neu in Sachen programmierung. Ich hoffe, dass mir hier jemand weiter helfen kann.
Ich arbeite derzeit an dem Spiel Minesweeper, welches ich mit Delphi programmieren möchte. Ich habe für die erste Stufe 81 kleine Panels erstellt ( weis nicht, ob man das einfacher machen kann). Mittels eines 2D Arrays habe ich 10 Minen verteilt. Jedes Panel hat den Namen PanelA(x)(y). Also z.B: PanelA32. Wobei die erste Ziffer für den x Wert und die zweite für den y Wert stehen soll. Wie kann ich es schaffen, dass ich die Zahlen im Panelnamen als Variablen verwenden kann?

Schonmal danke im Vorraus.
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Di 11.04.06 16:22 
Moin und :welcome: im Forum!

Schau dich mal nach dem Stichwort Suche in: Delphi-Forum, Delphi-Library FINDCOMPONENT um, damit solltest du weiterkommen.

Vielleicht kannst du dir aus diesem Tut auch noch ein paar Anregungen holen. ;)

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
Stoney
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 122

Mac OS X 10.6 "Snow Leopard", Ubuntu Linux 9.04, Mandriva 2010, Win 7, Win Vista, Win XP
Object Pascal (Turbo Delphi, FPC 2.2.4, Lazarus), C++ (Code::Blocks, XCode), Java (Eclipse)
BeitragVerfasst: Di 11.04.06 16:24 
81 Panels zu erstellen muss doch eine Mordsarbeit gewesen, zumal ich nicht aus deinem Post herauslese, dass die dynamisch erzeugt wurden. Wenn du dir wirklich so viel Arbeit aufsatteln willst, solltest du am besten mit dem Befehl FindComponent arbeiten:
ausblenden Delphi-Quelltext
1:
  (FindComponent('PanelA'+IntToStr(x)+IntToStr(y)) as TPanel).Caption := 'Mine';					

Panels sind übrigens auch sehr speicherlastig, damit könntest du einige Computer in die Knie zwingen.

Der einfachere Lösungsweg ist das du nur ne Paintbox schnappst, und mit Hilfe von Canvas darauf malst. Oder du nimmst eine Grafikbibliothek wie DirectX, SDL oder OpenGL und bekommst noch gute Performance zusätzlich dazu.
Martin1966
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1068

Win 2000, Win XP
Delphi 7, Delphi 2005
BeitragVerfasst: Di 11.04.06 16:29 
Hallo Shanks!

Willkommen in der Entwickler-Ecke! :wink2:

Du kannst auch das Draw-Grid. Das wird denke ich noch einfacher sein. ;-)

Lg Martin

_________________
Ein Nutzer der Ecke ;-)
Shanks Threadstarter
Hält's aus hier
Beiträge: 4

Win XP

BeitragVerfasst: Di 11.04.06 16:46 
Erstmal danke für eure schnellen Antworten. Vielleicht wäre es für euch hilfreich, wenn ich mein Problem besser erkläre. Bei dem FindComponent schein ich irgendwas falsch zu machen, denn es klappt nicht. Also hier ne bessere erklärung. entweder habt ihr mich missverstanden oder ich bin zu dumm. ( ich tippe auf letzteres :wink:)

Also ich habe einen Globale 2D Array "FeldA[1..9,1..9] of boolean" erstellt. 2D, weil das Feld ja 81 Felder (Panels) hat. Je nach rechts und unten 9 Stück. Jede Reihe nach rechts hat einen X Wert von 1 bis 9 und auch jede Reihe nach Unten. (Y Wert, 1 bis 9).
Also habe ich vorhin etwas falsch erklärt. z.B. haben die Panels in der obersten Reihe die Zahlen : 11,12,13.... 19. ab dann beginnt die zweite Reihe, nur das sich der Y Wert um eine Zahl erhöht hat, also : 21,22,23.... 29.
Nun habe ich (oder hatte es vor, weil das klappt auch noch nicht so recht) 10 Minen in diesem Array mit dem boolean Wert "True" gesetzt. (bei mir setzt der immer nur eine, trotz "For Schleife")

Nun möchte ich, dass man, wenn man auf ein Panel klickt, ich die Zahlen im Namen als Variable x und y nutzen kann um im Array abzufragen, ob das besagte Feld "True" ist oder nicht.

Eine andere Frage wäre auch noch. Muss ich dafür jedes einzelne Panel mit
"procedure TForm1.PanelA......;
programmieren, oder gibt es eine alles umfassende procedure, mit der ich nicht jedes einzelne Panel neu programmieren müsste?

So ich hoffe ich konnte es etwas besser erklären, falls immer noch unklarheiten sein sollten, kopier ich meine bisherige Codierung ins Forum (ist eh nicht viel)
Martin1966
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1068

Win 2000, Win XP
Delphi 7, Delphi 2005
BeitragVerfasst: Di 11.04.06 16:59 
Hallo!

Ich denke, wir haben dich schon verstanden. ;-) Nur die Info mit der Nummerierung ist neu.

Allerdings würde ich dir immer noch empfehlen das ganze nicht mit Panels zu machen. Wenn du es mit Panels machst dann schleichen sich immer wieder Probleme auf die Du zu lösen hast die Du zum Beispiel mit einem DrawGrid nicht hättest.

Lösche am besten also deine ganzen Panels von deinem Form und erstelle ein DrawGrid mit der entsprechenden Anzahl an Spalten und Reihen. Dort musst du dann das Draw-Event verwenden um die Zellen zu zeichnen.

Dein 2 dimensionales Array sollte nicht aus lauter Boolean Werten bestehen sondern am besten aus einem oder noch besser jeweils zwei Aufzählungstypen. Ein Boolean Wert der festlegt ob hnter der Zelle eine Bombe liegt und ein Aufzählungstype der festlegt ob der User die Zelle schon aufegeckt hat oder nicht oder ob der User dort eine Bombe vermutet.

Beim zeichnen der einzelnen Zellen im DrawGrid kannst du dann den Array verwenden und die entsprechenden Symbole zeichnen.

Dies nur mal so als kleine Hinweise. ;-)

Lg Martin

_________________
Ein Nutzer der Ecke ;-)
Simon Joker
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 236
Erhaltene Danke: 1



BeitragVerfasst: Mi 12.04.06 10:27 
Hallo Shanks

Erstmal willkommen ;-)

@Benutzung von Panels
Die Idee halte ich nicht für so schlecht.

Hinweise:

Datenspeicherung - Ich würde hier wohl kein zweidimensionales Array nehmen, sondern mit einem Eindimensionalen. Die Verwaltung wird so sehr einfach und du brauchst NICHT den Namen der Panels zu parsen um die Richtigen Daten abzufragen. (weiteres dazu weiter untern)

Datentyp - Verwende ein Record mit allen relevanten Daten für das Daten-Array, spart viel Sucherei. Außerdem würde ich ein dynamisches Array empfehlen. Das kannst du ohne Codeänderung auf andere Größen des Minenfeldes scalieren.

Beispiel:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
type
  TViewStats = (vsUnknown,vsFlagged,vsViewed,vsReference);

  TMineFieldRec = record
    GridPosition : TPoint;
    ViewPanel    : TPanel;
    HaveMine     : boolean;
    NearMines    : byte;
    ViewStat     : TViewStats;
  end;
  TMineFieldArray = array of TMineFieldRec;


Da so die größe des Spielfeldes dynamisch ist, sollten auch die Panels dynamisch sein. Dafür braucht es etwas Vorbereitung. Du brauchst dafür Event-Proceduren, die für alle Panels gelten können.

Die Erzeugung sollte in etwa so aussehen.
ausblenden volle Höhe 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:
var NewMinePanel : TPanel;
    i, 
    PosIndexX, PosIndexY, 
    PosPixX, PosPixY : integer;
...
  PanelGround.Visible := false; //Das Gebastel soll ja keiner sehen

  SetLength(MineFieldArray,CountRow*CountCol); //Array auf die benötigte Länge setzen
  //Array initialisieren

  for i := 0 to high(MineFieldArray) do begin
    //Einige Berechnungen
    PosIndexX := i mod CountCol; 
    PosIndexY := i div CountCol;
    PosPixX   := PosIndexX * 20;
    PosPixY   := PosIndexY * 20;
    //Panel erzeugen
    NewMinePanel             := TPanel.Create(PanelGround); //Erzeugen
    NewMinePanel.Parent      := PanelGround;                //Parent setzen, sonst wird es nicht gezeichnet 
    NewMinePanel.Tag         := i+1;                        //DatenArray-Index als Tag merken 
                                                            //-> Schneller Zugriff
                                                            //-> Index +1 weil 0 der Standardwert
    NewMinePanel.Name        := 'MinePanel_'+IntToStr(i); //Namen vergeben für FindComponent-Zugriffe
    NewMinePanel.Left        := PosPixX;                  //X Position
    NewMinePanel.Top         := PosPixY;                  //Y Position
    NewMinePanel.Caption     := '';                       //Caption entsorgen
    NewMinePanel.OnClick     := DynPanelOnClick;          //Event-Procedur zuweisen
    NewMinePanel.Width       := 20;                       //Breite  
    NewMinePanel.Height      := 20;                       //Höhe
    //Datenarray füllen
    MineFieldArray[i].GridPosition.X := PosIndexX;
    MineFieldArray[i].GridPosition.Y := PosIndexY ;
    MineFieldArray[i].ViewPanel      := NewMinePanel;
    MineFieldArray[i].HaveMine       := false;
    MineFieldArray[i].NearMines      := 0;
    MineFieldArray[i].ViewStat       := vsUnknown;
  end;

  ...

  //Minen verteilen und berechnen der Minen in benachbarten Feldern

  PanelGround.Visible := true; //zeigen wir das Ergebniss


Beispiel für die dynamischen Proceduren.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
procedure TForm1.DynPanelOnClick(Sender: TObject);
var 
  MinePanel : TPanel;
  MineData  : TMineFieldRec;
begin
  if Sender is TPanel then begin //Prüfen, ob die Quelle wirklich ein Panel ist
    MinePanel := TPanel(Sender); //Sender als TPanel zuweisen
    //Prüfen, ob Tag im validen Indexbereich
    if (MinePanel.Tag-1 >= 0and (MinePanel.Tag-1 <= high(MineFieldArray)) then begin 
      MineData := MineFieldArray[MinePanel.Tag-1]; //zugehörige Felddaten holen 
      //So jetzt können wir alles machen, was nötig ist
      
      ...

    end;
  end;
end;


So viel Spass

MfG Simon
Shanks Threadstarter
Hält's aus hier
Beiträge: 4

Win XP

BeitragVerfasst: Do 13.04.06 12:53 
Ich bin zwar dankbar für eure vielen Antworten, aber leider kann ich mit den meisten nichts anfangen, da ich kaum ahnung vom Programmieren habe.

Ich habe es mal mit findComponent probiert, aber nur merkwürdige Zahlenwerte bekommen. (über 40.000)

Wie schaffe ich es also, alle 81 Panels mit nur einer Procedure, oder Function anzusprechen?

Und wie bekomm ich das genau hin, mit dem findComponent. Mein Lehrer meinte (als kleine hilfestellung) etwas in der Art: TPanel(findComponent(PanelA'+IntToStr(x)+IntToStr(y)));
Aber damit bekam ich merkwürdige Werte ausgespuckt. Ich bräuchte derzeit wirklich nur hilfe dabei, wie ich die Zahlen aus dem Panelnamen als Variablen verwenden kann und umgekehrt, also wieder die Variablen in den Panelnamen einfügen kann.

Ich weis, dass ich mit meiner unwissenheit nerve, aber als Anfänger bleibt mir leider keine andere Wahl.
Shanks Threadstarter
Hält's aus hier
Beiträge: 4

Win XP

BeitragVerfasst: Fr 14.04.06 10:54 
Ich habe mich jetzt durchgerungen, mein Spiel anders zu gestalten. Möchte es jetzt mit einem Image anfertigen. Jedoch klappt das auch mal wieder überhaupt nicht und ich kann den dummen Fehler nicht finden. Ich schreib jetzt mal meine Codierung zum Zeichnen des Spielfeldes und hoffe, dass mir irgendwer helfen kann.

procedure MinenfeldZeichnen(pMaxX, pMaxY : integer);
var x, y, Feldx, Feldy : integer;
begin
with Form1.Image1 do
begin
Feldx := trunc(Width/AMaxX);
Feldy := trunc(Height/AMaxY);
for y := 1 to pMaxY do
for x := 1 to pMaxX do
Canvas.Brush.Color := clGray;
Canvas.Rectangle(x*Feldx-Feldx,y*Feldy-Feldy,x*Feldx,y*Feldy);
end;
end;

Wenn ich es so mache, seh ich nur unten rechts in der Ecke einen kleinen Strich.
Xion
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
EE-Maler
Beiträge: 1952
Erhaltene Danke: 128

Windows XP
Delphi (2005, SmartInspect), SQL, Lua, Java (Eclipse), C++ (Visual Studio 2010, Qt Creator), Python (Blender), Prolog (SWIProlog), Haskell (ghci)
BeitragVerfasst: Sa 13.05.06 13:30 
Hi

hab auch mal ein Minesweeper gemacht. Ähnlich wie du hab ich BitBtns statt Panels benutzt benutzt und ein 2D-array. jetzt hab ich bei jedem button bei onclick das dann ungefähr so gemacht (hab ich grad etwas modifiziert und weiß nicht obs so funzt.


Button363:=DOCLICK(3,19,Button363);


(ne ziemliche Arbeit bei alle Buttons ;) )

soll heißen: DoClick ist ne function mit Result vom Typ TButton. ich gebe der funktion X,Y-Position des Buttons zum zugehörigen Array-Feld. Zudem geb ich ihm den alten Button (wegen Name usw.). In der Funktion

ausblenden volle Höhe 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:
function DoClick(X,Y: integer; Buttoner: TButton) :TButton;
var A: integer;
begin

with Form1.Buttoner  do
  begin
    A:=Data[X,Y];
    Glyph:=ClearButton.Glyph; //so setze ich das Bild auf Null. Müsste eigentlich doch auch mit Glyph:=Nil; gehen, oder?

   if Marking=true then //Marking bedeudet, ob ich das Feld als Mine markieren will
    begin
      Marking:=False;
      Glyph.LoadFromFile('LEDRedON.BMP');
      Caption:='';
      Font.Color:=clSilver;
    end
   else if Delete=true then //Deletebedeudet, ob ich die Markierung als Mine aufheben will
    begin
     Delete:=False;
     Caption:='';
     Font.Color:=clSilver;
    end
   else
    begin
     if A=0 then
      begin
       Font.Color:=clWhite;  //Zahl+Farbe
       Caption:='-';
      end
     if A=1 then
      begin
       Font.Color:=$00A4FFFF;
       Caption:='1';
      end;
...
    if A=100 then  //100 =Mine
    begin
      Font.Color:=clRed;
      Caption:='';
      Glyph.LoadfromFile('Mine.bmp');
      try
       Form1.MediaPlayer1.Play;
      except
      end;
    end;
 end;
Result:=Buttoner;
end;
end;


müsste so funktionieren, hab grad noch etwas dran rumgebastelt, war schon lange her als ich das Prog gemacht hab.

Xion

_________________
a broken heart is like a broken window - it'll never heal
In einem gut regierten Land ist Armut eine Schande, in einem schlecht regierten Reichtum. (Konfuzius)