Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi Geschwindigkeit umkehren (https://www.delphipraxis.net/171532-geschwindigkeit-umkehren.html)

DelphiUser1 10. Nov 2012 23:21

Geschwindigkeit umkehren
 
Guten Abend alle miteinander.
Momentan arbeite ich an einem kleinen Spiel, in dem es darum geht, Kreise zu vernichten. Diese Kreise werden mit einem timer erzeugt (array of TKreis).
Sie haben eine grundgeschwindigkeit von speedx=5 und speedy=5. Es gibt Objectives und Weapons, unter Objectives findet man unter anderem eine Kiste. Ich bewege sie in dem ich ihr einfach die mausposition zuweise. Das Problem ist das ich nicht weiß wie ich eine gute Kollision hinbekomme. Kollidieren die Kiste und ein kreis wird der kreis momentan in die selbe richtung aus der er kam zurückgeschleudert. ich will aber einfallswinkel gleich ausfallswinkel. Was ich bisher ausprobiert habe (ohne Erfolg):

Delphi-Quellcode:
if InterSectRect(StubRect,Kreis[b].BoundsRect,Image3.BoundsRect) and Image3.Visible then
    begin
      Kreis[b].speedx := -(Kreis[b].speedx);
      Kreis[b].speedy := -(Kreis[b].speedy);
      end;
    end;
und:


Delphi-Quellcode:
if InterSectRect(StubRect,Kreis[b].BoundsRect,Image3.BoundsRect) and Image3.Visible then
    begin
      Kreis[b].speedx := -Abs(Kreis[b].speedx);
      Kreis[b].speedy := -Abs(Kreis[b].speedy);
      end;

nuclearping 10. Nov 2012 23:27

AW: Geschwindigkeit umkehren
 
Wenn du nur die Speed-Werte umkehrst, ist es ja klar, dass der Kreis in exakt die selbe Richtung zurückfliegt, aus die er kam.

Was du noch brauchst ist eine Feststellung aus welcher Richtung die Kollision kommt und musst entsprechend darauf reagieren.

Von oben und unten: Y = -Y
Von links und rechts: X = -X

PS: Ich würde empfehlen, dass du dir auch mal Andorra 2D anschaust. Die VCL (TImage, ...) als Sprites zu verwenden ist auf lange Frist keine effiziente Lösung.

DelphiUser1 10. Nov 2012 23:32

AW: Geschwindigkeit umkehren
 
ja ich weiß, das ist mir auch bewusst, nur ich wusste nicht wie es richtig geht.
Wieso soll ich kein Image verwenden?
Ist schon etwas später, wie genau stellst du dir die Abfrage vor. ich hatte überlegt man könnte es mit dem Satz des Pythagoras machen, aber gibt es nicht noch was einfacheres?

himitsu 11. Nov 2012 00:14

AW: Geschwindigkeit umkehren
 
Liste der Anhänge anzeigen (Anzahl: 1)
Im Prinzip ist es einfache Mathematik.

Du hast 2 Vektoren, der aufeinandertreffenden Objekte.
Daraus kannst du eine Aufschlagebene berechnen, wie die Kräfte aufeinandertreffen.
Und darüber berechnest du dann jeweils die Winkel, wie es weitergeht.



Aber im Prinzip kommt dann noch mehr mit rein, wenn man es genau machen will.
- die jeweilige Geschwindigkeit der Objekte
- und die Größe/Masse
(also ob z.B. Kraft von einem Objekt auf das Andere übertragen wird)
- und teilweise auch die Form der Objekte, denn jenachdem wie und an welche Stelle der Aufschlag geschieht, kann sich das auch noch auswirken

nuclearping 11. Nov 2012 00:35

AW: Geschwindigkeit umkehren
 
Zitat:

Zitat von DelphiUser1 (Beitrag 1190674)
Ist schon etwas später, wie genau stellst du dir die Abfrage vor. ich hatte überlegt man könnte es mit dem Satz des Pythagoras machen, aber gibt es nicht noch was einfacheres?

Du kennst doch die Dimensionen deiner Objekte? Also X, Y, Höhe, Breite? Daraus kannst du bestimmen, von welcher Richtung das Quellobjekt kommt.

Code:
Wenn Kollision Dann
  Wenn Quellobjekt.Y + Quellobjekt.Höhe >= Zielobjekt.Y Dann
    Kollisionsrichtung = Von oben
  Wenn Quellobjekt.X + Quellobjekt.Breite >= Zielobjekt.X Dann
    Kollisionsrichtung = Von links
...
Nur als grobes Beispiel.

Medium 11. Nov 2012 02:04

AW: Geschwindigkeit umkehren
 
Nennt sich dann (Voll) Elastischer Stoß

nuclearping 11. Nov 2012 03:07

AW: Geschwindigkeit umkehren
 
Erinnert mich fast an http://einklich.net/rec/eins.htm :mrgreen:

Medium 11. Nov 2012 03:21

AW: Geschwindigkeit umkehren
 
Zugegeben: Mathematische Wipkipedia Artikel tendieren teilweise stark zu unnötig komplexen Formeln und Symbolgeilheit (oftmals wirklich für das breite Publikum unangemessen verklausuliert). Hier finde ich es aber doch noch recht okay - sind ja wirklich nur Grundrechenarten :) Wenn man die Formeln ein wenig auseinanderklamüsert sieht man, dass das an sich ziemlich popelig ist. Schaut auf den ersten Blick nur gewaltig aus.
In diesem Fall nicht nötig: Aber wenn man sich einfach mal vor Augen hält, dass eine Summenformel nichts weiter ist, als eine for-Schleife mit der Formel dahinter im Rumpf, verlieren zumindest diese schon mal ihre abschreckende Wirkung =)

