Entwickler-Ecke
Multimedia / Grafik - Canvas Kollisionsabfrage
somebody - So 10.01.10 01:01
Titel: Canvas Kollisionsabfrage
Hallo Leute, für die Schule sollen wir einen kleines Spiel Programmieren. Das ganze soll recht einfach sein, man hat eine Kanone, die man nach links und rechts bewegen kann. Außerdem kann diese auch Kugeln abschießen. Oben befindet sich ein "Raumschiff", welches man treffen kann.
Soweit auch kein problem. Zwei Bedingungen waren noch gegeben, das ganze soll Objektorientiert und mit Canvas gemacht werden. Auch noch kein Problem.
Jetzt ist nur die Frage, wie kann ich mit Canvas eine Kollisionsabfrage machen, also abfragen, ob die Kugel das "Raumschiff" berührt hat? Ich hatte schon probiert es so zu machen, dass ich gucke ob die y koordinaten der kugel und des Raumschiffes nahezu gleich sind, UND ob die x Koordinaten der Kugel und des Raumschiffes nahezu gleich sind, allerdings ist dieser Fall komischerweise nie eingetreten.
Die Kugel ist ein Canvas.Ellipse und das Raumschiff ein Canvas.Rectangle
Habt ihr eine Idde?
Gruß
somebody
P.S: Falls die Infos zu wenig waren, kann ich ja auch noch ein Stück Code posten.
MaPsTaR - So 10.01.10 01:09
Ich würde mir um das Raumschiff ein Rechteck oder anderes "denken" und dann anhand der Koordinaten des Geschosses berechnen, ob es sich in dem Rechteck befindet.
Aber wenn das bei dir nie eingetreten ist...
Am besten wäre du postest mal deinen Code.
somebody - So 10.01.10 01:18
Oki, also hiermit bewege ich die Kugel
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| Canvas.Ellipse(Kugel.Bewegen_x(10,Kugel.x),Kugel.Bewegen_y(10,Kugel.y),20 + Kugel.Bewegen_x(10,Kugel.x),20 + Kugel.Bewegen_y(10,Kugel.y));
. . .
Function TKugel.Bewegen_Y(AVy: integer; AYalt: integer): Integer; begin FYneu := AYalt + AVy;
Result := FYNeu; end;
function TKugel.Bewegen_X(AVx: integer; AXalt: integer): Integer; begin FXneu := AXAlt + AVx;
Result := FXneu; end; |
Und das Raumschiff bewegt sich so
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| Canvas.Rectangle(Raumschiff.Bewegen_x(Lok_x),20,50 + Raumschiff.Bewegen_x(Lok_x), 40); . . .
function TRaumschiff.Bewegen_X(AVx: integer): Integer; begin FXneu := FXneu + AVx;
if FXneu >= 800 then begin FXneu := -20; end else begin Result := FXneu; end; end; |
Und dann hatte ich halt versucht, die Koordinaten zu vergleichen, das sah dann ungefähr so aus.
Delphi-Quelltext
1: 2: 3: 4:
| if (Kugel.y <= 8) and (Kugel.x = Raumschiff.Bewegen_x(Lok_speicher) then begin Raumschiff.Destroy; end; |
Ich hoffe es bringt etwas...
Moderiert von
matze: Code- durch Delphi-Tags ersetzt
MaPsTaR - So 10.01.10 01:30
Zitat: |
Delphi-Quelltext 1: 2: 3: 4:
| if (Kugel.y <= 8) and (Kugel.x = Raumschiff.Bewegen_x(Lok_speicher) then begin Raumschiff.Destroy; end; | |
Warum bewegst du das Raumschiff beim Testen nochmal?
Welche Felder hat Raumschiff denn?
X- und Y-Koordinate? Width? ...
Delphi-Quelltext
1: 2: 3: 4:
| if (Kugel.y <= 8) and (Kugel.x > Raumschiff.x) and (Kugel.x < (Raumschiff.x + Raumschiff.width)) then begin Raumschiff.Destroy; end; |
ub60 - So 10.01.10 01:39
Die grobe Kollision gibt es mit IntersectRect (Schnittpunkt zweier Rechtecke), das "Finetuning" dann mit Masken.
ub60
somebody - So 10.01.10 01:40
Also ich bewege das Raumschiff nochmal, weil ich darüber die x Koordinate des Raumschiffes erhalte. Diese überprüfe ich dann... Man sieht die Bewegung aber nicht, da ich sie ja nicht zeichne.
Und das Raumschiff hat nur die Felder x und y.
MaPsTaR - So 10.01.10 01:53
Aber du müsstest die X-Koordinate doch auch in Lok_Speicher haben, oder?
Delphi-Quelltext
1: 2: 3: 4:
| if (Kugel.y <= 8) and (Kugel.x > Lok_speicher) and (Kugel.x < (Lok_speicher + 50)) then begin Raumschiff.Destroy; end; |
Wie kommst du eigentlich auf
if (Kugel.y <= 8) ...
Müsste es nicht eher
Delphi-Quelltext
1:
| if (Kugel.y <= Raumschiff.y) ... |
heißen?
Bergmann89 - So 10.01.10 03:04
Hey,
ich würd das so machen:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| const TOLERANCE = 10;
if (Kugel.x + TOLERANCE > Raumschiff.x - TOLERANCE) and (Kugel.x - TOLERANCE < Raumschiff.x + TOLERANCE) and (Kugel.y + TOLERANCE > Raumschiff.y - TOLERANCE) and (Kugel.y - TOLERANCE < Raumschiff.y + TOLERANCE) then Raumschiff.Free; |
das Bild zeigt jetzt die 2. überprüfung. Der Punkt sind die Koordinaten un das Viereck die Toleranz.
MfG Bergmann
Moderiert von
Narses: Bild als Anhang hochgeladen.
somebody - So 10.01.10 11:29
Oki, Danke für die schnellen Antworten. Ich habe es jetzt mit Bergmans Variante versucht und es geht fast ohne Fehler. Das einzige Problem ist, dass wenn ich das Raumschiff getroffen habe, es nicht zerstört wird, sondern noch weiterlebt aber von Anfang an wieder startet. Wenn ich es dann ein Zweites mal treffen will, dann kommt eine Zugriffsverletzung, aber auch nur wenn ich das Raumschiff getroffen habe.
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:
| procedure TForm1.Timer1Timer(Sender: TObject); const toleranz = 10; begin Timer2.Enabled := false; Paintbox1.refresh;
Canvas.Ellipse(Kugel.Bewegen_x(10,Kugel.x),Kugel.Bewegen_y(10,Kugel.y),20 + Kugel.Bewegen_x(10,Kugel.x),20 + Kugel.Bewegen_y(10,Kugel.y));
Canvas.Rectangle(Lok_speicher,20,50 + Lok_speicher, 40); Kugel.Y := Kugel.Y - 10;
if Kugel.y <= 8 then begin if (Kugel.x + toleranz > Raumschiff.x - toleranz) and (Kugel.x - toleranz < Raumschiff.x + toleranz) then begin Raumschiff.Free; Timer2.Enabled := false; end else begin Timer2.Enabled := true; PaintBox1.Refresh; Kugel.Y := 650; Timer1.Enabled := false; end; end; end; |
Ich finde den Fehler irgendwie nicht, könnt ihr mir da weiterhelfen?
EDIT: Ich erzeuge das Raumschiff einfach nochmal, nachdem es getroffen wurde, damit nach einmal schießen nicht gleich alles vorbei ist. Das alte wird natürlich auch zerstört um speicher zu sparen.
Danke für eure hilfe!
Moderiert von
matze: Code- durch Delphi-Tags ersetzt
F34r0fTh3D4rk - So 10.01.10 12:12
ich würde die Toleranz auf der linken Seite weglassen. Sonst könnte man auch gleich schreiben:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| const TOLERANCE = 10;
if (Kugel.x > Raumschiff.x - TOLERANCE*2) and (Kugel.x < Raumschiff.x + TOLERANCE*2) and (Kugel.y > Raumschiff.y - TOLERANCE*2) and (Kugel.y < Raumschiff.y + TOLERANCE*2) then |
und dann lässt man das
*2 gleich weg und nimmt lieber ne größere Toleranz, falls es nicht reicht.
Das Projektil würde ich mir eher als Punkt vorstellen und das Raumschiff als Rechteck (in diesem Falle wäre es ein Quadrat).
Dann hast du halt nur noch die Punkt-In-Quadrat Prüfung zu machen.
Also eher wie das hier:
Delphi-Quelltext
1: 2: 3: 4: 5:
| if (Kugel.x > Raumschiff.x - Raumschiff.breite) and (Kugel.x < Raumschiff.x + Raumschiff.breite) and (Kugel.y > Raumschiff.y - Raumschiff.hoehe) and (Kugel.y < Raumschiff.y + Raumschiff.hoehe) then |
Und das mit der globalen Variable, in der du zusätzlich die Koordinate speicherst, ist nicht im Sinne der Objektorientierung.
In der Regel verzichtet man auf globale Variablen.
Ich würde das zu testende Projektil der Kollisions Funktion des Raumschiffs übergeben (oder umgekehrt):
Delphi-Quelltext
1:
| TRaumschiff.pruefeKollisionMit(projektil: TProjektil): boolean; |
oder:
Delphi-Quelltext
1:
| TProjektil.pruefeKollisionMit(raumschiff: TRaumschiff): boolean; |
Oder was hat es genau mit diesem
Lok_Speicher auf sich?
mfg
Bergmann89 - So 10.01.10 15:29
Hey,
wie erzeugst du denn das Raumschiff, bzw wo? Weil das steht ja nich im Codeausschnitt.
MfG Bergmann.
somebody - Mo 11.01.10 12:20
Das Raumschiff erzeuge ich in formcreate. Danke zwar für die weiteren Fragen, aber das Problem hat sich schon erledigt. geht mittlerweile alles...
aber trotzdem danke für die hilfe ;)
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!