Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Speichern verschiedener Objekte in einer Datei (https://www.delphipraxis.net/67077-speichern-verschiedener-objekte-einer-datei.html)

TheAn00bis 9. Apr 2006 11:25


Speichern verschiedener Objekte in einer Datei
 
Hey,

Ich programmiere gerade ein Spiel, dass Karten benötigt. Auf den Karten gibt es Objekte verschiedener Typen und zusätzlich hat die Karte noch weitere Eigenschaften, wie Hintergrundanimationen etc..

Ich würde gerne all diese Daten in einer Datei speichern, da es viele verschiede Objekte gibt und es sehr unschön wäre, für jeden Objekttypen eine eigene Datei anzulegen.

Wie gehe ich vor?

Ich könnte für die verschiedenen Objekte ein Record verwenden; der Record-Typ hätte dann ein Attribut, das besagt, um welchen Objekttypen es sich handelt. Allerdings hängen alle weiteren Attribute vom Objekttypen ab, was bedeutet, dass je nach Objekttyp alle nicht benötigten Attribute leer blieben.
Eine weitere Möglichkeit wäre die Verwendung einer IniDatei, was ich allerdings für genauso unschön halte. Hier würde der Name der Sektion dann vermutlich als Präfix den Objekttypen deklarieren, was auf unschöne Stringoperationen hinausliefe.
Es wäre auch möglich verschiedene Dateien zu benutzen, diese aber in ein Archiv zu packen, aber auch dies wäre ziemlich aufwändig in Bezug auf das Speichern und Laden der Daten.

Was empfehlt ihr mir? Bietet sich die Verwendung einer Datenbank an?

Die Eigenschaften der Karte könnte ich - sofern nicht anders möglich - auch in einer zusätzlichen Ini-Datei speichern, aber die Objekte hätte ich schon lieber in einer Datei.

Bernhard Geyer 9. Apr 2006 11:27

Re: Speichern verschiedener Objekte in einer Datei
 
Wie wäre es mit einer XML-Datei. Dann hast Du auch keine Probleme falls später mal weitere zu speichernde Infos dazu kommen.

jfheins 9. Apr 2006 11:36

Re: Speichern verschiedener Objekte in einer Datei
 
Eine Möglichkeit wäre eine Hier im Forum suchendpCollection - dann müsstest du deine Karten-Objekte von TCollectionItem ableiten, und schon könntest du einfach ein MapObject.SaveToFile machen und fertig ;)

TheAn00bis 11. Apr 2006 10:47

Re: Speichern verschiedener Objekte in einer Datei
 
Ist es auch möglich, ein Record zu nehmen, in welchem Arrays vom Typen der verschiedenen Objekte sind?
Beispiel:

Delphi-Quellcode:
GameObject = record
    objects1 = array of TObject1;
    objects2 = array of TObject2;
    {...}
    property1: Boolean;
    {...}
end;
Dann würde die "file of GameObject" nur ein "GameObject" besitzen, in dem alle restlichen Objekte stünden;
zusätzlich enthielte es auch die weiteren Eigenschaften der Karte.

Ich finde diese Variante unkomplizierter, was möglicherweise auch daran liegt, dass ich mich schon ziemlich an Records gewohnt habe. Dagegen spricht nichts, oder? Würde man das als "unschönen Programmierstil bezeichnen"?

//Edit: Statt der Arrays kann ich sogar TObjectListen verwenden, was das ganze noch komfortabler macht.

jim_raynor 11. Apr 2006 13:51

Re: Speichern verschiedener Objekte in einer Datei
 
Zitat:

Zitat von TheAn00bis
Ist es auch möglich, ein Record zu nehmen, in welchem Arrays vom Typen der verschiedenen Objekte sind?

Nein, da der Record in einem file of keine Strings und dynamische Arrays enthalten darf. Mach ne XML-Datei oder dpCollections. Klingt für den Anfang kompliziert ist aber wesentlich flexibler.

jfheins 11. Apr 2006 13:55

Re: Speichern verschiedener Objekte in einer Datei
 
Delphi-Quellcode:
GameObject = record
    objects1 = array of TObject1;
    objects2 = array of TObject2;
    {...} 
    property1: Boolean;
    {...} 
end;
Das sollte

1. Kein record sein sondern eine Klasse und
2. Das Array sollte dann eine SubCollection sein
und dann sollte das gehen ;)

(TCollection ist Quasi ein Array of TCollectionItem - da muss man dann aber auch mit Klassen arbeiten ;))

TheAn00bis 11. Apr 2006 19:24

Re: Speichern verschiedener Objekte in einer Datei
 