Die Seite ist aber eine ziemlich herrliche Satire! Manchmal fühlt man sich echt so :)

DelphiUser1 11. Nov 2012 15:41

AW: Geschwindigkeit umkehren
 
Danke für die Lösung. Ich habe jetzt mal angefangen mit der Kollision
Delphi-Quellcode:
if (Kreis[b].y+Kreis[b].Height)>Image3.Height then    //Kreis kommt von oben
      Kreis[b].speedy := -Abs(Kreis[b].speedy);
und das funktioniert auch alles soweit, aber als ich versucht habe die kollision von unten und den Seiten zu schreiben, kam ich nicht mehr so ganz weiter. mit diesem code ging es nicht:

Delphi-Quellcode:
if Kreis[b].x+Kreis[b].Width>Image3.Width then     //
      begin
      Kreis[b].speedy := -Abs(Kreis[b].speedy);
      Kreis[b].speedx:= Abs(Kreis[b].speedx);
      end;

Bummi 11. Nov 2012 15:46

AW: Geschwindigkeit umkehren
 
bei den Seitenprüfungen musst Du x invertieren // wahrscheinlich ein Flüchtigkeitsfehler.
Du kannst links rechts zusammen und oben unten ebenfalls zusammen behandeln.

DelphiUser1 11. Nov 2012 16:16

AW: Geschwindigkeit umkehren
 
Was genau ist denn mit "x invertieren" gemeint?
Soll ich die speedx invertieren?
und wieso kann ich rechts und links und oben und unten als eins behandeln. Funktioniert zumindest nicht

Bummi 11. Nov 2012 17:06

AW: Geschwindigkeit umkehren
 
ich meinte etwas in der Art ....
Delphi-Quellcode:
if ((Kreis[b].y+Kreis[b].Height)>Image3.Height) or (Kreis[b].y <=0 ) then
      Kreis[b].speedy := - Kreis[b].speedy;

if ((Kreis[b].x+Kreis[b].Width)>Image3.Width) or (Kreis[b].x <= 0) then
      Kreis[b].speedx := - Kreis[b].speedx;

DelphiUser1 11. Nov 2012 19:42

AW: Geschwindigkeit umkehren
 
Mit diesem Code passiert leider genau das, was ich vermeiden wollte:
Der Ball prallt wieder in die Richtung, aus der er kam und nicht "Einfallswinkel=Ausfallswinkel"

Bummi 11. Nov 2012 20:03

AW: Geschwindigkeit umkehren
 
die Stelle mit der Positionszuweisung sieht schon so oder so ähnlich aus ?

Delphi-Quellcode:
Kreis[b].x := Kreis[b].x + Kreis[b].speedy;
Kreis[b].y := Kreis[b].y + Kreis[b].speedx;
ich hatte vor längerem mal ein Thema wo so etwas auch verwendet wurde ...
http://www.delphipraxis.net/156716-g...-und-zoom.html

DelphiUser1 11. Nov 2012 20:12

AW: Geschwindigkeit umkehren
 
Nein so oder so ähnlich sah sie nicht aus, aber mit dieser Zuweisung bugt es komplett rum.
Die Kreise bleiben stehen wenn sie jetzt das Objekt berühren...

nuclearping 11. Nov 2012 23:32

AW: Geschwindigkeit umkehren
 
Zitat:

Zitat von DelphiUser1 (Beitrag 1190739)
Danke für die Lösung. Ich habe jetzt mal angefangen mit der Kollision
Delphi-Quellcode:
if (Kreis[b].y+Kreis[b].Height)>Image3.Height then    //Kreis kommt von oben
      Kreis[b].speedy := -Abs(Kreis[b].speedy);
und das funktioniert auch alles soweit, aber als ich versucht habe die kollision von unten und den Seiten zu schreiben, kam ich nicht mehr so ganz weiter. mit diesem code ging es nicht:

Delphi-Quellcode:
if Kreis[b].x+Kreis[b].Width>Image3.Width then     //
      begin
      Kreis[b].speedy := -Abs(Kreis[b].speedy);
      Kreis[b].speedx:= Abs(Kreis[b].speedx);
      end;

1) Was willst du eigentlich mit dem Abs bezwecken?
2) So schwer ist es nicht. Es ist einfach nur Logik und hat nichts mit Programmieren zu tun. Logikarbeit nehme ich dir aber nicht ab, weil's der Punkt ist, wo du am meisten lernen kannst. :mrgreen:

DelphiUser1 11. Nov 2012 23:39

AW: Geschwindigkeit umkehren
 
1.Mir wurde erklärt das "abs" die Richtung absolut umkehrt und irgendwie sinnvoller wäre.
2.ja das ist richtig, ich will es auch gerne alleine schaffen, aber so ganz peile ich es noch nicht.
x und y zeigen die Position auf x und y Achsen an aber geht diese Position jetzt von der Mitte des Kreises aus oder wieso verrechnen wir diese Koordinaten mit der höhe?

Bummi 11. Nov 2012 23:52

AW: Geschwindigkeit umkehren
 
Zitat:

Die Kreise bleiben stehen wenn sie jetzt das Objekt berühren...
Der Code mit + with war von Dir und lies darauf schließen dass x und y die linke obere Ecke eines Rechteckes um Deinen Kreis darstellen. Im letzen Post schreibst Du x und y wären die Mitte es Kreises, in diesem Fall bleibst Du bei den Bedingungen zwangsläufig kleben wenn z.B. der rechte Halbkreis den rechten Rand beinhaltet und die Geschwindigkeit klein genug ist.
Hier musst Du einfach die Grenzen Deinen Gegebenheiten anpassen und rechts Width/2 zu x addieren und links statt 0 Width/2 verwenden, entsprechend für die y Koordinaten ...

Medium 11. Nov 2012 23:59

AW: Geschwindigkeit umkehren
 
Zitat:

Zitat von DelphiUser1 (Beitrag 1190784)
1.Mir wurde erklärt das "abs" die Richtung absolut umkehrt und irgendwie sinnvoller wäre.

