Autor Beitrag
Waldkauz
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 102



BeitragVerfasst: Do 28.05.09 22:52 
Hallo

Wie bereits beschrieben, mach ich ein Spiel.
Auf einem Image bewegen sich zwei Images.
Wenn Image2 auf Image3 trifft, bzw. umgekehrt, soll der Timer angehalten werden.
Ich hab da zwar eine Ahnung, wie ich das machen könnte, und zwar, dass er ihn ausschaltet, sobald mindestens ein Pixel des jeweiligen Image den gleichen Abstand (Left, Top) hat, wie das andere - aber das wird ja 'ne ziemlich umständliche Schleife...

Gehts auch einfacher?

mfg

Markus
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19336
Erhaltene Danke: 1751

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Fr 29.05.09 00:28 
Prüfe einfach für alle vier Ecken des zweiten Images, ob der Punkt im Rechteck des ersten Images ist...
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
var
  FirstImgRect, SecondImgRect: TRect;
begin
  FirstImgRect := FirstImage.BoundsRect;
  SecondImgRect := SecondImage.BoundsRect;
  if PtInRect(SecondImgRect.TopLeft, FirstImgRect) // top left
    or PtInRect(Point(SecondImgRect.Right, SecondImgRect.Top), FirstImgRect) // top right
    or ... then
Wenn die Kollision schon vor dem Überlappen ausgelöst werden soll, füge vor der Abfrage noch ein OffsetRect(FirstImage, -1, -1); hinzu, damit das erste Rechteck ein Pixel in jeder Richtung größer ist.
Waldkauz Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 102



BeitragVerfasst: Sa 30.05.09 11:01 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Prüfe einfach für alle vier Ecken des zweiten Images, ob der Punkt im Rechteck des ersten Images ist...
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
var
  FirstImgRect, SecondImgRect: TRect;
begin
  FirstImgRect := FirstImage.BoundsRect;
  SecondImgRect := SecondImage.BoundsRect;
  if PtInRect(SecondImgRect.TopLeft, FirstImgRect) // top left
    or PtInRect(Point(SecondImgRect.Right, SecondImgRect.Top), FirstImgRect) // top right
    or ... then
Wenn die Kollision schon vor dem Überlappen ausgelöst werden soll, füge vor der Abfrage noch ein OffsetRect(FirstImage, -1, -1); hinzu, damit das erste Rechteck ein Pixel in jeder Richtung größer ist.


mein Gott, stell ich mich jetzt blöd an, aber was sind die anderen zwei Parameter? :oops: :oops:
Marc.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1876
Erhaltene Danke: 129

Win 8.1, Xubuntu 15.10

BeitragVerfasst: Sa 30.05.09 11:08 
Alle vier Ecken, zwei bleiben also noch übrig: Bottom Left und Bottom Right. :)
Waldkauz Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 102



BeitragVerfasst: Sa 30.05.09 11:16 
user profile iconMarc. hat folgendes geschrieben Zum zitierten Posting springen:
Alle vier Ecken, zwei bleiben also noch übrig: Bottom Left und Bottom Right. :)


Er sagt ständig "Inkompatible Typen - TRect und Tpoint"
Marc.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1876
Erhaltene Danke: 129

Win 8.1, Xubuntu 15.10

BeitragVerfasst: Sa 30.05.09 11:37 
user profile iconWaldkauz hat folgendes geschrieben Zum zitierten Posting springen:
Er sagt ständig "Inkompatible Typen - TRect und Tpoint"

Schau dir doch einmal in der DOH die Parameterreihenfolge an. Die ist im derzeitigen Beispiel verkehrt. ;)
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
   if PtInRect(FirstImgRect, SecondImgRect.TopLeft) // top left
    or PtInRect(FirstImgRect, Point(SecondImgRect.Right, SecondImgRect.Top)) // top right
    or PtInRect(FirstImgRect, SecondImgRect.BottomRight) // bottom right
    or ... //  bottom left
  then

Das wird aber so nur funktionieren, wenn das zweite Image kleiner-gleich groß dem Ersten ist. ;)
ffgorcky
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 573

WIN XP/2000 & 7Prof (Familie:Win95,Win98)

BeitragVerfasst: Sa 30.05.09 11:42 
Also wenn ich das gerade richtig überblicke, dann möchtest Du sowas schreiben:
ausblenden Delphi-Quelltext
1:
2:
3:
//Dieses müsste dann vom Timer aufgerufen werden:
if PruefeObKollision(Image2,Image3) or PruefeObKollision(Image3,Image2) then
   ShowMessage('Ja! Sie haben sich getroffen!');

Und die Abfrage wäre dann so:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
function PruefeObKollision(erstesImage,zweitesImage:TImage):boolean
begin
//Prüfung, ob das eine auf das andere oben getroffen hat:
if erstesImage.Left<zweitesImage.Left+zweitesImage.width and zweitesImage.Left<erstesImage.Left+erstesImage.width and zweitesImage.top<erstesImage.top+erstesImage.height then
   PruefeObKollision:=true;
//Prüfung, ob eine auf das andere links getroffen hat:
if erstesImage.Left<zweitesImage.Left+zweitesImage.width and zweitesImage.Top>erstesImage.Top+erstesImage.Height and erstesImage.top>zweitesImage.top+zweitesImage.height then
   PruefeObKollision:=true;
end;

- Oder?
Ich kann jetzt leider so spontan nicht sagen, ob ich da jetzt alles richtig geschrieben habe (da ich das hier momentan leider schlecht überprüfen kann) und:
Ich weiß leider im Moment auch keine einfachere, prozessorsparendere Lösung.


Zuletzt bearbeitet von ffgorcky am Sa 30.05.09 12:02, insgesamt 1-mal bearbeitet
Marc.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1876
Erhaltene Danke: 129

Win 8.1, Xubuntu 15.10

BeitragVerfasst: Sa 30.05.09 12:00 
Ich hab auch noch schnell etwas gebastelt. Es funktioniert jedenfalls.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
  if   (FirstImage.Left + FirstImage.Width <= SecondImage.Left) // right
   and (FirstImage.Left >= (SecondImage.Left + SecondImage.Width))
   or  (FirstImage.Left <= SecondImage.Left + SecondImage.Width) // left
   and (FirstImage.Left + FirstImage.Width >= SecondImage.Left)
   and ((FirstImage.Top <= SecondImage.Top + SecondImage.Height) // top
   and (FirstImage.Top + FirstImage.Height >= SecondImage.Top)
   or  (FirstImage.Top + FirstImage.Height >= SecondImage.Top)  // bottom
   and (FirstImage.Top <= SecondImage.Top + SecondImage.Height))
  then ...

Grüße,
Marc
ffgorcky
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 573

WIN XP/2000 & 7Prof (Familie:Win95,Win98)

BeitragVerfasst: Sa 30.05.09 12:09 
Ja Marc, ich denke nur, dass meine Lösung (so sie denn funktioniert - was ich ja hoffe) dadurch, dass ich die Abfragen auf jeweils nur von links und oben beschränkt habe und das ganze dann einfach nur noch einmal mit vertauschten Parametern (also Image2 und Image3 umgedreht) abfrage, das ganze doch übersichtlicher und schneller mal wieder zu ändern macht - oder?
Siehst Du das nicht so?
Marc.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1876
Erhaltene Danke: 129

Win 8.1, Xubuntu 15.10

BeitragVerfasst: Sa 30.05.09 12:16 
Das mag sein. Ich muss zugeben den Source relativ flott und ohne Gedanken runtergetippt zu haben. Ich muss jetzt auch leider direkt los, werd mir später nochmal den Kopf darüber zerbrechen. :?

Edit: Bei meinem Beispiel ließen sich auch die Parameter austauschen, vorrausgesetzt du verwendest ein entsprechendes Funktionsgerüst, wie bei dir.
Zudem, performanter wird dein Beispiel, wenn du statt den IF-Abfragen direkt den Boolschen-Wert als Rückgabe verwendest. :P
Timer1.Enabled := (A and B) or ..

Grüße,
Marc
Waldkauz Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 102



BeitragVerfasst: Sa 30.05.09 12:42 
hab jetzt mal alle durchprobiert...
Sind zwar frei von Fehlermeldungen, aber funktionieren tun sie nicht...die Images "fliegen" trotzdem weiter
SvenAbeln
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 334
Erhaltene Danke: 3



BeitragVerfasst: Sa 30.05.09 14:10 
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
function CheckCollision(FirstImage, SecondImage: TImage): boolean;
var
  FirstImgRect, SecondImgRect: TRect;
begin
  FirstImgRect := FirstImage.BoundsRect;
  SecondImgRect := SecondImage.BoundsRect;

  Result := (FirstImgRect.Left <= SecondImageRect.Right) and (FirstImgRect.Right>= SecondImageRect.Left)
        and (FirstImgRect.Top) <= SecondImageRect.Bottom) and (FirstImgRect.Bottom >= SecondImageRect.Top);
end;



@user profile iconffgorcky
In deiner Funktion prüfst du einige Bedingungen unötigerweise doppelt, ausserdem mußt du die beiden Abfragen noch miteinander verküpfen. Im Moment können die beiden Images sich über bzw untereinander befinden und du meldest trotzdem eine Kollision, da deine erste Bedingung schon erfüllt ist. z.B. Image2.Top = 5 und Image2.Top = 500

Ausserdem hast du noch einen groben Fehler:
Sollte es keine Kollision geben, wird bei dir gar kein Ergebnis geliefert, Result ist dann also undefiniert.

ausblenden Delphi-Quelltext
1:
if PruefeObKollision(Image2,Image3) or PruefeObKollision(Image3,Image2) then					

So ein Aufruf ist auch unnötig und eher verwirrent, denn wenn zwei Images kollidieren ist es egal in welcher Reihenfolge ich dies prüfe.

@user profile iconMarc.
ausblenden Delphi-Quelltext
1:
2:
  if   (FirstImage.Left + FirstImage.Width <= SecondImage.Left) //
   and (FirstImage.Left >= (SecondImage.Left + SecondImage.Width))


Das wird nur Wahr für folgende Bedingungen:
ausblenden Delphi-Quelltext
1:
2:
FirstImage.Left = SecondImage.Left und 
FirstImage.Width = SecondImage.Width = 0
da ein Bild nicht gleichzeitig Links und Rechts von einem anderen sein kann.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19336
Erhaltene Danke: 1751

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Sa 30.05.09 15:19 
Ja, die Parameter für PtInRect habe ich vertauscht, aber ansonsten klappt das so wie ich anfangs geschrieben habe...
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
var
  FirstImgRect, SecondImgRect: TRect;
begin
  FirstImgRect := FirstImage.BoundsRect;
  SecondImgRect := SecondImage.BoundsRect;
  if PtInRect(FirstImgRect, SecondImgRect.TopLeft) // top left
    or PtInRect(FirstImgRect, Point(SecondImgRect.Right, SecondImgRect.Top)) // top right
    or PtInRect(FirstImgRect, Point(SecondImgRect.Left, SecondImgRect.Bottom)) // bottom left
    or PtInRect(FirstImgRect, SecondImgRect.BottomRight) // bottom right
    then
user profile iconMarc. hat folgendes geschrieben Zum zitierten Posting springen:
Das wird aber so nur funktionieren, wenn das zweite Image kleiner-gleich groß dem Ersten ist. ;)
Das verstehe ich nicht, warum?
Einloggen, um Attachments anzusehen!
Waldkauz Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 102



BeitragVerfasst: Sa 30.05.09 15:50 
es geht immer noch nicht...

hier mal der quelltext:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
procedure TForm2.Button5Click(Sender: TObject);
var
  FirstImgRect, SecondImgRect: TRect;