Zitat:

Zitat von jim_raynor
Zitat:

Zitat von TheAn00bis
Ist es auch möglich, ein Record zu nehmen, in welchem Arrays vom Typen der verschiedenen Objekte sind?

Nein, da der Record in einem file of keine Strings und dynamische Arrays enthalten darf. Mach ne XML-Datei oder dpCollections. Klingt für den Anfang kompliziert ist aber wesentlich flexibler.


Dann mach ich ein Array mit einer Länge von 500 und arbeite das soweit ab, bis der Inhalt leer ist! =P
Das gleiche mit den Strings. ;)

Spaß beiseite, ich versuch mal mit den Collections zurecht zu kommen.

TheAn00bis 13. Apr 2006 10:17

Re: Speichern verschiedener Objekte in einer Datei
 
Hey, die Verwendung der Collections ist weit aus unkomplizierter, als ich erwartet habe!
Vielen Dank für die Antworten und vor allem Danke an Alcaeus für das Tutorial! :)

TheAn00bis 14. Apr 2006 12:55

Re: Speichern verschiedener Objekte in einer Datei
 
Müssen alle Objekte, die in einer Collection abgespeichert werden von TPersistent abgeleitet sein?

Ich hab jetzt eine Collection mit Namen "Coll", diese enthält wiederum die Subcollection TBrickCollItem, welche die beiden SubSubcollections "TRealCollItem" und "TTargaCollItem" enthält, diese verwende ich anstelle eines "Array of Real" und anstelle eines "Array of TTargaGraphic".
Die Subcollection "TRealCollItem" hat das Attribut "RealValue: Real" und "TTargaCollItem" hat "Targa: TTargaGraphic" als Attribut.
Beim Speichern der Collection gibt es keinerlei Probleme, aber beim Laden macht die "TTargaCollItem" Probleme.
Es treten eine Reihe von Exceptions auf (beim Aufruf von Coll.LoadFromFile(filename)): 1. "Ungültiger Pfad für Eigenschaft", 2. "Fehler beim Lesen von TTargaCollItem.Targa.Data: Ungültiger Pfad für Eigenschaft" 3. "Fehler beim Lesen von TBrickCollItem.TargaCollItems: Fehler beim Lesen von TTargaCollItem.Targa.Data: Ungültiger Pfad für Eigenschaft".

Mach ich da irgendetwas falsch, beim Speichern oder beim Laden - oder kann man das nicht sagen oder kann ich generell kein TTargaGraphic (was übrigens aus GraphicEx stammt) in einer Collection speichern?

TheAn00bis 15. Apr 2006 13:10

Re: Speichern verschiedener Objekte in einer Datei
 
*push*

TheAn00bis 17. Apr 2006 17:19

Re: Speichern verschiedener Objekte in einer Datei
 
Okay, ich poste mal die gesamte Unit, die für das Speichern der Objekte verantwortlich ist. Der restliche Code befindet sich in anderen Units, dieser ist hier aber nicht relevant.

Ist ganz schön lang, ich wäre aber sehr dankbar, wenn ihr mal drüber schauen könntet, da ich wirklich ein wenig auf dem Schlauch stehe.

Es geht darum, eine Objektlist ("BrickPrototypes"), die mit Objekten vom Typen "TBrickPrototype" gefüllt ist zu speichern und zu laden. Um den Vorgang des Speicherns und Ladens vom restlichen Programm strickt zu trennen, speichere ich die Klasse "TBrickPrototype" nicht direkt, sondern gehe den Umweg über die Klasse "TBrickCollItem", die von TPersistent abgeleitet ist.
Außer den beiden Arrays habe ich alle restlichen Parameter weggelassen, da diese problemlos funktionieren.

Die Klasse "TFileControler" ist die Klasse, die meine Objektlist "BrickPrototypes" als Collection speichert und aus der Datei wiederherstellt.

Mein Problem findet ihr zwei Posts weiter oben. Aber ich wiederhole meine Frage nochmal: Hab ich da irgendwas falsch verstanden und kann das folglich so gar nicht funktionieren, oder ist da nur irgendwo ein kleiner Fehler drin?

Wäre auch für sonstige Verbesserungsvorschläge dankbar.



Delphi-Quellcode:
type

  //Objektlist mit Objekten dieses Typs soll gespeichert werden!!
  TBrickPrototype = class(TObject) {aus anderer Unit}
    private
    public
      textures: array of TTargaGraphic;
      animationVelocities: array of Real;
  end;