Abs = Betrag, was bei einfachen reellen Zahlen bedeutet: "Wenn da ein Minus vor der Zahl ist, mach es weg. Wenn nicht, lass sie so."
Wer auch immer dir das wie du schriebst erzählt hat, wollte dich entweder veräppeln, oder ist definitiv nicht die richtige Person für mathematische Fragen. (Zumal ich nichtmal wüsse, wie man "absolut umkehren" verstehen sollte.)

DelphiUser1 12. Nov 2012 00:02

AW: Geschwindigkeit umkehren
 
Das Problem war wohl, dass ich mit dem Programm vor Ewigkeiten angefangen habe und mir über x und y nicht mehr im klaren war.
Die beiden variablen werden beim erzeugen des kreises verwendet um einen beliebigen startpunkt zu wählen, das sieht dann so aus:
Delphi-Quellcode:
Kreis [a].x := Kreis [a].radius + random (1000 - 2*Kreis [a].radius);
  Kreis [a].y := Kreis [a].radius + random (500 - 2*Kreis [a].radius);

Bummi 12. Nov 2012 00:09

AW: Geschwindigkeit umkehren
 
:cyclops:

Random für x und für y ... ok, dann weißt Du ja wo Du hinfassen musst, wobei gegen eine zufällige Positionierung nichts spricht solange Du weißt worauf sich x und y beziehen ... (z.B. top/left, center ...)

nuclearping 12. Nov 2012 01:52

AW: Geschwindigkeit umkehren
 
Zitat:

Zitat von DelphiUser1 (Beitrag 1190784)
2.ja das ist richtig, ich will es auch gerne alleine schaffen, aber so ganz peile ich es noch nicht.

Dann geh dein Konzept doch nochmal durch. Am besten mit 'nem Stift und 'n paar Blättern Papier. Wichtig ist, dass du dir auch im Kopf visualieren kannst, was im Code passiert und wieso er das macht, was er macht.

Zeichne deine Kreise und deine Objekte, beschrifte sie, zeichne Pfeile, gepunktete Linien um Bewegungen darzustellen ...

Zitat:

Zitat von DelphiUser1 (Beitrag 1190784)
x und y zeigen die Position auf x und y Achsen an aber geht diese Position jetzt von der Mitte des Kreises aus oder wieso verrechnen wir diese Koordinaten mit der höhe?

X und Y beziehen sich nicht auf den Mittelpunkt, sondern auf die obere linke Ecke des Sprite-Objekts.

Wenn du also eine Kollision rechts vom Objekt feststellen willst, muss du X + Breite addieren und prüfen, ob sie >= dem X-Wert des Kollisionsobjekts sind.

Wenn du auf eine Kollision links vom Objekt prüfen willst, musst du schauen, ob der X-Wert des Kollisionsobjekts + Breite des Kollisionsobjekts <= dem X-Wert deines Objekts sind.

Denn einem normalen Sprite-Objekt liegt in der Regel immer ein Quadrat zu Grunde, mit dem man arbeitet, auch wenn es einen Kreis darstellt (der Kreis wird dann in das Quadrat gezeichnet).

DelphiUser1 16. Nov 2012 17:39

AW: Geschwindigkeit umkehren
 
So also da bin ich wieder und habe mich direkt mal an die Arbeit gemacht.
X und Y werden wie folgt beschrieben:

Delphi-Quellcode:
 for b := 0 to high(Kreis) do
  begin
    Kreis [b].x := Kreis [b].x + Kreis [b].speedx; //Geschwindigkeit X
    Kreis [b].y := Kreis [b].y + Kreis [b].speedy; //Geschwindigkeit Y
    With Kreis [b] do
    begin
      Left := Kreis [b].x;
      Top := Kreis [b].y;
    end;
Nun zeigen die beiden ja die Position genau so an, wie es notwendig wäre. Wieso funktioniert es nun trotzdem nicht bzw. wieso prallt der Ball mit Bummis Sourcecode falsch ab und bugt rum

Bummi 16. Nov 2012 17:53

AW: Geschwindigkeit umkehren
 
pack das ganze doch mal in ein Zip, so stochern wir im Nebel rum ...

nuclearping 16. Nov 2012 17:57

AW: Geschwindigkeit umkehren
 
Irgendwie hab ich das Gefühl, dass das Ganze bei dir 'n ziemliches Flickwerk ist. :mrgreen: Daher nochmal der Tipp: Geh dein Projekt und dein Vorhaben nochmal analytisch durch. Denn wenn du nicht weißt, warum und weshalb etwas geht oder nicht geht, dann weil dir selbst nicht klar ist, was da überhaupt passiert. Und da kommt man dahin, wo wir jetzt sind: Unklare Fragestellung durch unklare Problemformulierung, weil du scheinbar selbst den Überblick irgendwie über das Projekt verloren hast. Oder?

1)
Delphi-Quellcode:
for b := 0 to high(Kreis) do
Warum 0 to ... und nicht Low(Kreis) to ...?

2)
Delphi-Quellcode:
With Kreis [b] do
    begin
      Left := Kreis [b].x;
      Top := Kreis [b].y;
    end;
Wo wird Width und Height gesetzt?

DelphiUser1 16. Nov 2012 18:11

AW: Geschwindigkeit umkehren
 
Liste der Anhänge anzeigen (Anzahl: 1)
Okay alles klar, ich habe den ganzen Kram mal angehängt

Bummi 16. Nov 2012 18:44

AW: Geschwindigkeit umkehren
 
Die Bitmapprobleme hat ja Sir Rufo bereits beantwortet.
Das Klebeproblem lässt sich hierdurch beseitigen, allerdings ist das noch nicht final, da durch die Bedingungen Kollisionen z.B. oben und rechts gleichzeitig gefunden werden, was zu einer optisch nicht nachzuvollziehenden Reflexion führt. Ich habe leider jetzt nicht mehr die Zeit mir eine brauchbare Bedingung zu suchen. Aber wir haben ja genügend Mitstreiter hier ...
Delphi-Quellcode:
    if InterSectRect(Stubrect, Kreis[b].BoundsRect, Image3.BoundsRect) and Image3.Visible then // Box
    begin

      if ((Kreis[b].y + Kreis[b].Height) > Image3.top) or (Kreis[b].y <= (Image3.top + Image3.Height))  then
        Kreis[b].speedy := -Kreis[b].speedy;

      if ((Kreis[b].x + Kreis[b].Width) > Image3.left) or (Kreis[b].x <= (Image3.Left + Image3.Width)) then
        Kreis[b].speedx := -Kreis[b].speedx;
    end;


    Kreis[b].x := Kreis[b].x + Kreis[b].speedx;
    Kreis[b].y := Kreis[b].y + Kreis[b].speedy;

DelphiUser1 16. Nov 2012 22:07

AW: Geschwindigkeit umkehren
 
Danke trotzdem für die ganze Mühe :-D
Mit diesem Code funktoniert die Kollision leider nicht wie gewollt (altes Problem, Einfallswinkel=Einfallswinkel) und manchmal bleibt ein Kreis hängen. Aber ich bin schon ein Stück weiter, danke dafür.
Haben die Anderen den vielleicht noch Ideen, dass zu realisieren?
Ist wichtig und sollte bis Montag fertig sein, wenn möglich

Bjoerk 16. Nov 2012 23:51

AW: Geschwindigkeit umkehren
 
Den elastischen Stoß hab' ich hier mal gepostet:

http://forum.delphi-treff.de/showthr...2-Bewegte-B%#9

Gruß
Thomas

DelphiUser1 17. Nov 2012 11:58

AW: Geschwindigkeit umkehren
 
@Bjoerk: So ganz blicke ich bei dem Code noch nicht durch. Mit Matrizen habe ich mich noch nicht beschäftigt

DelphiUser1 20. Nov 2012 21:51

AW: Geschwindigkeit umkehren
 
