![]() |
AW: Vektoriales Rechnen
Hallo Mauroon
die Funktion ZweiObjekte( ) überprüft, ob sich zwei Objekte a und b, welche sich mit gleichmässiger Geschwindigkeit je entlang einer Gerade bewegen jetzt gerade oder in der Zukunft treffen werden. IN: a1 : Momentaner Standort von a a2 : a ist unterwegs von a1 in Richtung a2 ppsa: Geschwindigkeit von a in Pixel Pro Sekunden radiusa : Zur Vereinfachung wird für die Form der Objekte ein Kreis mit Radius radiusa angenommen. [Man könnte hier natürlich auch ein Rechteck oder die wirkliche Form annehmen.] OUT: treffpunkt_a : Ortsvektor von a beim Zusammentreffen mit b. kontakt: TRUE, wenn sich die beiden Objekte momentan überlappen. zeit_bis_a2: Zeit, welche a von a1 nach a2 benötigt Result: TRUE, wenn sich die beiden Objekte jetzt treffen oder sich in Zukunft treffen werden. Falls Result=TRUE: sekundenbiszumteffen: Nach dieser Zeit treffen a und b aufeinander.
Delphi-Quellcode:
function ZweiObjekte( a1, a2 : TRPoint; radiusa : extended; ppsa : extended;
b1, b2 : TRPoint; radiusb : extended; ppsb : extended; var treffpunkt_a, treffpunkt_b : TRPoint; var zeit_bis_a2 : extended; var sekundenbiszumteffen : extended; var kontakt : boolean ):boolean; var speeddelta, startdelta, speeda, speedb : TVektor; Radius : extended; quadres : TQuadResultat; res : boolean; function getVektor( a, b : TRPoint ): TVektor; begin Result.x := b.x - a.x; Result.y := b.y - a.y; end; function speedvektor( v : TVektor; pps : extended ) : TVektor; var len : extended; // IN v in Bewegungsrichtung pps=Speed des Objekts Pixel pro Sekunden // OUT Vektor - nach einer Sekunde hat sich das Objekt um diesen Vektor verschoben begin len := sqrt( sqr(v.x) + sqr(v.y) ); if ( len > 0 ) then begin Result.x := v.x/len*pps; Result.y := v.y/len*pps; end else begin v.x := 0; v.y := 0; end; end; function OrtNachTSekunden( start, speedvektor : TVektor; sec : extended ) : TVektor; begin Result.x := start.x + sec*speedvektor.x; Result.y := start.y + sec*speedvektor.y; end; function hkontakt( pos1, pos2 : TRPoint; radius1, radius2 : extended ):boolean; begin Result := sqrt(sqr(pos2.x-pos1.x) + sqr(pos2.y-pos1.y)) < (radius1 + radius2); end; begin Radius := radiusa + radiusb; res := false; kontakt := false; // Objekt a bewegt pro Sekunde "speeda" vorwärts - Objekt b bewegt pro Sekunde "speeda" vorwärts speeda := speedvektor( getVektor( a1, a2 ), ppsa ); speedb := speedvektor( getVektor( b1, b2 ), ppsb ); // Solange benötigt a von a1 nach a2: if abs(speeda.x) > abs(speeda.y) then zeit_bis_a2 := ( a2.x - a1.x )/speeda.x else zeit_bis_a2 := ( a2.y - a1.y )/speeda.y; // nach t Sekunden befindet sich Objekt a an der Stelle a1 + t*speeda, // nach t Sekunden befindet sich Objekt b an der Stelle b1 + t*speedb // Treffen die Objekte aufeinander? D.g. gibt es ein t: a1 + t*speeda = b1 + t*speedb? speeddelta := getVektor( speedb, speeda ); startdelta := getVektor( b1, a1 ); if ( speeddelta.x = 0 ) and ( speeddelta.y = 0 ) then begin // die relative geschwindigkeit zwischen a und b ist 0 => // prüfen, ob sich a und b am momentanen ort berühren: res := hkontakt( a1, b1, radiusa, radiusb ); treffpunkt_a := a1; treffpunkt_b := b1; kontakt := res; sekundenbiszumteffen := 0; end else begin // sonst muss für ein Zusammentreffen nach t gelten: // ¦a1+t*speeda - (b1+t*speedb)¦ < Radius => // Dies führt auf eine quadratische Gleichung in t, welche wir lösen müssen: if Quadratische_Gleichung_Reell( (sqr(speeddelta.x) + sqr(speeddelta.y)), 2*( speeddelta.x * startdelta.x + speeddelta.y * startdelta.y), sqr(startdelta.x) + sqr(startdelta.y)- sqr(Radius), quadres ) then begin // quadres.x2 ist immer <= quadres.x1 (da in dieser quadratischen Gleichung (at^2+bt+c=0) a immer positiv ist) if ( quadres.x1 <> quadres.x2 ) then // wir werden nur Überschneidungen der Kreise als Treffer begin kontakt := ( quadres.x2 < 0 ) and ( quadres.x1 > 0 ); if kontakt then begin // a und b haben momentan einen gemeinsamen Schnitt treffpunkt_a := a1; treffpunkt_b := b1; res := true; sekundenbiszumteffen := 0; end else begin // a und b werden in quadres.x2 Sekunden einen gemeinsamen Schnitt haben if ( quadres.x2 > 0 ) then begin treffpunkt_a := OrtNachTSekunden( a1, speeda, quadres.x2 ); treffpunkt_b := OrtNachTSekunden( b1, speedb, quadres.x2 ); res := true; sekundenbiszumteffen := quadres.x2; end; end; end; end; end; Result := res; end; Anwendungsbeispiel: Dein Spielobjekt a befindet sich an Position a1, das Zielobjekt an Position a2. a (dein Projektil) bewegt sich mit ppsa in Richtung a2. b ist ein Hindernis, welches sich auch bewegt oder auch still steht ( dann ppsb = 0 wählen ). Die Funktion überprüft, ob und wann (var sekundenbiszumteffen) a auf b treffen wird. Die Funktion berechnet ebenfalls, wie lange a von a1 nach a2 benötigt. Code unten: a bewegt sich entlang der x Achse von x=1000 nach -1000. speed 500 b bewegt sich entlang der y Achse von y=500 nach 0. speed 250 Die Funktion gibt TRUE zurück, weil sich die Objekte natürlich nach ca. 2 Sekunden in der Region (0,0) treffen werden. a und b treffen nach treffer_in_sec=1.989266873708 aufeinander. a benötigt von a1 nach a2 bisa=4 Sekunden. => a trifft aufs Hindernis b, bevor a beim Punkt a2 angekommen ist.
Delphi-Quellcode:
procedure TForm92.Button1Click(Sender: TObject);
var a1, a2, b1, b2, tpa, tpb : TRPoint; ppsa, ppsb, radiusa, radiusb, bisa2, treffer_in_sec : extended; kontakt : boolean; begin a1 := RPoint( 0,1000); a2 := RPoint( 0,-1000 ); b1 := RPoint( 500,0 ); b2 := RPoint( 0,0 ); radiusa := 3; radiusb := 3; ppsa := 500; ppsb := 250; if ZweiObjekte( a1, a2, radiusa, ppsa, b1, b2, radiusb, ppsb, tpa, tpb, bisa2, treffer_in_sec, kontakt ) then begin showmessage( 'treffer' ); end else showmessage( 'kein treffer' ); end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:15 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