Space Invaders

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
LazarusPleb
Beiträge: 10
Registriert: Do 5. Okt 2017, 18:05

Space Invaders

Beitrag von LazarusPleb »

Hallo,
ich habe ein Problem bei meinem Space Invaders Clon.
Alles funktioniert, bis darauf, dass die Schüsse der Gegner nicht richtig erkennen, ob das eigene Raumschiff getroffen wird.
Der dafür wichtige Code ist Zeile 167-231.
Bitte um Hilfe, was ich falsch gemacht hab.
Prinzip. linker Punkt des Schusses muss kleiner vom x wert sein als linker Punkt des Raumschiffes. Dementsprechend rechter Punkt des Schusses muss größer sein, als rechter Punkt des Raumschiffes und es muss auf der passenden Höhe liegen. Andersrum bei dem abschießen der Aliens hat es nach dem Prinzip geklappt.

(alles an Quelltext in unit 1.)
https://www.file-upload.net/download-12 ... s.rar.html

[url][/url]

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Space Invaders

Beitrag von wp_xyz »

LazarusPleb hat geschrieben:Hallo,
linker Punkt des Schusses muss kleiner vom x wert sein als linker Punkt des Raumschiffes. Dementsprechend rechter Punkt des Schusses muss größer sein, als rechter Punkt des Raumschiffes und es muss auf der passenden Höhe liegen.

Wirklich? Ich weiß zwar nicht, was hier genau passieren soll, aber wenn der Schuss das Raumschiff treffen soll, dann muss die linke Koordinate des Geschosses größer sein als der linke Punkt des Raumschiffes und die rechte kleiner, also in Pseudocode:

Code: Alles auswählen

 (Geschoss.x > Raumschiff.Left) and (Geschoss.x < Raumschiff.Right)

Und wenn Streifschüsse erlaubt sind, dann muss das "<" durch ein "<=" ersetzt werden, genauso beim ">".

LazarusPleb
Beiträge: 10
Registriert: Do 5. Okt 2017, 18:05

Re: Space Invaders

Beitrag von LazarusPleb »

wp_xyz hat geschrieben:
LazarusPleb hat geschrieben:Hallo,
linker Punkt des Schusses muss kleiner vom x wert sein als linker Punkt des Raumschiffes. Dementsprechend rechter Punkt des Schusses muss größer sein, als rechter Punkt des Raumschiffes und es muss auf der passenden Höhe liegen.

Wirklich? Ich weiß zwar nicht, was hier genau passieren soll, aber wenn der Schuss das Raumschiff treffen soll, dann muss die linke Koordinate des Geschosses größer sein als der linke Punkt des Raumschiffes und die rechte kleiner, also in Pseudocode:

Code: Alles auswählen

 (Geschoss.x > Raumschiff.Left) and (Geschoss.x < Raumschiff.Right)

Und wenn Streifschüsse erlaubt sind, dann muss das "<" durch ein "<=" ersetzt werden, genauso beim ">".


Ersteinam vielen Dank für die schnelle Antwort, auch wenn ich den Sinn bei dir nicht wirkliche erkenne, habe ich es mal ausprobiert Funktioniert hat es nicht.
https://imgur.com/a/QuDan
So habe ich mir das vorgestellt. Wo ist der Denkfehler?

Mathias
Beiträge: 6164
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Space Invaders

Beitrag von Mathias »

Es betrifft nicht deine Frage, aber ich gebe dir einen Tip, das dein Code übersichtlicher wird. :wink:
Wieso verwendest du in OpenGL nicht glTranslatef ?

Code: Alles auswählen

  glPushMatrix;       //Gegner1
  glTranslatef(-0.8 + gegnerrechts1, 0.9 - gegnerunten, 0.0);
 
  glbegin(gl_QUADS);
  glcolor3f(1 + gegner1farbe, 0.0, 0.0);
  glvertex3f(-0.0, -0.05, 0.0);
  glvertex3f(-0.1, -0.05, 0.0);
  glvertex3f(-0.1, 0.0, 0.0);
  glvertex3f(-0.0, 0.0, 0.0);
  glend;
 
  glPopMatrix;

Sieht doch recht aufgeräumt aus ?
Somit findest du auch viel schneller einen Fehler. :wink:

Von Arrays würde ich auch Gebrauch machen, zB.

Code: Alles auswählen

var 
  schusstart: array[10..14] of Real

Somit kannst du deine Abfrage bei Timer2Timer sehr elegant lösen.

Code: Alles auswählen

  for i := 10 to 14 do begin
    if schussstart[i] = 15 then begin
      gegnerschussoben := gegnerschussoben - 0.01;
    end;
  end;


Somit könntest so etwas auch in eine for-to-Schleife packen und sparst somit etliche Zeilen Code.
Die gegner?farbe müsste dann auch in eine Array.

Code: Alles auswählen

  if (schussoben - 0.85 > 0.9 - gegnerunten) and (gegnerrechts1 - 0.9 < schusslinks + 0.01) and (gegnerrechts1 - 0.8 > schusslinks - 0.01) then
    //Wird überprüft, ob Raumschiff 1 getroffen wird
  begin
    gegner1farbe := -1;
    //Raumschiff wird gelöscht, indem es schwarz wird
    Schussoben := 0;
    //Variablen des Schuss werden für den nächsten Schuss zurückgesetzt
    Schussstart := 0;
  end;


Auch in den Zeilen wo sich dein Fehler befindet, wäre eine Schleife angebracht, dann müsstest du nur einmal korrigieren, anstelle von 5mal.

Ich hoffe das ich dir mit diesen Tips helfen kann.

PS:Wen du willst kann ich die noch sagen, wie du die Steuerung deines Raumschiffes elegant lösen kannst, ohne das sich die Tastaturwiederholung bemerkbar macht.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

LazarusPleb
Beiträge: 10
Registriert: Do 5. Okt 2017, 18:05

Re: Space Invaders

Beitrag von LazarusPleb »

LazarusPleb hat geschrieben:
wp_xyz hat geschrieben:
LazarusPleb hat geschrieben:Hallo,
linker Punkt des Schusses muss kleiner vom x wert sein als linker Punkt des Raumschiffes. Dementsprechend rechter Punkt des Schusses muss größer sein, als rechter Punkt des Raumschiffes und es muss auf der passenden Höhe liegen.

Wirklich? Ich weiß zwar nicht, was hier genau passieren soll, aber wenn der Schuss das Raumschiff treffen soll, dann muss die linke Koordinate des Geschosses größer sein als der linke Punkt des Raumschiffes und die rechte kleiner, also in Pseudocode:

Code: Alles auswählen

 (Geschoss.x > Raumschiff.Left) and (Geschoss.x < Raumschiff.Right)

Und wenn Streifschüsse erlaubt sind, dann muss das "<" durch ein "<=" ersetzt werden, genauso beim ">".


Ersteinam vielen Dank für die schnelle Antwort, auch wenn ich den Sinn bei dir nicht wirkliche erkenne, habe ich es mal ausprobiert Funktioniert hat es nicht.
https://imgur.com/a/QuDan
So habe ich mir das vorgestellt. Wo ist der Denkfehler?


Ich habe das Programm, indem ich es so gemacht habe, wie du es sagst, hochgeladen:
https://www.file-upload.net/download-12842445/Versuch_SpaceInvaders.zip.html

Soner
Beiträge: 623
Registriert: Do 27. Sep 2012, 00:07
OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
CPU-Target: x86_64-win64
Wohnort: Hamburg

Re: Space Invaders

Beitrag von Soner »

Wenn ich deine Zeichnung von https://imgur.com/a/QuDan anschaue, dann ist die Kollisionsabfrage einfach. Bei Schuss.X2<Schiff.X1 oder Schuss.X1>Schiff.X2 findet nie ein Kollision statt, dann musste man das etwa so umsetzen (y1 ist oben und y2 ist unten)

Code: Alles auswählen

 
 if not ((Schuss.X2<Schiff.X1) or (Schuss.X1>Schiff.X2)) then begin // treffer bei x
   if not ((Schuss.Y2<Schiff.Y1) or (Schuss.Y1>Schiff.Y2)) then begin // treffer bei Y
     //getroffen
   end;   
 end;
 

LazarusPleb
Beiträge: 10
Registriert: Do 5. Okt 2017, 18:05

Re: Space Invaders

Beitrag von LazarusPleb »

Soner hat geschrieben:Wenn ich deine Zeichnung von https://imgur.com/a/QuDan anschaue, dann ist die Kollisionsabfrage einfach. Bei Schuss.X2<Schiff.X1 oder Schuss.X1>Schiff.X2 findet nie ein Kollision statt, dann musste man das etwa so umsetzen (y1 ist oben und y2 ist unten)

Code: Alles auswählen

 
 if not ((Schuss.X2<Schiff.X1) or (Schuss.X1>Schiff.X2)) then begin // treffer bei x
   if not ((Schuss.Y2<Schiff.Y1) or (Schuss.Y1>Schiff.Y2)) then begin // treffer bei Y
     //getroffen
   end;   
 end;
 


So hab ich das auch gemacht. Nur das statt dem or ein and ist.(Es muss ja innerhalb der Grenzen sein.)

Soner
Beiträge: 623
Registriert: Do 27. Sep 2012, 00:07
OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
CPU-Target: x86_64-win64
Wohnort: Hamburg

Re: Space Invaders

Beitrag von Soner »

Mit dem AND-Verknüpfung muss ganze Schuß im Schiff sein, sonst wird es nicht als Treffer gezahlt. Bei mein Abfrage reicht eine Berührung von irgeneine Seite. Ich prüfe ob es Nichttreffer und verneine das ganze.
Mein Vorgehensweise kannst du für viele Kollisionsabfragen verwenden. Es ist meistens einfacher Nichttreffer zu prüfen. z.B wenn (Schuss.X2<Schiff.X1) ist, dann ist es nicht Treffer und man braucht nicht mehr zu prüfen.

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Space Invaders

Beitrag von wp_xyz »

Ich würde das nicht mit NOT formulieren, da dreht sich einem ja der Kopf um, vor allem wenn man die boole'schen Gesetze nicht kennt: NOT (A AND B) = (NOT A) OR (NOT B).

Blödsinn - so wie es Soner macht, ist es genau richtig. (Leider kann ich meinen Beitrag hier nicht mehr löschen...)

[EDIT]
Um diesem Beitrag doch noch einen Sinn zu geben, man kann auch sagen: Das Schiff ist getroffen, wenn sich mindestens ein Eckpunkt des Geschosses im Schiff befindet:

Code: Alles auswählen

type
  TFigur = record
    x1, y1, x2, y2: Integer;
  end;
 
function PktinFigur(x,y: Integer; AFigur: TFigur): Boolean;
begin
  Result := (x >= AFigur.x1) and (x <= AFigur.x2) and (y >= AFigur.y1) and (y <= AFigur.y2);
end;
 
function Treffer(Schuss, Schiff: TFigur): Boolean;
begin
  Result := PktInFigur(Schuss.x1, Schuss.y1, Schiff) or
            PktInFigur(Schuss.x2, Schuss.y1, Schiff) or
            PktInFigur(Schuss.x1, Schuss.y2, Schiff) or
            PktInFigur(Schuss.x2, Schuss.y2, Schiff);
end

Mathias
Beiträge: 6164
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Space Invaders

Beitrag von Mathias »

Das Schiff ist getroffen, wenn sich mindestens ein Eckpunkt des Geschosses im Schiff befindet:

Etwas muss da noch berücksichtigt werden. Wen das Geschoss zu schnell ist und die FPS zu klein, dann kann es passieren, das das Geschoss durchfliegt, ohne das es zur Kollision kommt. Das war bei ersten NFS der Fall, wen man da mit dem Auto eine sehr hohe Geschwindigkeit hatte, fuhr man ab und zu durch den Gegenverkehr, ohne das es eine Kollision gab.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Antworten