//Subcollections:

  TRealCollItem = class(TCollectionItem)
    private
      fRealValue: Real;
    public
      procedure Assign(Source: TPersistent); override;
    published
      property RealValue: Real read fRealValue write fRealValue;
  end;

  TTargaCollItem = class(TCollectionItem)
    private
      fTarga: TTargaGraphic;
    public
      procedure Assign(Source: TPersistent); override;
    published
      property Targa: TTargaGraphic read fTarga write fTarga;
  end;

//Maincollection:

  TBrickCollItem = class(TCollectionItem)
    private
      fTargaCollItems: TJSCollection;
      fRealCollItems: TJSCollection;
    public
      constructor Create(Collection: TCollection); override;
      destructor Destroy; override;
      procedure Assign(Source: TPersistent); override;
    published
      property TargaCollItems: TJSCollection read fTargaCollItems write fTargaCollItems;
      property RealCollItems: TJSCollection read fRealCollItems write fRealCollItems;
  end;

//Administration:

TFileControler = class(TOBject)
  private
  public
    procedure LoadBricks; //Bricks from File -> global TObjectList
    procedure SaveBricks;
end;


implementation

uses UBrickEditor_Main;

               { TRealCollItem }

procedure TRealCollItem.Assign(Source: TPersistent);
begin
  inherited;
  if Source is TRealCollItem then
    fRealValue := TRealCollItem(Source).RealValue
  else
    inherited Assign(Source);
end;

               { TTargaCollItem }

procedure TTargaCollItem.Assign(Source: TPersistent);
begin
  inherited;
  if Source is TRealCollItem then
    fTarga := TTargaCollItem(Source).Targa
  else
    inherited Assign(Source);
end;

               { TBrickCollItem }

constructor TBrickCollItem.Create(Collection: TCollection);
begin
  inherited Create(Collection);
  fTargaCollItems := TJsCollection.Create(TTargaCollItem);
  fRealCollItems := TJsCollection.Create(TRealCollItem);
end;

destructor TBrickCollItem.Destroy;
begin
  fTargaCollItems.free;
  fRealCollItems.free;
  inherited Destroy;
end;

procedure TBrickCollItem.Assign(Source: TPersistent);
begin
  inherited;
  if Source is TBrickCollItem then
    begin
      fTargaCollItems.Assign(TBrickCollItem(Source).fTargaCollItems);
      fRealCollItems.Assign(TBrickCollItem(Source).fRealCollItems);
    end
  else
    inherited Assign(Source);
end;

               { TFileControler }

procedure TFileControler.LoadBricks;
var Coll: TmxJSCollection;
    tempBrickPrototype: TBrickPrototype;
    i, j: integer;
begin
  Coll := TmxJSCollection.Create(TBrickCollItem);
  Coll.LoadFromFile(filename);
  BrickPrototypes.Clear;
  for i:=0 to Coll.Count-1 do
    begin
      for j:=0 to TBrickCollItem(Coll.Items[i]).TargaCollItems.Count-1 do
        begin
          setlength(tempBrickPrototype.textures, length(tempBrickPrototype.textures)+1);
          tempBrickPrototype.textures[high(tempBrickPrototype.textures)] := TTargaCollItem(TBrickCollItem(Coll.Items[i]).TargaCollItems).Targa;
        end; {}
      for j:=0 to TBrickCollItem(Coll.Items[i]).RealCollItems.Count-1 do
        begin
          setlength(tempBrickPrototype.animationVelocities, length(tempBrickPrototype.animationVelocities)+1);
          tempBrickPrototype.animationVelocities[high(tempBrickPrototype.animationVelocities)] := TRealCollItem(TBrickCollItem(Coll.Items[i]).RealCollItems).RealValue;
        end;
      BrickPrototypes.Add(tempBrickPrototype);
    end; {for i...}
  Coll.free;
end;

procedure TFileControler.SaveBricks;
var Coll: TmxJSCollection;
    i,j : integer;
begin
  coll := TmxJSCollection.Create(TBrickCollItem);
  for i:=0 to BrickPrototypes.Count-1 do
    begin
      with Coll.add as TBrickCollItem do
        begin
          for j:=0 to high(TBrickPrototype(BrickPrototypes[i]).textures) do
            with TargaCollItems.add as TTargaCollItem do
                Targa := TBrickPrototype(BrickPrototypes[i]).textures[j];
          for j:=0 to high(TBrickPrototype(BrickPrototypes[i]).animationVelocities) do
            with RealCollItems.add as TRealCollItem do
                RealValue := TBrickPrototype(BrickPrototypes[i]).animationVelocities[j];
        end; {with Coll.add...}
    end; {for i...}
  Coll.SaveToFile(filename);
  Coll.free;
end;

end.


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:45 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz