Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Delphi Berührung 2er bewegter Kreise (https://www.delphipraxis.net/134598-beruehrung-2er-bewegter-kreise.html)

mr____zero 25. Mai 2009 15:23


Berührung 2er bewegter Kreise
 
ersteinmal hallo bin hier schonwas länger angemeldet brauchte aber bisher noch nicht wirklich hilfe
jetzt schon^^

mein problem ist das wir für die schule ein prog schreiben sollen indem sich auf einem canvas 2 kreise bewegen die gleiche oder verschiedene geschwindigkeiten haben
treffen diese auf die wände sollen sie reflektiert werden was auch klappt aller dings sollen sie auch reflecktiert werden wenn sie sich gegenseitig berühren und da liegt mein problem

hier einmal den quelltext

Code:
verschx := StrToInt(edit1.text);
    verschy := StrToInt(edit2.text);
    verschx1 := StrToInt(edit3.text);
    verschy1 := StrToInt(edit4.text);

    image1.Canvas.Pen.Color := clwhite;
    image1.Canvas.Brush.Color := clwhite;
    image1.Canvas.Rectangle(x,y,x+50,y+50);
    image1.Canvas.Rectangle(x1,y1,x1+50,y1+50);

    x := x+verschx;
    y := y+verschy;
    x1 := x1+verschx1;
    y1 := y1+verschy1;
    image1.Canvas.Pen.Color := clred;
    image1.Canvas.Brush.Color := clred;

    {if (((x1 <= x+50) and (x1 >= x)) and ((y1 <= y+50) and (y1 >= y)))
    then begin
             edit1.Text := IntToStr(StrToInt(Edit1.Text)*(-1));
             edit3.Text := IntToStr(StrToInt(Edit3.Text)*(-1));
             edit2.Text := IntToStr(StrToInt(Edit2.Text)*(-1));
             edit4.Text := IntToStr(StrToInt(Edit4.Text)*(-1));
         end;}
    if (x1+25-x+25+y1+25-y+25) > 0
    then if (Round(sqrt(x1+25-x+25+y1+25-y+25))) <= 50
         then begin
               edit1.Text := IntToStr(StrToInt(Edit1.Text)*(-1));
               edit3.Text := IntToStr(StrToInt(Edit3.Text)*(-1));
               edit2.Text := IntToStr(StrToInt(Edit2.Text)*(-1));
               edit4.Text := IntToStr(StrToInt(Edit4.Text)*(-1));
              end ;



    if x <= 0
    then edit1.Text := IntToStr(StrToInt(Edit1.Text)*(-1));

    if x >= image1.Width-50-StrToInt(Edit1.Text)
    then edit1.Text := IntToStr(StrToInt(Edit1.Text)*(-1));

    if y <= 0
    then edit2.Text := IntToStr(StrToInt(Edit2.Text)*(-1));

    if y >= image1.Height-50-StrToInt(Edit2.Text)
    then edit2.Text := IntToStr(StrToInt(Edit2.Text)*(-1));

    image1.Canvas.Ellipse(x,y,x+50,y+50);

    if x1 <= 0
    then edit3.Text := IntToStr(StrToInt(Edit3.Text)*(-1));

    if x1 >= image1.Width-50-StrToInt(Edit3.Text)
    then edit3.Text := IntToStr(StrToInt(Edit3.Text)*(-1));

    if y1 <= 0
    then edit4.Text := IntToStr(StrToInt(Edit4.Text)*(-1));

    if y1 >= image1.Height-50-StrToInt(Edit4.Text)
    then edit4.Text := IntToStr(StrToInt(Edit4.Text)*(-1));

    image1.Canvas.Brush.Color := clblue;
    image1.Canvas.Pen.Color := clblue;
    image1.Canvas.Ellipse(x1,y1,x1+50,y1+50);
hoffe das ihr mir helfen könnt:)

Satty67 25. Mai 2009 15:39

Re: Berührung 2er bewegter Kreise
 
Also mal theoretisch...

Beide Kreismittelpunkte berechnen (Koordinaten umgebendes Quadrat hast Du)
Entfernung der Kreismittelpunkte berechnen (Wie Diagonale eines Rechteckes)
Wenn Entfernung <= Radius1 + Radius2 dann berühren sich die Kreise

Sollte aus den Kreisen echte Ellipsen werde, wird es mit dem Radius haarig

mr____zero 25. Mai 2009 15:44

Re: Berührung 2er bewegter Kreise
 
