Autor Beitrag
speck12
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 36



BeitragVerfasst: 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 :
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:
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
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Init;
 begin

  breite_creep := StrToInt(Edit1.Text);  {Max : 38}
  hoehe_creep  := StrToInt(Edit2.Text);  {Max : 38}
  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 < 100and (TCreep(creep_liste.Items[i]).x_Creep > 60then {Zone 1}
        begin
         If TCreep(creep_liste.Items[i]).y_Creep > 90-(hoehe_creep div 2then
          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; {Bedingung für Zonenwechsel}
        end;

      if (TCreep(creep_liste.Items[i]).x_Creep < 380and (TCreep(creep_liste.Items[i]).x_Creep >= 100and (TCreep(creep_liste.Items[i]).y_Creep < 280-(hoehe_creep div 2)) then {Zone 2}
        begin
         If TCreep(creep_liste.Items[i]).x_Creep < 380-(breite_creep div 2then
          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 <= 300and (TCreep(creep_liste.Items[i]).y_Creep >= 280-(hoehe_creep div 2)) then {Zone 3}
        begin
         If TCreep(creep_liste.Items[i]).x_Creep >= 380-(hoehe_creep div 2then
          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                         {Hier soll gelöscht werden}
    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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19313
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 36



BeitragVerfasst: 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:

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:
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
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Init;
 begin

  breite_creep := StrToInt(Edit1.Text);  {Max : 38}
  hoehe_creep  := StrToInt(Edit2.Text);  {Max : 38}
  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 < 100and (TCreep(creep_liste.Items[i]).x_Creep > 60then {Zone 1}
        begin
         If TCreep(creep_liste.Items[i]).y_Creep > 90-(hoehe_creep div 2then
          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; {Bedingung für Zonenwechsel}
        end;

      if (TCreep(creep_liste.Items[i]).x_Creep < 380and (TCreep(creep_liste.Items[i]).x_Creep >= 100and (TCreep(creep_liste.Items[i]).y_Creep < 280-(hoehe_creep div 2)) then {Zone 2}
        begin
         If TCreep(creep_liste.Items[i]).x_Creep < 380-(breite_creep div 2then
          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 <= 300and (TCreep(creep_liste.Items[i]).y_Creep >= 280-(hoehe_creep div 2)) then {Zone 3}
        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) = 0and (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;  {falls der Cursor das Objekt "berührt", soll dieses gelöscht werden}
       creep_liste.Items[c] := nil;        {Hier tritt die Zugriffsverletzung auf}
      end;
    end;

  end;

end.


Mfg
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19313
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: 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.