begin
  FirstImgRect := Image2.BoundsRect;
  SecondImgRect := Image4.BoundsRect;
  if PtInRect(FirstImgRect, SecondImgRect.TopLeft) // top left
    or PtInRect(FirstImgRect, Point(SecondImgRect.Right, SecondImgRect.Top)) // top right
    or PtInRect(FirstImgRect, Point(SecondImgRect.Left, SecondImgRect.Bottom)) // bottom left
    or PtInRect(FirstImgRect, SecondImgRect.BottomRight) // bottom right
    then  Timer4.Enabled:=false;
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19336
Erhaltene Danke: 1751

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Sa 30.05.09 15:53 
Das gehört ja wohl eher in den Timer und nicht in den ButtonClick, oder?

Dass es prinzipiell funktioniert, siehst du ja an der Demo, ich weiß ja nicht was du anders machst. Ich vermute der ButtonClick passiert nur nicht im richtigen Moment...
Waldkauz Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 102



BeitragVerfasst: Sa 30.05.09 15:56 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Das gehört ja wohl eher in den Timer und nicht in den ButtonClick, oder?

Dass es prinzipiell funktioniert, siehst du ja an der Demo, ich weiß ja nicht was du anders machst. Ich vermute der ButtonClick passiert nur nicht im richtigen Moment...


upps :oops: , hast recht, das kommt in den Timer...
jetzt funktionierts!

Vielen Dank an alle!
Marc.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1876
Erhaltene Danke: 129

Win 8.1, Xubuntu 15.10

BeitragVerfasst: Sa 30.05.09 17:55 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconMarc. hat folgendes geschrieben Zum zitierten Posting springen:
Das wird aber so nur funktionieren, wenn das zweite Image kleiner-gleich groß dem Ersten ist. ;)
Das verstehe ich nicht, warum?
Angenommen, du willst wissen, ob eine größeres Rect ein kleineres schluckt und testest dabei nur die äußerden Punkte des größeren Rects... dann kann's durchrutschen. :P

user profile iconSvenAbeln hat folgendes geschrieben Zum zitierten Posting springen:

Das wird nur Wahr für folgende Bedingungen:
ausblenden Delphi-Quelltext
1:
2:
FirstImage.Left = SecondImage.Left und 
FirstImage.Width = SecondImage.Width = 0
da ein Bild nicht gleichzeitig Links und Rechts von einem anderen sein kann.

Korrekt. :oops:
Waldkauz Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 102



BeitragVerfasst: Mi 03.06.09 19:52 
user profile iconMarc. hat folgendes geschrieben Zum zitierten Posting springen:
Angenommen, du willst wissen, ob eine größeres Rect ein kleineres schluckt und testest dabei nur die äußerden Punkte des größeren Rects... dann kann's durchrutschen.

Und wie kann ich das verhindern, dass es "durchrutscht" ?
Denn genau das Problem habe ich jetzt.
Wenn das größere Image nun auf dem kleineren liegt (da das größere eine Zufallsposition hat) und es praktisch verdeckt, treten nicht die Paramter einer Kollision ein.

Moderiert von user profile iconNarses: Zitat gekürzt.
Waldkauz Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 102



BeitragVerfasst: Do 18.06.09 00:33 
push (sorry, aber das Problem mit dem Durchrutschen hab ich nach wie vor).
Und wird das nicht ein wenig zu aufwendig für eine Art Arkanoid-Spiel?
SvenAbeln
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 334
Erhaltene Danke: 3



BeitragVerfasst: Do 18.06.09 09:37 
user profile iconSvenAbeln hat folgendes geschrieben Zum zitierten Posting springen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
function CheckCollision(FirstImage, SecondImage: TImage): boolean;
var
  FirstImgRect, SecondImgRect: TRect;
begin
  FirstImgRect := FirstImage.BoundsRect;
  SecondImgRect := SecondImage.BoundsRect;

  Result := (FirstImgRect.Left <= SecondImageRect.Right) and (FirstImgRect.Right>= SecondImageRect.Left)
        and (FirstImgRect.Top) <= SecondImageRect.Bottom) and (FirstImgRect.Bottom >= SecondImageRect.Top);
end;


Dies erkennt auch, wenn ein Bild komplett in dem Anderen liegt.