nein sollen kreise bleiben
und von der theorie her ist mir auch klar wie das geht nur leider funzt das net habe bei beiden kreisen den radius 25 gewählt
nun rechne ich via phytagoras aus wie weit die voneinander entfernt sind und lasse die dann ihre richtung wechseln nur wenn man das ganze startet kommt da irgendwie müll raus

Code:
if round(sqrt(sqr(x1+25-x+25)+sqr(y1+25-y+25))) <= 50
         then begin
               edit1.Text := IntToStr(StrToInt(Edit1.Text)*(-1));
               edit3.Text := IntToStr(StrToInt(Edit3.Text)*(-1));
               edit2.Text := IntToStr(StrToInt(Edit2.Text)*(-1));
               edit4.Text := IntToStr(StrToInt(Edit4.Text)*(-1));
              end ;

Nikolas 25. Mai 2009 15:45

Re: Berührung 2er bewegter Kreise
 
Hast du schon mal was von Variablen gehört? Ein Edit ist nicht dazu da, Variablen zu speichern... Wenn du die aktuellen Werte anzeigen willst, wären Labels das richtige.
Zahlen wie "25" gehören auf keinen Fall (!) in den Code, in 2h weisst du nicht mehr, was die bedeuten, wenn du einen größeren Kreis benutzen willst, liegst du damit recht schnell auf der Nase.

Das mit der Kollision ist eigentlich ziemlich einfach. Du kannst die beiden Geraden, auf denen sich die Mittelpunkte bewegen, in Parameterform angeben:
g_1 : (x,y)+r*(vx,vy)
g_2 : (x',y')+s*(vx',vy')

