![]() |
Bugs und Zugriffsverletzungen in meinem Spiel (Aspirin)
Hey Leute,
vielleicht kennt einer von euch das Spiel Aspirin. Man muss den Spieler durch die sich bewegenden Gegner zum Ziel bringen. Ich habe noch Items hinzugefügt und man verliert erst wenn die 5 Herzen (5,4,3,2 oder 1 je nach Schwierigkeitsgrad). Mein Probleme sind: - Manchmal erscheind oben-links in der Form einfach ein weißer Shape (vermutl. Item) - Ab einer bestimmten Anzahl an Gegnern (TGegner=Abgeleitet von TShape) bekomme ich eine Zugriffsverletzung bei Verlieren (wenn keine Herzen mehr da wären) - Manchmal passiert nichts wenn man ein Item berührt Vielleicht ein paar mal spielen. Dann werdet ihr damit sicher "bekanntschaft machen" Bei mir wird die Hauptarbeit von Timer1 übernommen. Das gesammte Spiel befindet sich hier: ![]() Den Quellcode von Timer1 findet ihr hier:
Delphi-Quellcode:
Könnt ihr mir vielleicht beantworten warum diese Bugs entstehen ? Ich habe nämlich keine Ahnung :S
procedure TForm1.Timer1Timer(Sender: TObject);
var l,k,m,n,o,AL1,AL2,Zufall: Integer; begin //Spieler bewegegen If Spielerbewegung=True then begin If ((KeyPressed(VK_Up)) or (KeyPressed($57)) and (Spieler.Top >= Spielflaeche.Top)) Then Spieler.top := Spieler.top - Spieler.Speed; If ((KeyPressed(VK_Down)) or (KeyPressed($53)) and (Spieler.Top <= Spielflaeche.height + Spielflaeche.top - Spieler.Height)) Then Spieler.top := Spieler.top + Spieler.Speed; If ((KeyPressed(VK_Left)) or (KeyPressed($41)) and (Spieler.Left >= Spielflaeche.left)) Then Spieler.Left := Spieler.Left - Spieler.Speed; If ((KeyPressed(VK_Right)) or (KeyPressed($44)) and (Spieler.Left <= Spielflaeche.width + Spielflaeche.left - Spieler.width)) Then Spieler.Left := Spieler.Left + Spieler.Speed; end; //Kollision Spieler und Ziel if IsCollision(Spieler.BoundsRect, Ziel.BoundsRect) then begin Punktzahl:=Punktzahl+1; PunkteAnzeige.caption:='Punkte: '+IntToStr(Punktzahl); If Sounds='Enabled' Then begin SoundPlayer.FileName:=Pfad+'\Datein\Ziel.wav'; SoundPlayer.Open; SoundPlayer.play; end; ItemCount:=ItemCount+1; Ziel.Top:=random(Spielflaeche.Height - Ziel.Height) + Spielflaeche.top; Ziel.Left:=random(Spielflaeche.Width - Ziel.width) + Spielflaeche.left; // Gegner hinzufügen begin setLength(gegner,length(Gegner)+1); AL1 := length(Gegner)-1; Gegner[AL1]:= TGegner.Create(Self); With Gegner[AL1] do begin speed:=3; Parent := self; Cooldown := 1000; BringToFront; If RandomAusgabe(1)=1 Then begin Width:=5; Height:=30; top:= random( Spielflaeche.Height - height ) + Spielflaeche.top; Left := random( Spielflaeche.Width - Width ) + Spielflaeche.left; end; If RandomAusgabe(1)=0 Then begin Width:=30; Height:=5; top:= random( Spielflaeche.Height - height ) + Spielflaeche.top; Left := random( Spielflaeche.Width - Width ) + Spielflaeche.left; end; end; end; //Item hinzufügen begin If ItemCount=5 Then begin ItemCount:=0; Zufall:=RandomAusgabe(3); setLength(Item,length(Item)+1); AL2 := length(Item)-1; Item[AL2]:= TItem.Create(Self); With Item[AL2] do begin Picture.LoadFromFile(Pfad+'\Datein\Item.jpg'); Parent:=Self; Height:=16; Width:=16; Stretch:=True; Top:=random(Spielflaeche.Height - Ziel.Height) + Spielflaeche.top; Left:=random(Spielflaeche.Width - Ziel.width) + Spielflaeche.left; Brush.Color:=clblack; BringToFront; Enabled:=True; If ((Zufall=1) or (Zufall=2)) then begin Typ:=True; end; If Zufall=3 then begin Typ:=False; end; end; end; end; end; //Gegner bewegen If length(gegner)>=1 then begin For m:= 0 to high(gegner) do begin If Gegner[m].width > Gegner[m].Height Then begin //Waagrecht Gegner[m].left:=Gegner[m].left + Gegner[m].Speed; end; If Gegner[m].width < Gegner[m].Height Then begin //Senkrecht Gegner[m].Top:=Gegner[m].top + Gegner[m].Speed; end; end; end; //Gegner Cooldown For o:= low(Gegner) to high(Gegner) do begin If Gegner[o].cooldown>=1 Then Gegner[o].cooldown:=Gegner[o].cooldown-50; end; //Kollision Gegner und Wand For l:= low(gegner) to high(gegner) do begin if Gegner[l].Left <= Spielflaeche.Left then Gegner[l].speed:=Gegner[l].speed*-1; if Gegner[l].Left >= Spielflaeche.Width + Spielflaeche.Left - Gegner[l].Width then Gegner[l].speed:=Gegner[l].speed*-1; if Gegner[l].top <= Spielflaeche.Top - Gegner[l].Width then Gegner[l].speed:=Gegner[l].speed*-1; if Gegner[l].top >= Spielflaeche.height + Spielflaeche.top - Gegner[l].height then Gegner[l].speed:=Gegner[l].speed*-1; end; //Kollision Spieler und Gegner For k:= low(gegner) to high(gegner) do begin if ((IsCollision(Gegner[k].BoundsRect, Spieler.BoundsRect)) and (Gegner[k].Cooldown<=0))Then begin If Spieler.Verletzbar Then Dec(Herzen); If ((Herzen=4) and (Spieler.Verletzbar)) Then begin Spieler.Verletzbar:=False; Abwarten2.Enabled:=True; Herz5.picture.loadfromfile(Pfad+'\Datein\Herz_Leer.jpg'); end Else If ((Herzen=3) and (Spieler.Verletzbar)) Then begin Spieler.Verletzbar:=False; Abwarten2.Enabled:=True; Herz4.picture.loadfromfile(Pfad+'\Datein\Herz_Leer.jpg'); end Else If ((Herzen=2) and (Spieler.Verletzbar)) Then begin Spieler.Verletzbar:=False; Abwarten2.Enabled:=True; Herz3.picture.loadfromfile(Pfad+'\Datein\Herz_Leer.jpg'); end Else If ((Herzen=1) and (Spieler.verletzbar)) Then begin Spieler.Verletzbar:=False; Abwarten2.Enabled:=True; Herz2.picture.loadfromfile(Pfad+'\Datein\Herz_Leer.jpg'); end; end Else If Herzen<=0 then begin Verloren; Herz1.Picture.LoadFromFile(Pfad+'\Datein\Herz_leer.jpg'); end; end; //Kollision Spieler und Item For n := low(item) to high(item) do begin If ((IsCollision(Spieler.BoundsRect,Item[n].BoundsRect)) and (Item[n].Enabled=True)) Then begin Spieler.Upgrade(n,Item[n].Typ); Item[n].Enabled:=False; end; end; end; |
AW: Bugs und Zugriffsverletzungen in meinem Spiel (Aspirin)
Wie wäre es, wenn du uns erstmal sagst was genau los ist?
- Fehlermeldungen (ja, Strg+C funktioniert an sehr vielen Stellen, vorallem in Fehlerdialogen) - in welchen Zeilen treten die Fehler auf? - Und hast du dir schonmal angesehn wofür ein Debugger gut ist? |
AW: Bugs und Zugriffsverletzungen in meinem Spiel (Aspirin)
Zitat:
(Edit: hab mal nachgeschaut und jetzt weiß ich was du meinst xD. Aber was soll ich denn machen was sollen mir Haltepunkte bringen. Ich weiß ja nicht warum. Das habe ich auch schon mit Haltepunkten usw. nachgeschaut) Und eine richtige Zeile gibts ja nur für die Zugriffsverletzung. Die wäre dann bei
Delphi-Quellcode:
bei //Kollision Gegner und Spieler
if ((IsCollision(Gegner[k].BoundsRect, Spieler.BoundsRect)) and (Gegner[k].Cooldown<=0))Then
|
AW: Bugs und Zugriffsverletzungen in meinem Spiel (Aspirin)
Ich würde das Spiel über die Delphi IDE starten und spielen. Sobald eine Zugriffsverletzung auftritt, bekommst Du diese Meldung angezeigt und hast unten rechts einen Button Break. Wenn Du diesen dann anklickst, springt die Delphi IDE an die ungefähre Stelle wo die Zugriffsverletzung auftritt. Wenn Du diese Stelle hast, würde ich ein paar Zeilen davor den Haltepunkt setzen. Danach das Spiel wieder neu starten und spielen. Jetzt solltest Du die gleichen Aktionen ausführen wie beim ersten Mal und wenn Du an den Haltepunkt kommst mit Trace Into (F7) oder mit Step Over (F8) die Zeilen Deiner Funktion durchgehen.
|
AW: Bugs und Zugriffsverletzungen in meinem Spiel (Aspirin)
Der Fehler tritt vermutlich beim Zugriff auf Gegner[k] auf.
Eigentliche Ursache ist dann die Stelle, an der Gegner freigegeben werden. Dazu fehlt aber der Quellcode. |
AW: Bugs und Zugriffsverletzungen in meinem Spiel (Aspirin)
Es kann auch nicht schaden, zu erwähnen welche Delphiversion man nutzt. Du kannst dein D7 ja ganz einfach mal im Forenprofil angeben.
Projekt > Optionen > Compiler > Laufzeitfehler > alle Haken dort reinmachen Sicherheitshalber (wärend du noch am Programm arbeitest) auch bei Projekt > Optionen > Compiler > Coderzeugung die optimierung aus und die Stackframes an. (dann hat es der Debugger einfacher) Nein, Debugger ist nicht nur "Haltepunkte". Da kann man nachsehn warum es knallt, indem man sich den aktuellen Wert von Variablen ansieht und so erkennen könnte, was nicht stimmt. Die sind dennoch praktisch, vorallem weil man ab da auch leicht mal den Code Zeile für Zeile, aka Befehl für Befehl einzeln/schrittweise ausführen und nachsehn kann, was genau passiert. :roll Und ich fragte nicht umsonst nach eine "genaueren" Fehlerbeschreibung, denn da kann man leichter erkennen, ob sich darin ein Hinweis verbirgt. z.B. "Zugriffsverletzung bei Adresse $xxxxxxxx auf Adresse $000000xx" = dort wird vermutlich auf "nil" (z.B. nicht existierendes Array oder Objekt) zugegriffen. Bei "Zugriffsverletzung bei Adresse $000000xx ..." wurde wohl eine Methode in einem nichtexistierenden Prozedurzeiger angesprungen. Und bei "Zugriffsverletzung bei Adresse $xxxxxxxx auf Adresse $xxxxxxxx" stimmt irgendwas Anderes nicht, aber 66% der Fälle hat man dennoch sofort erkannt. Wie gesagt ... Strg+C in der Form drücken und dann hier im Editor Strg+V. (X = irgendein Wert, meistens keine 0 ... und 0 = eine 0) |
AW: Bugs und Zugriffsverletzungen in meinem Spiel (Aspirin)
Die genaue Zugriffsverletzung lautet:
"Im Proekt Project1.exe ist eine Exeption der Klasse EAccessViolation aufgetreten. Meldung'Zugriffsverletzung bei Adresse 0046B726 in Modul 'Project1.exe'. Lesen von Adresse 00000008. Prozess wurde angehalten. Mit Einzelne Anweisung oder Start vortsetzen" |
AW: Bugs und Zugriffsverletzungen in meinem Spiel (Aspirin)
Dann lies Dir #5 und #6 noch einmal durch. Anscheinend greifst Du ungeprüft auf ein nil-Objekt zu, d.h. es wurde noch gar nicht erzeugt oder bereits freigegeben.
|
AW: Bugs und Zugriffsverletzungen in meinem Spiel (Aspirin)
So, daß heißt also es wird auf etwas zugrgriffen, was es nicht gibt ... und das kann man sehr leicht nachprüfen.
Zitat:
Also entweder liegt es am IF oder an dem, was in IsCollision liegt. (falls es an is colision liegt, dann kann man den Inhalt ) Da es ein nicht "direkt" reproduzierbarer Fehler ist, hilft ein Haltepunkt nicht viel, da man nun jede Ausführung dieser Zeile prüfen müßte, bis es knallt (das kann dauern). Man läßt es nun also erstmal knallen und schaut sich nach dem Knall im Debugger die Variablen an. Dort suchst du nun nach einem nil. Leider sind sind nach einer exception "manchmal" keine Variableninhalte lesbar :cry: Also hilft man sich ganz einfach mit einem Schutzblock, welcher um den code drumrum kommt, wo man den Fehler vermutet. In dem Except-Block kann man sich entweder via ShowMessage und Co. Variableninhalte anzeigen lassen oder man kopiert den Code nochmals dort rein (nur sinnvoll wenn mit einem reproduzierbaren Ergebnis zu rechnen ist). bei dir also
Delphi-Quellcode:
Wenn es knallt, dann landet man im Except und kann den Code nochmals ausführen.
for ... do
try if ... then begin ... end; except if ... then // hier der Haltepunkt begin ... end; end; Dieses mal Schritt für Schritt und dabei guckt man sich "vorher" die Variableninhalte an. Bei dir ist es also speziell der Inhalt von Gegner, an der Position k, bzw. der Inhalt von IsColition. Daß "Spieler" verschwindet, schließe ich einfach mal aus, aber prüfen kann man es denoch. (ist ja kein Aufwand) Und zusätzlich nochmals: - wie vorher schonmal beschrieben, soltest du gewisse Einstellungen in den Projektoptionen vornehmen, womit bestimmte Prüfungen von Delphi automatisch eingebaut werden - manchmal kann es nicht schaden, wenn man geziehlt FreeAndNil verwendet, statt nur .Free (aber bei der genannten Fehlermeldung, ist sowas erstmal nicht nötig, da es sowieso schon nil ist) |
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:10 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz