Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Delphi Collisionsabfrage (https://www.delphipraxis.net/166-collisionsabfrage.html)

Luckie 16. Jun 2002 08:58


Collisionsabfrage
 
So Gegner habe ich auch schon - zu mindest einen :mrgreen:.

Zum Schiessen verwende ich jbg's Code und um zu prüfen, ob ich ihn getroffen habe, verwende ich folgenden Code in einem Timer:

Code:
[b]procedure[/b] TForm1.tmrDefenderHittingTimer(Sender: TObject);
[b]var[/b]
  ii: DWORD;
  p: PPoint;
[b]begin[/b]
  [b]for[/b] ii := 0 [b]to[/b] AllShoots.Count -1 [b]do[/b]
  [b]begin[/b]
    p := PPoint(AllShoots.Items[ii]);
    [b]if[/b] (p^.x > Image2.Left)
      [b]and[/b] (p^.x < Image2.Left + Image2.Width)
      [b]and[/b] (p^.y < Image2.Top)
      [b]then[/b]
    [b]begin[/b]
      Image2.Picture.LoadFromFile(ExtractFilePath(ParamStr(0)) + 'expl1.bmp');
      bHit := TRUE;
      tmrDefenderHitting.Enabled := FALSE;
    [b]end[/b];
  [b]end[/b];
[b]end[/b];
In einem anderen Timer wird bHit geprüft und wenn das TRUE ist der Gegner wieder neu positioniert und der Collisions-Timer neu gestartet und alles geht von vorne los.

Nun mein Problem:
Wenn ich den Gegner einmal getroffen habe und schon mehr mals geschossen habe, explodiert er von alleine mehr mals. Ich habe so das dumpfe Gefühl, dass nach dem der Gegner neu gestartet wurde, noch Schüsse in der Liste sind, die dann auch noch die Bedingung erfüllen.

Löschen der Liste:

Code:
[b]procedure[/b] TForm1.DeleteDeadShoots(DeleteAll: Boolean);
[b]var[/b]
  p, penemy: PPoint;
  ii: Integer;
[b]begin[/b]
  [b]for[/b] ii := AllShoots.Count - 1 [b]downto[/b] 0 [b]do[/b]
  [b]begin[/b]
    p := PPoint(AllShoots.Items[ii]);
    [b]if[/b] (p^.y < 0) [b]or[/b] (DeleteAll) [b]then[/b]
    [b]begin[/b]
     Fire; [color=#000080][i]// deswegen die Schleife rückwärts durchlaufen[/i][/color]
     Dispose(p);
    [b]end[/b];
  [b]end[/b];

  [b]for[/b] ii := AllShootsEnemy.Count - 1 [b]downto[/b] 0 [b]do[/b]
  [b]begin[/b]
    penemy := PPoint(AllShootsEnemy.Items[ii]);
    [b]if[/b] (penemy^.y > Width) [b]or[/b] (DeleteAll) [b]then[/b]
    [b]begin[/b]
     FireEnemy; [color=#000080][i]// deswegen die Schleife rückwärts durchlaufen[/i][/color]
     Dispose(penemy);
    [b]end[/b];
  [b]end[/b];
[b]end[/b];
Rufe ich das aber nach einem Treffer auf, bekomme ich eine Zugriffsverletzung.

by Daniel B; ich habe mir erlaubt aus den Variablen i ein ii zu machen, da sonst die Formatierung nicht funktioniert hätte.

OregonGhost 16. Jun 2002 10:57

Dein Code:

Code:
    [b]if[/b] (p^.x > Image2.Left)
      [b]and[/b] (p^.x < Image2.Left + Image2.Width)
      [b]and[/b] (p^.y < Image2.Top)
Das ist wohl die eigentliche Kollisionsabfrage. Nun, wenn du abfragst, ob x zwischen Left und Left + Width liegt, musst du auch abfragen, ob y zwischen Top und Top + Height liegt. Weil so wird auch ein Schuss ein Treffer sein, der unterhalb des Zielobjekts liegt.

Setzt du bHit nach der Abfrage auch wieder auf false?

Und musst du beim Löschen der Schüsse nicht zum einen den Schuss selbst löschen (machst du ja mit Dispose()), als auch den Eintrag in der TList (TList.Delete())? Steht auch in dem anderen Thread drin, aber im hier geposteten Code nicht...

Mir ist außerdem folgende Zeile unklar:

Code:
[b]if[/b] (penemy^.y > Width) [b]or[/b] (DeleteAll) [b]then[/b]
Warum soll y größer als Width sein?

Luckie 16. Jun 2002 17:15

Danke werde ich mir mal ankucken.

bHit setze ich wieder uaf TRUE und zur Information, falls es wichtig ist: Der Schuß von mir geht von unten nach oben und der des Gegner von oben nach unten, deswegen muß er gelöscht werden, wenn er größer der Höhe des Formulars wird.

jbg 16. Jun 2002 17:33

Re: Collisionsabfrage
 
Zitat:

Zitat von Luckie
Code:
    [b]if[/b] (p^.y < 0) [b]or[/b] (DeleteAll) [b]then[/b]
    [b]begin[/b]
       Fire; [color=#000080][i]// deswegen die Schleife rückwärts durchlaufen[/i][/color]
       Dispose(p);
    [b]end[/b];
  [b]end[/b];

Das sah doch bei mir anders aus. Anstatt Fire gehört da doch FAllShoots.Delete(i) hin. Mit Fire erzeugst du einen neuen Schuss, aber an dieser Stelle soll der Schuss aus FAllShoots entfernt werden. Das Kommentar kannst du entfernen und die Schleife wieder vorwärts laufen lassen, da du FAllShoots.Delete nicht aufrufts. Übrigens führt der Code zu einer Schutzverletzung, da der Speicherbereich für die Koordinaten zwar freigegen wird, aber eben nicht der Eintrag entfernt wird.

Luckie 16. Jun 2002 17:38

Sah das echt anders aus? Ehrlich gesagt habe ich mich die ganze Zeit gewundert warum da Fire steht :mrgreen:.

OregonGhost 16. Jun 2002 17:42

Wenn du y mit der Breite vergleichst, wird er aber nicht gelöscht, wenn y größer als die Höhe des Formulars ist, sondern erst, wenn es größer als die Breite ist ;c)

jbg 16. Jun 2002 17:48

Zitat:

Code:
Image2.Picture.LoadFromFile(ExtractFilePath(ParamStr(0)) + 'expl1.bmp');

Ich würde das expl1.bmp einmalig in ein TBitmap einlesen und dann nur noch Image2.Picture.Assign(BitmapExpl1);
schreiben. Diese Vorgehensweise ist um einiges schneller, da das Bild nicht jedesmal von der im Verhältinis zum Arbeitsspeicher langsamen Festplatte geladen werden muss.

Luckie 16. Jun 2002 17:52

Danke Jungs so klatt es.

@jbg: Kommt noch alles. Die Bitmaps und das ganze Zeugs wird in die Ressource gepackt nur so lnage ich noch am basteln bin ist es so etwas einfacher. Die Grafiken sind bis her noch nicht so toll. Ich werde mal sehen ob ich für die Spezial Effekts George Lucas gewinnen kann :wink: . Von der Optimierung habe ich schon geträumt und von Collosionsabfragen, Schleifen, Feuern, explodierenden Raumschiffen usw. :mrgreen:.


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:37 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