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;