Die beiden Kreise kollidieren, wenn der Abstand der geraden der Summe der Radien entspricht. In Abhängigkeit von der Position hast du einen Abstand von
d_x = (x+r*vx-x'-r*vx)
d_y = (y+r*vy-y'-s*vy')

d(r,s)=sqrt(d_x*d_x+d_y*d_y)

Dann löst du den Ausdruck d(r,s)=R_1+R_2 und hast zwei Mögliche Lösungen, wobei du die frühere Lösung wählst.

Wenn du das hast, kannst du dir sorgen um das Abprallen machen, da wirds schon ein bischen schwieriger, weil noch Rotationsmatrizen ins Spiel kommen (und für Fortgeschrittene auch noch unterschiedliche Massen).

@satty: Das mit Ellipsen wird SEHR unschön. Die Kollisionsberechnung dort für auf ein Polynom dritten Grades, dessen Lösung (ohne Approximative Verfahren) recht schwierig wird.

@Post 3: Hast du verstanden, was dein Code macht? Du tust so, als ob die Kugeln von senkrechten Wänden abprallen und nicht voneinander...
btw: Du hast schon die Variable verschx. Warum machst du diesen Murks mit den Casts in das Edit rein und wieder raus?

mr____zero 25. Mai 2009 15:53

Re: Berührung 2er bewegter Kreise
 
Zitat:

Zitat von Nikolas
Hast du schon mal was von Variablen gehört? Ein Edit ist nicht dazu da, Variablen zu speichern... Wenn du die aktuellen Werte anzeigen willst, wären Labels das richtige.
Zahlen wie "25" gehören auf keinen Fall (!) in den Code, in 2h weisst du nicht mehr, was die bedeuten, wenn du einen größeren Kreis benutzen willst, liegst du damit recht schnell auf der Nase.

Das mit der Kollision ist eigentlich ziemlich einfach. Du kannst die beiden Geraden, auf denen sich die Mittelpunkte bewegen, in Parameterform angeben:
g_1 : (x,y)+r*(vx,vy)
g_2 : (x',y')+s*(vx',vy')

Die beiden Kreise kollidieren, wenn der Abstand der geraden der Summe der Radien entspricht. In Abhängigkeit von der Position hast du einen Abstand von
d_x = (x+r*vx-x'-r*vx)
d_y = (y+r*vy-y'-s*vy')

d(r,s)=sqrt(d_x*d_x+d_y*d_y)

Dann löst du den Ausdruck d(r,s)=R_1+R_2 und hast zwei Mögliche Lösungen, wobei du die frühere Lösung wählst.

Wenn du das hast, kannst du dir sorgen um das Abprallen machen, da wirds schon ein bischen schwieriger, weil noch Rotationsmatrizen ins Spiel kommen (und für Fortgeschrittene auch noch unterschiedliche Massen).

@satty: Das mit Ellipsen wird SEHR unschön. Die Kollisionsberechnung dort für auf ein Polynom dritten Grades, dessen Lösung (ohne Approximative Verfahren) recht schwierig wird.

@Post 3: Hast du verstanden, was dein Code macht? Du tust so, als ob die Kugeln von senkrechten Wänden abprallen und nicht voneinander...
btw: Du hast schon die Variable verschx. Warum machst du diesen Murks mit den Casts in das Edit rein und wieder raus?

g_2 : (x',y')+s*(vx',vy')
hier müsstest du mir noch einmal erklären was du mit s meinst
ansonsten danke ich dir für deine hilfe werde versuchen alles umzusetzen

jfheins 25. Mai 2009 22:07

Re: Berührung 2er bewegter Kreise
 
Zitat:

Zitat von mr____zero
g_2 : (x',y')+s*(vx',vy')
hier müsstest du mir noch einmal erklären was du mit s meinst
ansonsten danke ich dir für deine hilfe werde versuchen alles umzusetzen

Das ist ein Schreibweise für eine Gerade.

s ist eine Laufvariable (z.B. die Zeit) und x',y' ist die Anfangsposition. Zum Zeuitpubkt s=0 ist die Position also gleich der Anfangsposition. Danach bewegt sich das Objekt - du zählst s hoch und bekommst die aktuielle Position raus.

mr_emre_d 26. Mai 2009 00:03

Re: Berührung 2er bewegter Kreise
 
Delphi-Quellcode:
function CircleIntersect( Circle1Center, Circle2Center: TPoint;
  Circle1Radius, Circle2Radius: Cardinal ): Boolean;
begin
  Circle1Center := Point( Circle2Center.X - Circle1Center.X, Circle2Center.Y - Circle1Center.Y );
  Result := SQRT( Circle1Center.X*Circle1Center.X + Circle1Center.Y*Circle1Center.Y ) <= (Circle1Radius div 2 + Circle2Radius div 2);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  M1  := Point( $80, $80 );
  M1R := $80;
  M2  := Point( $100, $80 );
  M2R := $80;
end;

procedure TForm1.FormPaint(Sender: TObject);
begin
  if CircleIntersect( M1, M2, M1R, M2R ) then
    Canvas.Pen.Color := clRed
  else
    Canvas.Pen.Color := clLime;
  Canvas.Ellipse( M1.X - M1R div 2, M1.Y - M1R div 2, M1.X + M1R div 2, M1.Y + M1R div 2 );
  Canvas.Ellipse( M2.X - M2R div 2, M2.Y - M2R div 2, M2.X + M2R div 2, M2.Y + M2R div 2 );
end;

Nikolas 26. Mai 2009 15:59

Re: Berührung 2er bewegter Kreise
 
Das ist aber ziemlich schlechter Stil.

Warum benutzt du in der Intersect-Funktion denn keine lokale Variable für den Abstand in x und y und überschreibst lieber einen der Parameter, wodurch die fiese Seiteneffekte auslöst und die Benennung der Variablen nichts mehr mit ihrem Inhalt zu tun hat.
Was machst du bei schnellen Kreisen? (Also etwa solche, die während eines Zeitschritts durcheinander durchlaufen?)
Die Lösung funktioniert zwar bei einfachen Beispielen, bei einer richtigen Anwendung bringt es dir aber gar nichts mehr...

Draos 26. Mai 2009 18:47

Re: Berührung 2er bewegter Kreise
 
Wie wärs mit Vektorrechnung? Hier mal eine Function die ich aufgrund eines Kollisionstest mal schrieb.
Vector ist eine Klasse die die Vektoroperationen beinhaltet.
Delphi-Quellcode:
TSphere=record
  m         :TVector;//Stützvektor, Kreismittelpunkt
  a         :TVector;//Geschwindigkeitsvektor
  r         :Single;//Kreisradius
end;
//..
function collision(k1,k2:TSphere):Single;
var a,b :TVector;
    s,r,t:Single;
begin
 with Vector do begin
  a:=Sub(k1.m,k2.m);
  b:=Sub(k1.a,k2.a);
  r:=k1.r+k2.r;
  t:=Skalar(b,b);
  if t<>0 then begin
   s:=sqr(Skalar(a,b)/t)-Skalar(a,a)/t+r*r/t;
   if s>=0 then
    s:=-Skalar(a,b)/t-sqrt(s)
   else s:=0;
  end else s:=0;
  result:=s;
 end;
end;
Der Rückgabewert der Funktion beinhaltet die Zeiteinheiten bis die Kreise kollidieren. Wenn sie nicht kollidieren s=0.


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