Array Zeile löschen
Hallo,
mit eurer Hilfe habe ich inzwischen einiges an meinem Projekt geschafft. Ich brauchte mich eine Weile nicht melden,kam ich gut vorwärts . Nun gibt es aber einen Fehler in meinem Programm, der mir schon seit Anfang an zu schaffen macht, den ich aber immer vor mir hergeschoben hab. Folgendes Problem: In meinem Spiel werden die Positionen und Eigenschaften von z.B. Gegnern in Arrays (of Record) gespeichert. Wenn nun einer von ihnen stirbt (Dat[X].Alive=False) soll die Zeile gelöscht werden und alle anderen um Platz zu sparen "eins aufrücken". Grundsätzlich funktioniert das auch, aber wenn mehrere Gegner gleichzeitig ins Jenseits befördert werden entstehen Fehler. Hier meine bisherige Technik:
Delphi-Quellcode:
In einigen Tutorials hab ich "Swap Values" kennengelernt, damit könnte man das ganze sicher etwas vereinfachen; ich konnte aber nichts dazu finden, was hieran falsch sein könnte. Hat jemand vielleicht eine Idee ?
X:=0;
For I:=1 To Gegneranzahl+X DO Begin if not Gegner[I-X].alive then Begin if ((I-X)<>Gegneranzahl) THEN Begin Gegner[I-X].Wert:=Gegner[Gegneranzahl].Wert; Gegner[I-X].Funktion:=Gegner[Gegneranzahl].Funktion; Gegner[I-X].PosX:=Gegner[Gegneranzahl].PosX; Gegner[I-X].PosY:=Gegner[Gegneranzahl].PosY; Gegner[I-X].breite:=Gegner[Gegneranzahl].breite; Gegner[I-X].hoehe:=Gegner[Gegneranzahl].hoehe; Gegner[I-X].Farbe:=Gegner[Gegneranzahl].Farbe; Gegner[I-X].Maxzeit:=Gegner[Gegneranzahl].Maxzeit; Gegner[I-X].Alter:=Gegner[Gegneranzahl].Alter; [...............] End; X:=X+1; Gegneranzahl:=Gegneranzahl-1; End; End; Alternativ: Könnte ich nicht theoretisch auch einfach den letzten mit demjenigen, der gelöscht werden soll Tauschen (es sei den selbiger ist der letzte) und dann den letzten löschen? Danke schoneinmal! |
AW: Array Zeile löschen
Ist das ein statisches array?
|
AW: Array Zeile löschen
Das und die Sortierung dürfte der Grund sein warum meist Listen bevorzugt werden.
Du könntest mehrfach 1 löschen oder umkopieren in ein initial leeres Array, wenn die Reihenfolge egal ist kannst Du auch wie von Dir bereits vorgeschlagen eine Lückenliste erstellen,auffüllen,löschen |
AW: Array Zeile löschen
@VkPenguin
Nur mal so, du kannst das auch so in einem Rutsch übergeben:
Delphi-Quellcode:
Macht alles etwas übersichtlicher.
Gegner[I-X] := Gegner[Gegneranzahl];
Und hier: http://www.delphipraxis.net/166529-f...heinander.html Da ging es um Objekte, aber auch da wird Array von unnötigen Datensätzen befreit. |
AW: Array Zeile löschen
Hallo, danke für eure Hilfe..
@ Bjoerk: Ja, ist es, bisher zumindest, später werde ich das aus Performancegründen vielleicht ändern. @ Popov: Ah, das macht das ganze zumindest schon mal einfacher, Dankeschön für den Tipp. @ Bummi: Da hast du wahrscheinlich recht. Ist es denn schwierig mein Programm auf die Verwendung von Listen umzubauen? Kennt jemand zufällig ein gutes Tutorial, wie man Listen verwendet? Ansonsten werde ich mich mal umschauen.. |
AW: Array Zeile löschen
Zitat:
Hier ein einfaches Beispiel:
Delphi-Quellcode:
unit Unit1;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type PGegnerRecord = ^TGegnerRecord; TGegnerRecord = record Name:AnsiString; PosX:Integer; PosY:Integer; {...} end; TForm1 = class(TForm) Button1: TButton; Button2: TButton; procedure Button2Click(Sender: TObject); procedure Button1Click(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure FormCreate(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; var Form1: TForm1; Gegnerliste:TList; implementation {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); begin Gegnerliste:=TList.Create; end; procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); Var i:Integer; Begin For i:=Gegnerliste.Count-1 downto 0 do //Löschen von Einträgen Dispose(PGegnerRecord(Gegnerliste.Items[i])); //Speicher wieder freigeben! Gegnerliste.Free; end; procedure TForm1.Button1Click(Sender: TObject); Var GegnerRec:PGegnerRecord; index:Integer; begin New(GegnerRec); //Speicher reservieren Gegnerliste.Add(GegnerRec); index:=Gegnerliste.Count; GegnerRec.Name:='Gegner'+IntToStr(index); GegnerRec.PosX:=index; GegnerRec.PosY:=30; end; procedure TForm1.Button2Click(Sender: TObject); Var i:Integer; begin For i:=0 to Gegnerliste.Count-1 do ShowMessage(TGegnerRecord(Gegnerliste[i]^).Name); end; |
AW: Array Zeile löschen
Zitat:
Aber Komfortabler auf jedenfall. Nja, es wäre ja zu praktisch, wenn die Fragesteller ihre Delphi-Version mal verrraten würden. :wall: Ab Delphi 2009 könnte man z.B. den Generics und einer generischen TList den Komfort nochmal wesentlich erhöhen. Und was die Speicherlecks angeht: Eine TObjectList, bzw. einer generischen TObjektList und mit OwnsObjects=True, würde man nochmal etweas mehr Sicherheit und Kompfort rausholen. |
AW: Array Zeile löschen
Zitat:
|
AW: Array Zeile löschen
Zum ursprünglichen Problem:
Delphi-Quellcode:
Die Umstellung von Records und Arrays auf Objekte und Objektlisten scheint hier sinnvoll. Der Aufwand dürfte sich in Grenzen halten.
for i := Gegneranzahl downto 1 do
begin if not Gegner[i].alive then Begin if i < Gegneranzahl then Gegner[I] := Gegner[Gegneranzahl]; Dec(Gegneranzahl); end; end; Die Alternative mit TList und Pointern zu arbeiten, erfordert mindestens den selben Aufwand und ist nicht so komfortabel. |
AW: Array Zeile löschen
Zitat:
Die generische TList ist leider nur für die haltung von statischen Records, deren Daten man nicht ändert, bzw. die man nur im ganzen ändert. Das Ändern einzelner Werte eines Records ist nicht (sehr unpraktsich) änderbar. Und da sich hier ja bestimmte mindestens Werte wie PosX und PosY ändern werden... Ich hatte mir damit beholfen, daß ich die TList<> erweiterte und ein Items einführte, welches den Pointer auf den Record und nicht eine Kopie Records zurückliefert. |
AW: Array Zeile löschen
Da Ganze ist ein Dilemma. Mit Array zu arbeiten ist für Anfänger einfacher, da man die Vorgänge logisch nachvollziehen kann. Oft wollte man am Anfang auch nur eine Kleinigkeit und plötzlich hat meine ein mächtiges Array-Record an der Backe. Die Verwaltung ist aber dann etwas komplexer. Eine Klasse ist von der Arbeit am Anfang ähnlich, bringt später unheimlich Vorteile, für einen Anfänger evtl. noch schwer nachvollziehbar.
|
AW: Array Zeile löschen
Zitat:
|
AW: Array Zeile löschen
Zitat:
Delphi-Quellcode:
Die Klasse muss man auch wieder sauber freigeben. Habe mal im Netz ein Beispiel (als Empfehlung) gefunden, mit einem wunderschönen Speicherleck. Leider weiss ich nicht mehr wo.
begin
... TGegnerRecord(Gegnerliste[i]^).Name:='Neuer Gegner'; TGegnerRecord(Gegnerliste[i]^).PosX:=10; ... end; |
AW: Array Zeile löschen
Hallo,
habe leider bisher keine Zeit gefunden, alle Beiträge zu lesen und zu überdenken; nur kurz als Antwort: Meine Version ist Delphi 2009, entschuldigt, wusste nicht, dass das wichtig ist |
AW: Array Zeile löschen
Hast du schonmal mit den Generics gearbeitet?
GegnerListe[0] liefert dort den Record, genauer eine Kopie des Records und keinen Zeiger.
Delphi-Quellcode:
Vorteil ist zwar, daß hier delphi die komplette Speicherverwaltung übernimmt, innerhalb der Liste und auch für die Einzelrecords.
type
TGegnerRecord = record Name:AnsiString; PosX:Integer; PosY:Integer; {...} end; var Gegner: TGegnerRecord; GegnerListe: TList<TGegnerRecord>; GegnerListe := TList<TGegnerRecord>.Create; Gegner.Name := 'ich'; Gegner.PosX := 123; ... GegnerListe.Add(Gegner); Label1.Caption := GegnerListe[0].Name: GegnerListe[0].PosX := 456; // geht nicht, auch wenn der Compiler, in älteren Delphi-Versionen, keine Warnung/Fehlermeldung anzeigt GegnerListe.Free; |
AW: Array Zeile löschen
das Ändern ist aber nicht wirklich problematisch
Delphi-Quellcode:
benötigt generics.collections in den uses.
var
i: Integer; begin GegnerListe := TList<TGegnerRecord>.Create; for i := 1 to 100 do begin Gegner.Name := 'ich' + IntToStr(i); Gegner.PosX := i; GegnerListe.Add(Gegner); end; Gegner := GegnerListe[10]; Gegner.PosX := 999; Gegner.Name := 'geändert'; GegnerListe[10] := Gegner; Showmessage(GegnerListe[10].Name + '-' + IntToStr(GegnerListe[10].PosX)); GegnerListe.Free; end; |
AW: Array Zeile löschen
Jupp, wenn man den Record vorher rausnimmt/rauskopiert und dann quasi "komplett" ersetzt.
Nur eben Einzeiler, zum Ändern eines klitzekleinen Wertes, sind standardmäßig nicht möglich. |
AW: Array Zeile löschen
Bei Generics muss ich leider aus Kompatibilitätsgründen passen.
Bei der von mir vorgeschlagenen Variante kann man jedoch, wie schon oben geschrieben, einzelne Werte ohne Probleme direkt ändern:
Delphi-Quellcode:
Oder spricht etwas dagegen?
procedure TForm1.Button3Click(Sender: TObject);
begin TGegnerRecord(Gegnerliste[0]^).Name:='Neuer Gegner'; TGegnerRecord(GegnerListe[0]^).PosX:=100; end; |
AW: Array Zeile löschen
Nein, das geht bei der generischen TList<T> nicht, welche direkt die Records enthält.
Wenn man eine TList mit Zeigern auf "Gegner"-Records oder mit einem Gegner-Objekten befüllt hat, dann geht es, so wie du sagst. Nur daß man andersrum wohl noch besser erkennt, warum es dort geht.
Delphi-Quellcode:
Nur muß man hier eben überall selber noch das New und Dispose aufrufen.
procedure TForm1.Button3Click(Sender: TObject);
begin PGegnerRecord(Gegnerliste[0])^.Name:='Neuer Gegner'; PGegnerRecord(GegnerListe[0])^.PosX:=100; end; |
AW: Array Zeile löschen
Oder man macht Klassen draus und... hatten wir das nicht schon? :mrgreen:
|
AW: Array Zeile löschen
Zitat:
Ich glaube, im Endeffekt hat jede mögliche/hier genannte Lösung ihre Vor- und Nachteile. Jetzt muss man sich nur noch das rauspicken, was einem am meisten zusagt ;-) Lg |
AW: Array Zeile löschen
... erst einmal vielen lieben Dank für eure Hilfe und Freundlichkeit - zuerst hab ich zwar nicht ganz verstanden, wovon ihr eigentlich redet, ich konnte mich aber dann gut anhand der Codebeispiele einfinden, danke noch einmal für die Mühe an dieser Stelle. Ich mach mich dann mal an den Umbau :) Melde mich, wenn es größere Probleme gibt oder wenn es geklappt hat.
*Edit* Funktioniert soweit wie ich gekommen bin gut; eine Frage hätte ich aber - wenn ich zwei Einheiten der Liste vergleichen will, also zwei gleichzeitig brauche, muss ich dann auch zwei temporäre "Gegner"-Variablen haben? *Edit2* Hm, bekomme folgende Fehlermeldung: --------------------------- Anwendungsfehler --------------------------- Exception EArgumentOutOfRangeException in Modul SpaceInvaders042.exe bei 000B6205. Argument out of range. --------------------------- OK --------------------------- Ich denke mal, dass bedeutet, dass die Liste nur sagen wir mal drei Einträge hat und ich nach dem vierten Frage..? Wir die Liste mit dem ".add"-Befehl nicht automatisch um eins erweitert? Das hatte ich so verstanden.. *Edit3* wenn ich es so "For I:=1 To Schussanzahl-1 Do" mache, geht es scheinbar. Fängt die Liste also schon bei 0 an zu zählen? Aber warum funktioniert dann der erste Schuss nicht? *Edit4*...erst Denken.. mit
Delphi-Quellcode:
geht es wunderbar. Werde mich am Wochenende weiter damit beschäftigen und (voraussichtlich) Rückmeldung geben. Danke nocheinmal!
For I:=0 To [...]
|
AW: Array Zeile löschen
Das Freigeben macht eine TObjectList von selber, wenn man es ihr sagt.
Delphi-Quellcode:
Nunja, eine kleine Erweiterung und schon läßt sich auch mit einer TObjectList<T> angenehm arbeiten.
type
TSimpleObjectList<T: class> = class(TList<T>) protected procedure Notify(const Value: T; Action: TCollectionNotification); override; public function Add: T; overload; function Insert(Index: Integer): T; overload; end; function TSimpleObjectList<T>.Add: T; begin Result := T.Create; inherited Add(Result); end; function TSimpleObjectList<T>.Insert(Index: Integer): T; begin if (Index < 0) or (Index > Count) then Items[Index]; Result := T.Create; inherited Insert(Index, Result); end; procedure TSimpleObjectList<T>.Notify(const Value: T; Action: TCollectionNotification); begin try inherited; finally if Action = cnRemoved then Value.Free; end; end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:50 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