Autor |
Beitrag |
speck12
      
Beiträge: 36
|
Verfasst: Sa 01.09.07 04:11
Hallo allerseits!
Ich bin dabei, ein kleines Spiel für zwischendurch zu schreiben. Es soll ein Tower Defense werden (Inspiriert ein bisschen vom Warcraft 3 Klon ^^).
Nach dem ich eine nicht all zu anspruchsvolle Welt per Canvas erstellt habe und die "Monster" in Form von Rechtecken(Bitmaps) auch die Straße entlang laufen, habe ich das Problem, dass nach einer Zeit der Arbeitsspeicher überläuft - verständlich, da immer neue Monster "createn". Diese werden in eine Liste aufgenommen. Nun weiß ich aber nicht, wie ich explizit die Monster, die das Spielfeld verlassen haben aus der Liste löschen soll. Ich habe es bereits mit drei Möglichkeiten probiert:
1. Per "Destroy" der Monsterklasse
2. Liste "free"
3. Monster "free"
jedoch immer ohne Erfolg, denn sobald das erste Monster das Spielfeld passiert hat, kommt immer ein Error "EAccessViolation".
Hier der Qelltext der MainUnit :
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: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141:
| unit Main;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, Creep_Unit, Hintergrund_unit;
type TForm1 = class(TForm) Bild: TImage; Button1: TButton; Timer1: TTimer; Edit1: TEdit; Edit2: TEdit; Edit3: TEdit; Label1: TLabel; Label2: TLabel; Label3: TLabel; Edit4: TEdit; Label4: TLabel; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); procedure Timer1Timer(Sender: TObject); private hintergrund : THintergrund; buffer : TBitmap; creep_liste : TList ; x_creep : Integer; y_creep : Integer; v_creep : Integer; breite_Creep: Integer; hoehe_Creep : Integer; procedure Init; procedure Bild_Aktualisieren; public end;
var Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Init; begin
breite_creep := StrToInt(Edit1.Text); hoehe_creep := StrToInt(Edit2.Text); v_creep := StrToInt(Edit3.Text); x_creep := 80-(breite_creep div 2) ; y_creep := 500;
end;
procedure TForm1.Bild_Aktualisieren; begin buffer.Canvas.Draw(0,0,hintergrund); Bild.Canvas.Draw(0,0,buffer) ; hintergrund.Refresh ; end;
procedure TForm1.FormCreate(Sender: TObject); begin hintergrund := THintergrund.create(Bild.Width,Bild.Height,clGreen,clGray);
buffer := TBitmap.Create; with buffer do begin Height := Bild.Height; Width := Bild.Width ; end;
creep_liste := TList.Create;
Form1.DoubleBuffered := true; Init; Bild_Aktualisieren; end;
procedure TForm1.Button1Click(Sender: TObject); var n : integer; begin Init; for n := 0 to StrToInt(Edit4.Text)-1 do begin y_creep := 500 + n*(hoehe_creep+20); creep_liste.Add(TCreep.Create(breite_creep,hoehe_creep,x_creep,y_creep,v_creep,clNavy)); end; Timer1.Enabled := True; end;
procedure TForm1.Timer1Timer(Sender: TObject); var i,n : integer;
begin
for i :=0 to creep_liste.Count - 1 do begin if (TCreep(creep_liste.Items[i]).x_Creep < 100) and (TCreep(creep_liste.Items[i]).x_Creep > 60) then begin If TCreep(creep_liste.Items[i]).y_Creep > 90-(hoehe_creep div 2) then TCreep(creep_liste.Items[i]).y_Creep := TCreep(creep_liste.Items[i]).y_Creep - TCreep(creep_liste.Items[i]).delta_weg else TCreep(creep_liste.Items[i]).x_Creep := TCreep(creep_liste.Items[i]).x_Creep + TCreep(creep_liste.Items[i]).delta_weg; end;
if (TCreep(creep_liste.Items[i]).x_Creep < 380) and (TCreep(creep_liste.Items[i]).x_Creep >= 100) and (TCreep(creep_liste.Items[i]).y_Creep < 280-(hoehe_creep div 2)) then begin If TCreep(creep_liste.Items[i]).x_Creep < 380-(breite_creep div 2) then TCreep(creep_liste.Items[i]).x_Creep := TCreep(creep_liste.Items[i]).x_Creep + TCreep(creep_liste.Items[i]).delta_weg else TCreep(creep_liste.Items[i]).y_Creep := TCreep(creep_liste.Items[i]).y_Creep + TCreep(creep_liste.Items[i]).delta_weg; end;
if (TCreep(creep_liste.Items[i]).y_Creep <= 300) and (TCreep(creep_liste.Items[i]).y_Creep >= 280-(hoehe_creep div 2)) then begin If TCreep(creep_liste.Items[i]).x_Creep >= 380-(hoehe_creep div 2) then TCreep(creep_liste.Items[i]).x_Creep := TCreep(creep_liste.Items[i]).x_Creep + TCreep(creep_liste.Items[i]).delta_weg; end;
hintergrund.Canvas.Draw(TCreep(creep_liste.Items[i]).x_Creep,TCreep(creep_liste.Items[i]).y_Creep,TCreep(creep_liste.Items[i]));
end;
Bild_Aktualisieren;
for n := creep_liste.Count - 1 downto 0 do begin if TCreep(creep_liste.Items[n]).x_Creep >= Bild.Width+50 then TCreep(creep_liste.Items[n]).Destroy; end;
end;
end. |
hoffe ihr könnt mir helfen
mfg
|
|
jaenicke
      
