Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Variablen ändern bei zur Laufzeiterzeugten Objecten


comes - Mi 10.12.03 23:23
Titel: Variablen ändern bei zur Laufzeiterzeugten Objecten

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:
unit main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls;

type
  TRohstoffe = record
    Uran : boolean;
    cryptonid : boolean;
  end;

type
  TStationierteSchiffe = record
    FrachterKlein : Integer;
    FrachterGross : Integer;
    Kriegsschiffklein : Integer;
    Kriegsschiffgross : Integer;
  end;

type
  TVolk = record
    Krieger : boolean;
    Handelsvolk : boolean;
    Mischvolk : boolean;
  end;

type
  TGebaeude = record
    Kraftwerk : boolean;
    Werft : boolean;
    Schutzschild : boolean;
    Waffensysteme : boolean;
    Forschungsstation : boolean;
    Depot : boolean;
  end;

type
  TPlanet = class
      Bild : TImage;
      Bezeichnung : String;
      AnzahlEinwohner : Integer;
      maxEineohner : Integer;
      Besitzer : String;
      Volk : TVolk;
      Rohstoffe : TRohstoffe;
      StationierteSchiffe : TStationierteSchiffe;
      Gebaeude : TGebaeude;
      neutral : boolean;
   end;

type
  TForm1 = class(TForm)
    Image1: TImage;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
      planet: Tplanet;
      // OnClick handler
      procedure planetClickHandler(Sender: TObject);

    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;
  x : integer = 0;
implementation

{$R *.dfm}
procedure TForm1.planetClickHandler(Sender: TObject); 
begin
  ShowMessage(inttostr(TPlanet(Sender).AnzahlEinwohner));
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
  Planet := TPlanet.Create;
  Planet.Bild := TImage.Create(Self);
  planet.bild.Picture.LoadFromFile('c:\test.bmp');
  Planet.Bild.Parent := Form1;   // Set its parent (Form1)
  Planet.Bild.SetBounds(20+x, 201010);
  planet.Bild.Show;
  Planet.Bild.OnClick := planetClickHandler; // assign onclick handler
  x := x+21;
  planet.AnzahlEinwohner := 10;
end;

end.

In der letzten Zeile wird zwar planet.AnzahlEinwohner auf 10 gesetzt, wenn ich aber den planeten im clickhandler auslese, ist anzahleinwohner = 0. Warum ist das so?

kann mir das mal plz jemand erklären?

Moderiert von user profile iconPeter Lustig: Code- durch Delphi-Tags ersetzt


Nightmare_82 - Mi 10.12.03 23:43

du weist das Click-Event von planet.bild zu, das heißt meines Wissens wird als sender planet.bild übergeben.
Das castest du dann zu TPlanet(dann müßte aber eigentlich eine Fehlermeldun kommen :shock: )
guck mal was passiert, wenn du planet direkt verwendest.

Ansonsten solltest du Planet nur einmal erzeugen in Form1create, sonst verursachst du Memory-Leaks.


Christian S. - Mi 10.12.03 23:49

Es ist ja schon spät, also sagt mir, wenn ich was blödes von mir gebe:

Wo wird der planetClickHandler denn aufgerufen? Ich sehe da nur Zuweisungen! Und erst bei einem Aufruf wird doch der Sender festgelegt!


comes - Mi 10.12.03 23:50
Titel: das soll ja allles...
das soll ja alles dynamisch werden, wie sich hoffentlich erkennen lässt.
ich möchte dann wärend der laufzeit 100 oder 2 oder 1000 dieser objekte erstellen. da kann ich nicht planet nehmen, weil das ja dann nur auf DIESES Eine object bezogen ist. (LEIDER)


comes - Mi 10.12.03 23:54
Titel: eigene onclick?
wenn ich für die classe TPlanet nen eigenes onclick handler benutze sollte dass doch auch gehn, oder?
also nicht plant.bild.onclick sonder planet.onclick? geht das irgendwie zu realisieren?

kann mir da jemand bitte helfen?


merci


Christian S. - Do 11.12.03 00:04

Hallo!

Ich weiß nicht, ob Du meine Frage nicht gesehen hast. Aber wie wird planetClickHandler aufgerufen. Und welcher Parameter wird dort als Sender übergeben?

MfG
Peter


Nightmare_82 - Do 11.12.03 00:07

er erstellt ein Bild und weist das OnClick-Event seiner Funktion zu.
Das ist doch dasselbe, wie wenn man ein Image auf eine Form zieht und auf OnClick doppelklickt?! Und dann wird doch als Sender das Image übergeben *denk*

Aber wie dem auch sei, eine Lösung für dein Problem:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
TPlanet
procedure Click(Sender : TObject);

