Hilfe bei Erstellung einer Kollisionserkennung

  • VB.NET

Es gibt 10 Antworten in diesem Thema. Der letzte Beitrag () ist von Sneeze.

    Hilfe bei Erstellung einer Kollisionserkennung

    Hallo,

    ich habe Probleme bei der Erstellung eines Pong-Spiels bzw. das Spiel funktioniert eigentlich - allerdings nur solange es bei einer Geschwindigkeit bleibt. Allerdings habe ich vor das der Ball über die Zeit immer schneller wird und auch ungewohnte Bewegung durchführt - aber meine "Kollisionserkennung" die ich zusammengeflickt habe kommt damit nur schwer klar. Manchmal schlägt es den Ball zurück und manchmal nicht - ich muss dazu sagen das ich sehr schlecht in Mathe bin (Hatte gute Noten zur Schulzeit, aber nie das Gefühl etwas gut zu verstehen).

    Die wichtigsten Variabeln erklärt:

    Playerx: Position der X-Kooridnate vom Spielerschläger
    Playery: Position der Y-Kooridnate vom Spielerschläger
    SchlägerhöheS: So groß ist der Schläger des Spielers
    Geschwindigkeitsveränderung: Die Höhe der Geschwindigkeitszunahme
    Abweichungy: Veränderung in Y-Richtung (des Balles), der Wert wird durch eine Formel errechnet und dann durch 100 geteilt
    Sieg: Führt die Siegesklasse aus, es gibt 2 Aktionsmöglichkeiten
    Richtung: 0 und 1 (links und rechts)

    Das Spielfeld ist ein doublebuffered Panel - das Spielfeld lässt sich frei vergrößern und ist nicht fix, fast alle Variabeln passen sich dann an. Schläger und Ball werden im Paint Event gezeichnet - wodurch ich dachte das es logisch ist in Intervallen Überschneidungen zu überprüfen:

    (Mir ist bewusst das Csng, etc. nicht optimal ist)

    VB.NET-Quellcode

    1. 'Kollision mit Spieler
    2. If ballx <= (Playerx + (Ballgröße + 1)) And Bally >= (Playery - (Ballgröße + 1)) And Bally <= (Playery + (SchlägerhöheS - 1)) Then 'untere Seite!
    3. Speed += Geschwindigkeitsveränderung
    4. Richtung = 0
    5. 'Aber der oberen Hälfte geht der Ball (Y) nach oben, ansonsten nach unten
    6. If Bally >= Playery + (SchlägerhöheS / 2) Then RichtungY = 0 : YKurve += CSng((Abweichungy / 100)) Else RichtungY = 1 : YKurve += CSng((Abweichungy / 100))
    7. 'Sicherheitsabfrage
    8. If ballx < (Spielfeld.Location.X - Ballgröße) Then
    9. Speed = Grundspeed
    10. Niederlage(0)
    11. Exit Sub
    12. End If
    13. 'Kollisionsabfrage Computer + Ball
    14. ElseIf ballx >= (Computerx - (Ballgröße + 1)) And Bally >= (Computery - (Ballgröße + 1)) And Bally <= (Computery + ((SchlägerhöheC - 1))) Then
    15. Speed += Geschwindigkeitsveränderung
    16. Richtung = 1
    17. 'Aber der oberen Hälfte geht der Ball (Y) nach oben, ansonsten nach unten
    18. If Bally <= Computery + (SchlägerhöheC / 2) Then RichtungY = 1 : YKurve += CSng((Abweichungy / 100)) Else RichtungY = 0 : YKurve += CSng((Abweichungy / 100))
    19. 'Sicherheitsabfrage
    20. If (ballx + Speed) > (Spielfeld.Width + 0) Then
    21. Speed = -Grundspeed
    22. Sieg(0)
    23. Exit Sub
    24. End If
    25. 'Sollte der Ball über den "Rand" gehen wird geschaut welcher Rand es ist und abhängig davon wird Sieg oder Niederlage aufgerufen
    26. ElseIf ballx <= (Spielfeld.Location.X - (Ballgröße)) Then
    27. Speed = Grundspeed
    28. Richtung = 0
    29. Niederlage(0)
    30. Exit Sub
    31. ElseIf ballx >= (Spielfeld.Width + (Ballgröße)) Then
    32. Speed = -Grundspeed
    33. Richtung = 1
    34. Sieg(0)
    35. Exit Sub
    36. End If


    Habe ich einen Logikfehler oder ist es normal das ab einer gewissen Geschwindigkeit der Timer nicht mehr hinterherkommt? Habe die Abfrage komplett selbst geschrieben und nicht einfach abkopiert, daher finde ich auch keine Lösung zu diesem Problem - ich habe nur andere Abfragen gesehen die beispielhaft zeigen wie Kreise und Kreise kollidieren.

    Über Ratschläge oder Hinweise wäre ich sehr erfreut.

    Edit:
    Der Ball wird relativ simpel bewegt:

    VB.NET-Quellcode

    1. If Richtung = 0 Then ballx += Speed Else ballx -= Speed 'in X-Richtung
    2. If RichtungY = 0 Then Bally += YKurve Else Bally -= YKurve 'in Y-Richtung

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „Sneeze“ ()

    Spekulatius:
    Das Problem wird sein, dass Du Speed direkt in Deine Berechnungen einbaust. Entweder bin ich zu müde, oder ich sehe nicht die Ballbewegung an sich im gezeigten Code, aber ich vermute trotzdem, dass Speed direkt Teil der Formeln sein wird. Falls Du alt genug bist, kannst Du Dich ggf. an solche Spiele wie in QBasic "Gorilla" erinnern. Da konnte man auch aberwitzige Wurfbananengeschwindigkeiten eingeben, was dazu führte, dass die Dinge nicht an den Häuserwänden, sondern in den Häusern hochgingen. Klar, wenn Du sowas hast wie x = x + Speed und Speed eben nicht 1, sondern 1000 ist, dann wird dann mal schnell ein Hindernis übersprungen. Daher geht es m.E. bei Speed eher darum, die "Berechnungszeiten" zu verkürzen. Also nicht, dass bei zwischen jeder Berechnung z.B. 100 ms liegen, sondern das Intervall speed-abhängig ist. Je höher Speed, desto kleiner das Intervall. Damit der Ball immer zwischen 2 Berechnungen die gleiche Distanz zurücklegt.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    @Sneeze Gehe an die Kollision so heran:
    Dein Körper hat eine Größe, nehmen wir zunächst der Einfachheit halber an, es sei ein Rechteck.
    Wenn vorn eine Wand steht, ist die ebenfalls ein Rechteck.
    Nun kannst Du mit elementaren Mitteln überprüfen, ob beide Rechtecke gemeinsame Punkte haben: If (rc1.IntersectsWith(rc2)) Then
    Bei zwei Kreisen ermittelst Du den Abstand der Mittelpunkte, der muss größer bzw. kleiner sein als die Summe der Radien.
    Bei Kreis gegen Wand muss der Abstand der x-Koordinate größer bzw. kleiner sein als der Radius.
    Andere Geometrien sind da etwas rechenaufwändiger.
    Mach aus Deinen Gegenständen Instanzen von Klassen mit gemeinsamer Basisklasse, die eine Double Methode .Distance(other) und eine Methode .CollisionWith(other) haben.
    Das wird Dir das Programmieren Deines Spiels wesentlich vereinfachen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Packe folgenden Code mal ein einen Timer mit einem Interval von 1 oder so:

    VB.NET-Quellcode

    1. ​If Ball.Bounds.IntersectsWith(Schläger.Bounds) Then
    2. 'ball zurückschlagen
    3. End If


    natürlich noch den Code optimieren :thumbsup:

    ╔══╦═╦╦╦═╦══╦══╦╗╔╦═╦╦═╦══╗
    ║║║║╩╠..╣╦╬╗╚╬╗╔╣╚╝║╠║║║╠╗╚╣
    ╚╩╩╩╩╩╩╩═╩══╝╚╝╚══╩═╩╩═╩══╝
    ich hab auchmal Ansätze eines Pongs geproggtt - mit Wpf ist das ganz schnucklig: Kein Pong - Erstaunliches mit ItemsControl.Itemspanel
    Aber beim Aufprall eines bewegten Balles auf die Ecke eines ebenfalls bewegten Schlägers habich erkannt, dass die dafür nötige Mathematik für mich doch den Rahmen sprengen würde.

    ErfinderDesRades schrieb:

    die dafür nötige Mathematik
    Elementare Vektorrechnung:
    Impulserhaltung (Vektor), Energieerhaltung (Skalar). Und ein wenig Geometrie zur Beschreibung der Räumlichkeiten.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    mit coolen Sprüchen kannste mich nicht weiter beeindrucken.
    Mach es, und bau's im og. Tut ein.
    Die Ball-Klasse steht da ja schon bereit, und funzt, und prallt auch schon von Wänden ab.
    Fehlt noch eine Schläger-Klasse.

    Würde ich sogar dran-bauen, wenn du mir versprichst, dafür die Kollisionen zu übernehmen.

    ErfinderDesRades schrieb:

    bau's im og. Tut ein.
    Is WPF, musste alleine machen. :/
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    RodFromGermany schrieb:

    @Sneeze Gehe an die Kollision so heran:
    Dein Körper hat eine Größe, nehmen wir zunächst der Einfachheit halber an, es sei ein Rechteck.
    Wenn vorn eine Wand steht, ist die ebenfalls ein Rechteck.
    Nun kannst Du mit elementaren Mitteln überprüfen, ob beide Rechtecke gemeinsame Punkte haben: If (rc1.IntersectsWith(rc2)) Then
    Mach aus Deinen Gegenständen Instanzen von Klassen mit gemeinsamer Basisklasse, die eine Double Methode .Distance(other) und eine Methode .CollisionWith(other) haben.
    Das wird Dir das Programmieren Deines Spiels wesentlich vereinfachen.


    Das mit Intersect funktioniert auch super, aber wieder dasselbe Problem. Ab einer gewissen Geschwindigkeit kommen die Timer da nicht mehr hinterher:

    VB.NET-Quellcode

    1. If r1.IntersectsWith(obenPlayer) Then 'Kollision des Balles mit dem oberen Teil des Schlägers
    2. Speed += Geschwindigkeitsveränderung
    3. YKurve += CSng((Abweichungy / 100)) 'Stärke in die es nach oben/unten fliegt
    4. RichtungY = 1 'Oben Y
    5. Richtung = 0 'Nach Rechts X
    6. ElseIf r1.IntersectsWith(untenPlayer) Then 'Kollision des Balles mit dem unteren Teil des Schlägers
    7. Speed += Geschwindigkeitsveränderung
    8. YKurve += CSng((Abweichungy / 100))
    9. RichtungY = 0 'Unten Y
    10. Richtung = 0 'Nach Rechts X
    11. End If


    (R1 = Ball)

    Ist es normal das es irgendwann nicht mehr klappt? Meine Vermutung ist das die Bewegung des Balles, also die Geschwindigkeit irgendwann so schnell ist das es sich um mehr Einheiten als die Größe des Balles/Schlägers bewegt und deswegen einfach durchgeht. Ich muss das nochmal nachprüfen - wenn das wirklich der Fall ist könnte ich den Timer runtersetzen und die Einheiten um die es bewegt wird ebenfalls herabsetzen.

    Aber ich habe gehört das der System.Forms.Timer nicht unter 50 ms geht (selbst wenn man es auf 1 ms stellt sollen es noch 50 ms sein), stimmt das? Der System Timer will ein Threadsicheres aufrufen, weiß nicht...tue mir mit delegates extrem schwer (bisher kein gutes Video dazu sehen können, das mir erklärt warum man es dort reinschreibt. Sondern immer nur jetzt schreiben wir XY hier rein und fertig, aber keine Erklärung warum).

    RodFromGermany schrieb:

    Mach aus Deinen Gegenständen Instanzen von Klassen mit gemeinsamer Basisklasse, die eine Double Methode .Distance(other) und eine Methode .CollisionWith(other) haben.Das wird Dir das Programmieren Deines Spiels wesentlich vereinfachen.


    Hast du dazu ein gutes Tutorial oder ein Beispiel? Bin gewillt mehr dazuzulernen und bisher habe ich nur eigene Klassen geschrieben mit Vererbung. Aber ich verstehe nicht was du mit Gegenständen meinst? Ich zeichne ja die Rechtecke mit GDI+ und lasse dann überprüfen ob sie sich überschneiden - sind die Rechtecke dann die Gegenstände?

    Entschuldige mein Nooblikes Auftreten, und danke dir für deine Antwort und entschuldige mich für meine späte Antwort. Wollte zunächst selbst überlegen was du meintest, habe dazu mich auf msdn.microsoft.com/de-de/library/ms973803.aspx umgeschaut.

    Sneeze schrieb:

    Ab einer gewissen Geschwindigkeit kommen die Timer da nicht mehr hinterher
    Dann sieh Dir mal dies an:
    Kollision und Reflexion - Elastischer Stoß
    Diskussion zum Thema Kollision und Reflexion - Elastischer Stoß
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    *Bitte keine unnötigen Vollzitate*

    Vielen Dank! Das gibt mir unheimlich gute Einblicke und hat mich schon auf ein paar Ideen gebracht! Ich frage mich wo der Hilfreich-Button hin ist, sonst hätte ich den schon mehrfach betätigt.

    Mein erster Lösungsansatz war es die Ball Geschwindigkeit und die noch verbleibende Strecke zu berechnen und daraus eine mögliche Kollision zu bilden/abzuschätzen, aber ich werde mich jetzt erstmal einlesen.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Marcus Gräfe“ ()