Beiträge: 19313
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Sa 01.09.07 22:11
Tja, die Zugriffsverletzung ist einfach erklärt: Du zerstörst Objekte in der Liste, entfernst die aber nicht daraus. Dadurch wird dann natürlich später versucht, auf die Eigenschaften des bereits zerstörten Objekts zuzugreifen und das kann nicht gehen... 1. Musst du nach dem Zerstören eines Objekts dieses auch wieder mit Delete aus der Liste löschen, genauso wie du es vorher in zeile 93 mit Add hinzugefügt hattest. 2. Solltest du sicherstellen, dass nicht zwei Timer-Events gleichzeitig auftreten. Da die asynchron mit dem Programm laufen, kann das durchaus passieren. Und wenn du dann ein Objekt in einem Timer-Event zerstörst, während in einem anderen darauf zugegriffen wird, dann gibts wieder einen Fehler.
|
|
speck12 
      
Beiträge: 36
|
Verfasst: So 02.09.07 13:43
Hi,
also das Problem habe ich jetzt folgenderweise beseitigt:
Während der for-Schleife wird immer kontrolliert, ob sich das Objekt noch auf dem Spielfeld befindet. Sollte dies für alle Objekte der Fall sein, wird der Timer disabled und mit Nil und Pack die Liste "frisch gemacht". Wenn der timer aus ist, funktioniert das auch alles gut, nur habe ich jetzt ein neues Problem:
In einem OnMouseMove Event des Images wird kontrolliert, ob der Cursor auf ein Objekt zeigt, oder nicht - das klappt alles wunderbar. Nur möchte ich probehalber für spätere Zwecke, dass das selektierte Objekt gelöscht wird. Allerdings tritt hier immer eine Zugriffsverletzung auf, da im Timer Event auf alle objekte der liste zugegriffen wird. Wie kann ich es nun bewerkstelligen, dass weiterhin auf alle Objekte zugegriffen wird, ausser auf das gelöschte ?
Würde mich über Hilfe freuen.
Hier der 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: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192:
| unit Main;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, Creep_Unit, Hintergrund_unit;
type TForm1 = class(TForm) Bild: TImage; Button1: TButton; Timer1: TTimer; Edit1: TEdit; Edit2: TEdit; Edit3: TEdit; Label1: TLabel; Label2: TLabel; Label3: TLabel; Edit4: TEdit; Label4: TLabel; Edit5: TEdit; ColorBox1: TColorBox; Panel1: TPanel; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); procedure Timer1Timer(Sender: TObject); procedure BildMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
private hintergrund : THintergrund; buffer : TBitmap; creep_liste : TList ; x_creep : Integer; y_creep : Integer; v_creep : Integer; breite_Creep: Integer; hoehe_Creep : Integer; creep_anzahl: Integer; creep_farbe : TColor ; procedure Init; procedure Bild_Aktualisieren; public end;
var Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Init; begin
breite_creep := StrToInt(Edit1.Text); hoehe_creep := StrToInt(Edit2.Text); v_creep := StrToInt(Edit3.Text); x_creep := 80-(breite_creep div 2) ; y_creep := 500; creep_farbe := ColorBox1.Selected;
end;
procedure TForm1.Bild_Aktualisieren; begin buffer.Canvas.Draw(0,0,hintergrund); Bild.Canvas.Draw(0,0,buffer) ; hintergrund.Refresh ; end;
procedure TForm1.FormCreate(Sender: TObject); begin hintergrund := THintergrund.create(Bild.Width,Bild.Height,clGreen,clGray);
buffer := TBitmap.Create; with buffer do begin Height := Bild.Height; Width := Bild.Width ; end;
creep_liste := TList.Create;
Form1.DoubleBuffered := true; Init; Bild_Aktualisieren; end;
procedure TForm1.Button1Click(Sender: TObject); var n : integer; begin Init; for n := 0 to StrToInt(Edit4.Text)-1 do begin y_creep := 500 + n*(hoehe_creep+20); creep_liste.Add(TCreep.Create(breite_creep,hoehe_creep,x_creep,y_creep,v_creep,100,creep_farbe)); end; creep_anzahl := creep_liste.Count; Edit5.Text := IntToStr(creep_anzahl); Timer1.Enabled := True; end;
procedure TForm1.Timer1Timer(Sender: TObject); var i,n,m,o : integer;
begin
for i :=0 to creep_liste.Count - 1 do begin m := 0; if (TCreep(creep_liste.Items[i]).x_Creep < 100) and (TCreep(creep_liste.Items[i]).x_Creep > 60) then begin If TCreep(creep_liste.Items[i]).y_Creep > 90-(hoehe_creep div 2) then TCreep(creep_liste.Items[i]).y_Creep := TCreep(creep_liste.Items[i]).y_Creep - TCreep(creep_liste.Items[i]).delta_weg else TCreep(creep_liste.Items[i]).x_Creep := TCreep(creep_liste.Items[i]).x_Creep + TCreep(creep_liste.Items[i]).delta_weg; end;
if (TCreep(creep_liste.Items[i]).x_Creep < 380) and (TCreep(creep_liste.Items[i]).x_Creep >= 100) and (TCreep(creep_liste.Items[i]).y_Creep < 280-(hoehe_creep div 2)) then begin If TCreep(creep_liste.Items[i]).x_Creep < 380-(breite_creep div 2) then TCreep(creep_liste.Items[i]).x_Creep := TCreep(creep_liste.Items[i]).x_Creep + TCreep(creep_liste.Items[i]).delta_weg else TCreep(creep_liste.Items[i]).y_Creep := TCreep(creep_liste.Items[i]).y_Creep + TCreep(creep_liste.Items[i]).delta_weg; end;
if (TCreep(creep_liste.Items[i]).y_Creep <= 300) and (TCreep(creep_liste.Items[i]).y_Creep >= 280-(hoehe_creep div 2)) then begin If (TCreep(creep_liste.Items[i]).x_Creep >= 380-(hoehe_creep div 2)) and (TCreep(creep_liste.Items[i]).x_Creep <= Bild.Width) then TCreep(creep_liste.Items[i]).x_Creep := TCreep(creep_liste.Items[i]).x_Creep + TCreep(creep_liste.Items[i]).delta_weg; end;
hintergrund.Canvas.Draw(TCreep(creep_liste.Items[i]).x_Creep,TCreep(creep_liste.Items[i]).y_Creep,TCreep(creep_liste.Items[i]));
if (TCreep(creep_liste.Items[i]).Noch_Im_Spielfeld(TCreep(creep_liste.Items[i]).x_Creep) = 0) and (TCreep(creep_liste.Items[i]).nicht_zaehlen = false) then begin Dec(creep_anzahl); TCreep(creep_liste.Items[i]).nicht_zaehlen := true; end; Edit5.Text := IntToStr(creep_anzahl);
for n := 0 to creep_liste.Count - 1 do begin if TCreep(creep_liste.Items[n]).Noch_Im_Spielfeld(TCreep(creep_liste.Items[n]).x_Creep) = 0 then Inc(m); if m >= creep_liste.Count then begin for o := 0 to creep_liste.Count - 1 do begin creep_liste.Items[o] := nil; end; Timer1.Enabled := false;
end; end; end;
Bild_Aktualisieren; creep_liste.Pack;
end;
procedure TForm1.BildMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); var c : integer ; Maus : TPoint; begin Maus.X := X; Maus.Y := Y;
for c := 0 to creep_liste.Count - 1 do begin If TCreep(creep_liste.Items[c]).selected(Maus) then begin TCreep(creep_liste.Items[c]).Free; creep_liste.Items[c] := nil; end; end;
end;
end. |
Mfg
|
|
jaenicke
      
Beiträge: 19313
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: So 02.09.07 14:13
Wie wärs, wenn du creep_liste.Items[c] auf nil prüfst bevor du auf dessen Eigenschaften zugreifst?  if Assigned(creep_liste.Items[c]) ginge auch, macht aber auch nix anderes.
|
|
|