{...}
planet.bild.onClick:= planet.click;
{...}

procedure TPlanet.click(Sender : TObject)
begin
  form1.planetClickHandler(self);
end;


Christian S. - Do 11.12.03 00:27

Zitat:
er erstellt ein Bild und weist das OnClick-Event seiner Funktion zu.
Das ist doch dasselbe, wie wenn man ein Image auf eine Form zieht und auf OnClick doppelklickt?! Und dann wird doch als Sender das Image übergeben *denk*
Du hast recht. Irgendwie denke ich heute krumm. :?

Aber hier habe ich noch eine Lösung. Ist nicht schön, aber geht:

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:
type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure myImageClickHandler(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

type
  tmyImage = class(TImage) //<- das Ganze von TImage ableiten
    private
    public
      anzahleinwohner : Integer;
  end;


var
  Form1: TForm1;
  planet : TMyImage;

implementation

{$R *.dfm}

procedure TForm1.myImageClickHandler(Sender: TObject);
begin
  if Sender is TmyImage then
    ShowMessage(IntToStr(TMyImage(sender).anzahleinwohner));
end;

procedure TForm1.Button1Click(Sender: TObject);
VAR x : INTEGER;
begin
  x := 20;
  Planet := TmyImage.Create(self);
  planet.Picture.LoadFromFile('c:\test.bmp');
  Planet.Parent := Form1;   // Set its parent (Form1)
  Planet.SetBounds(20+x, 201010);
  planet.Show;
  Planet.OnClick := myImageClickHandler; // assign onclick handler
  x := x+21;
  planet.AnzahlEinwohner := 10;
end;


MfG
Peter

P.S.: Hoffentlich ist meine Lösung nicht auch noch krumm.


comes - Do 11.12.03 00:30
Titel: jupp...

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:
unit main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls;

type
  TRohstoffe = record
    Uran : boolean;
    cryptonid : boolean;
  end;

type
  TStationierteSchiffe = record
    FrachterKlein : Integer;
    FrachterGross : Integer;
    Kriegsschiffklein : Integer;
    Kriegsschiffgross : Integer;
  end;

type
  TVolk = record
    Krieger : boolean;
    Handelsvolk : boolean;
    Mischvolk : boolean;
  end;

type
  TGebaeude = record
    Kraftwerk : boolean;
    Werft : boolean;
    Schutzschild : boolean;
    Waffensysteme : boolean;
    Forschungsstation : boolean;
    Depot : boolean;
  end;

type
  TPlanet = class
      Bild : TImage;
      Bezeichnung : String;
      AnzahlEinwohner : Integer;
      maxEineohner : Integer;
      Besitzer : String;
      Volk : TVolk;
      Rohstoffe : TRohstoffe;
      StationierteSchiffe : TStationierteSchiffe;
      Gebaeude : TGebaeude;
      neutral : boolean;
      procedure OnClick(Sender: TObject);
   end;

type
  TForm1 = class(TForm)
    Image1: TImage;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
      planet: Tplanet;
      // OnClick handler
      procedure planetClickHandler(Sender: TObject);

    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;
  x : integer = 0;
implementation

{$R *.dfm}
procedure TPlanet.OnClick(Sender: TObject);
begin
 form1.planetclickhandler(self);
end;

procedure TForm1.planetClickHandler(Sender: TObject);
begin
  ShowMessage(inttostr(TPlanet(Sender).AnzahlEinwohner));
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
  Planet := TPlanet.Create;
  Planet.Bild := TImage.Create(Self);
  planet.bild.Picture.LoadFromFile('c:\test.bmp');
  Planet.Bild.Parent := Form1;   // Set its parent (Form1)
  Planet.Bild.SetBounds(20+x, 201010);
  planet.Bild.Show;
  Planet.bild.OnClick := planet.OnClick; // assign onclick handler
  x := x+21;
  randomize;
  planet.AnzahlEinwohner := random(10);
end;

end.

jupp, genauso nightmare...
@Peter Lustig, hab es gelöst wie nightmare vorgeschlagen hat.... das is zwar bissl verwurschtelt aber es geht!

aber mal noch so ne frage, wäre es besser das teil als komponente auszulagern oder was wäre dann im gesamt konzept das beste...

plz helped mich mal...


Moderiert von user profile iconPeter Lustig: Code- durch Delphi-Tags ersetzt


Christian S. - Do 11.12.03 00:35

(1) Bitte nutze demnächst die Delphi-Tags!

(2) Randomize sollte nur beim Start des Programmes aufgerufen werden

(3) Wie sieht Dein Gesamtkonzept bisher aus?


Nightmare_82 - Do 11.12.03 00:42

du solltest eine Klasse erstellen, die die ganzen Planeten verwaltet.
Also sowas z.B.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
TWorld = class
private
FPlanets : array of TPlanet;

public
procedure onMouseClick(X, Y : Integer); // dort prüfst du ob ein Planet angeklcikt wurde und rufst seine OnClick-methode auf(wenn er überhaupt eine braucht)

procedure addPlanet({irgendwelche Daten, die er haben soll});
procedure tick; // so eine Funktion wird bei jedem Durchgang aufgerufen und steuert die Intelligenz(könnte z.B. eine Tick-und die Draw-Funktion aller Planeten aufrufen)


Was willst du denn genau machen? Es kommt immer darauf an, was du alles vorhast? Für mich sieht das nach einem Weltraum-Spiel aus oder?
Also Komponenten brauchst du dafür nicht und statt Images würd ich Bitmaps nehmen und deinen Planeten eine eigene draw-Funktion schreiben.
Die Prüfung, ob ein Planet angeklickt wurde kannst du auh selbst erstellen, da du ja die Größe der Bitmaps kenst. Wenn du ein richtiges Spiel machen willst, wirst du schnell feststellen, daß Images saulahm sind wenn man zu viele davon hat.


comes - Do 11.12.03 00:44
Titel: -
Also, das gesamtkonzept wird ein strategiespiel, welches rundenbasierend wird. es wird sobald es aus der probierphase raus ist, auf delphiX bzw. directX exportiert.
Man hat also ein paar planeten, die stück für stück vom spieler besetzt werden, wenn alle planeten vergeben sind, bekriegt man sich gegenseitig, bis alle planeten im eigenen besitz sind. und so weiter und sofort, das konzept sollte klar sein.

okay, delphi tags werd ich in zukunft verwenden und die sache mit dem randomize war nur zu test zwecken...


frohe weihnachten, mfg,comes


comes - Do 11.12.03 00:47


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
TWorld = class 
private 
FPlanets : array of TPlanet; 

public 
procedure onMouseClick(X, Y : Integer); // dort prüfst du ob ein Planet angeklcikt wurde und rufst seine OnClick-methode auf(wenn er überhaupt eine braucht) 

procedure addPlanet({irgendwelche Daten, die er haben soll}); 
procedure tick; // so eine Funktion wird bei jedem Durchgang aufgerufen und steuert die Intelligenz(könnte z.B. eine Tick-und die Draw-Funktion aller Planeten aufrufen)

wie meinst das genau? mach ma plz ein grobes bsp. hab noch nich so wirklich mit extra units gearbeitet

Moderiert von user profile iconPeter Lustig: Code- durch Delphi-Tags ersetzt (wenn Du so weiter machst, gibt es nichts zu Weihnachten)


Nightmare_82 - Do 11.12.03 01:04

OK, also wenn du so ein relativ komplexes Spiel machst, sit es wichtig, daß du die Klassen gut gliederst. Du solltest eine Manager-Klasse haben, die alle wichtigen Objekte verwaltet und zur Kommunikation der verschiedenen Objekte dient.
Du brauchst einen Main-Loop(kannst bei DelphiX einfach den Timer nehmen), der sollte einfach die Tick-Funktion des Manager-Objektes aufrufen.
Dieser Tick des manager könnte so aussehen:



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:
TWorld = class 
private 
FPlanets : array of TPlanet; 
FClicked : Boolean; // wurde nach dem letzten Tick geklickt?

public 
procedure onMouseClick;// rufst du bei Form1.onClick auf
procedure addPlanet({irgendwelche Daten, die er haben soll}); 
procedure tick; // so eine Funktion wird bei jedem Durchgang aufgerufen und steuert die Intelligenz(könnte z.B. eine Tick-und die Draw-Funktion aller Planeten aufrufen)

{...}
procedure TWorld.tick;
VAR
i : Integer;
Mouse : TPoint;
begin
  getCursorPos(Mouse);
  for i:= 0 to high(FPlanets) do
  begin
   FPlanets[i].tick;
   
   if (Clicked) and ({Mouse über Planet}then
     FPlanets[i].onClick(Mouse.X, Mouse.Y);
   FPlanets[i].draw;
  end;
  Clicked:= false;
end;


In deiner Form1 werden dann nur die Events an TWorld weitergeleitet und im Timer wird die Tick-Funktion von TWorld aufgerufen.
Wenn du das so machst kannst du dem Planeten als Owner TWorld übergeben. Dann kann jeder Planet z.B. über eine Funktion GetNearestPlanetAt(X, Y : Integer) : PPlanet; die Welt fragen, welcher Planet am nächsten liegt etc.