Hat nicht noch Jemand eine Lösung.
Der Code von Bummi lässt die Kreise in die selbe Richtung zurückprallen aus der sie kamen, aber wie bereits gesagt, ich will eine Einfallswinkel=Ausfallswinkel Kollision und zudem müsste das Bug Problem behoben werden: Wenn man den Block zu schnell bewegt, bleiben die Kreise darin hängen :/

Medium 20. Nov 2012 22:15

AW: Geschwindigkeit umkehren
 
Es wurden doch etliche Lösungsansätze geposted, und sogar ein gutes Stück Code verlinkt. Mach dich doch erstmal an die Umsetzung dieser Ideen (es sind die richtigen, sei versichert), und wenn dabei konkrete Probleme auftauchen, reden wir hier weiter.

Bummi 20. Nov 2012 22:24

AW: Geschwindigkeit umkehren
 
Liste der Anhänge anzeigen (Anzahl: 1)
Durch die Geschwindigkeit bekommst Du wie gesagt bei einem Treffer in der Auswertung für x und y Überschneidungen. Ein recht brauchbarer Weg könnte es sein statt der Region die Du jetzt verwendest 4 Regions je 1 Pixel hoch(horizontal) bzw. breit(vertikal) und Kantenlänge - Geschwindigkeit * 2 , zentriert auf den Kanten, in der anderen Dimension zu verwenden.

Dann sollte ein CombineRegion nacheinander über die 4 Seiten die richtige Auswertung zulassen.

DelphiUser1 20. Nov 2012 22:50

AW: Geschwindigkeit umkehren
 
Hmm das klingt schon sehr gut, aber wie soll ich das denn umsetzten. Ehrlich gesagt, fällt mir da jetzt so direkt keine konkrete Umsetzungsmöglichkeit in Delphi ein :?
Tut mir leid, dass ich nicht so der Profi bin, ich tue schon alles Mögliche, um mein Delphi Wissen zu steigern :oops:

Bummi 20. Nov 2012 23:17

AW: Geschwindigkeit umkehren
 
Du kannst behelfsweise auch mit InterSectRect an der Stelle weiterabeiten, dann sind es halt 4 Rects statt 4 Regions ,der Kreis durch das umhüllende Rect etwas verfälscht abgefragt, bei kleineren Radien fällt das aber kaum auf.
Wenn Du Dir die Regions ansehen willst, kannst Du Dich dort http://msdn.microsoft.com/de-de/libr...(v=vs.85).aspx mal durchhangeln ... DeleteObj nicht übersehen.

Bjoerk 21. Nov 2012 10:46

AW: Geschwindigkeit umkehren
 
Ich hab mir deinen Code jetzt nicht näher angeschaut, aber bei solchen Kollusionen gibt es i.d.R. folgende Punkte zu beachten.
1.) Der Timer läuft auf, weil er sehr schnell eingestellt ist. Das kann man leicht beheben, indem man am Anfang der OnTimerRoutine den Timer disabled und am Schluß der Routine wieder auf enabled setzt.
2.) Die Bälle, Kugeln ect. laufen ineinander. Das ist schon etwas schwieriger. Hier kann man mit einer function IsFreePlace(X, Y) prüfen, bevor man die Kugel an eine bestimmte Stelle setzt.
3.) Die Kollusion wird nicht erkannt, weil der Timer sehr schnell eingestellt ist und auch hier laufen die Kugeln manchmal ineinander. Da kann man zum Beispiel einen Zug im Voraus denken und mit diesen Koordinaten auf Kollusion prüfen (in meinem Code die NextBalls).
4.) Wenn dir der elastische Stoß mit Berücksichtigung der Massen zu kompliziert ist bzw. wenn alle Kugeln die gleiche Masse haben, kannst du die Geschwindigkeiten der beiden Kugeln einfach austauschen.
5.) Bei Kollusion mit einer Wand wird die entsprechende Geschwindigkeit umgedreht.

Gruß
Thomas

PS.: Etwas einfacher zu handhaben als InterSectRect ist:

http://www.delphi-treff.de/tipps/gra...e-kollidieren/


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:22 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz