Collisions Detection für ein Jump 'n' Run - Hilfe

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 13 Antworten in diesem Thema. Der letzte Beitrag () ist von ClonkAndre.

    Collisions Detection für ein Jump 'n' Run - Hilfe

    Hallo liebe Community!

    Ich entwickle momentan ein Jump 'n' Run Game, soll so ähnlich werden wie The Impossible Game.
    Ich bin auch schon zu 90% fertig aber ein wichtiges Problem besteht noch undzwar, ich habe mir auch für mein Spiel einen Editor gebaut das halt andere Leute für das Spiel Levels erstellen können.
    In dem Editor kann man halt Blöcke platzieren und der Spieler kann durch die Blöcke nicht hindurchfallen.

    In meinem Spiel werden Block zu Block die "Blöcke" erstellt und in ein "map" Panel hineingeladen.
    Jenach Block-Typ werden die PictureBoxen anders bennant. Beispiel: Jeder Block bekommt den Namen: block, jedes Hinderniss bekommt den Namen: spike

    Jeden erstellten Block kommt in einer List(of PictureBox)

    Dies ist mein bisheriger Collisions-Code:

    VB.NET-Quellcode

    1. Private IsJumping as Boolean = False
    2. Private grounds As New List(Of PictureBox) ' Grounds
    3. Private Sub checker_tmr_Tick(sender As Object, e As EventArgs) Handles checker_tmr.Tick ' Interval = 1
    4. Try
    5. For x = 0 To grounds.Count
    6. If not player_pb.Bounds.IntersectsWith(grounds(x).Bounds) Then
    7. down_tmr.start() ' Lässt den Spieler sinken
    8. IsJumping = True ' Setzt die Variable "IsJumping" auf True damit man weiß das er sich gerade in der Luft befindet
    9. Next
    10. Catch ex As Exception
    11. 'Fehler
    12. End Try
    13. End Sub
    14. ' Dies ist der down Timer (wird auch für den springen Timer benutzt)
    15. Private Sub down_tmr_Tick(sender As Object, e As EventArgs) Handles down_tmr.Tick ' Interval = 1
    16. Try
    17. player_pb.Top += 5
    18. For x = 0 To grounds.Count
    19. If player_pb.Bounds.IntersectsWith(grounds(x).Bounds) Then
    20. 'Rotate_tmr.Stop()
    21. 'player_pb.BackgroundImage = RotateImage(0, Color.Transparent, My.Resources.player_1)
    22. down_tmr.Stop()
    23. isJumping = False
    24. End If
    25. Next
    26. Catch ex As Exception
    27. 'Fehler
    28. End Try
    29. End Sub


    Falls Ihr mehr Code benötigt bitte schreiben.
    Hoffentlich könnt Ihr mir helfen!! :)
    Wenn ich dir auf irgendeiner Art und Weise helfen konnte, drück doch bitte den "Hilfreich" Button :thumbup:

    Für VB.NET Entwickler: Option Strict On nicht vergessen!
    Zeile#4, #12, #14: Fange nur Exceptions ab, die Du kennst und sinnvoll bearbeiten kannst. Aber allein, dass Du fehlerhafterweise von 0 bis grounds.count zählst (genauso Z#21), reicht schon für nen Fehler aus, da Du hier nur bis .Count - 1 zählen darfst.
    Wofür sind checker_timer und down_timer? Es braucht für Physik immer nur einen einzigen Timer, in dem alles passiert. Und zwar wird an alle Objekte ein Befehl gesendet, z.B. Spieler: falle herunter. Du hast aber gar keine Objekte. Das Ziel ist schon, dass Du objektorientiert arbeitest, oder?

    ClonkAndre schrieb:

    Jeden erstellten Block kommt in einer List(of PictureBox)
    Oh, bitte nicht. Du brauchst immer nur so viele PicBoxen wie Objekte auf dem Screen sind. PicBoxen sollten nur so viele erstellt werden, wie gleichzeitig auf dem Schirm sichtbar sind - falls man überhaupt PicBoxen hernehmen will. Sowas lässt sich schließlich auch anders realisieren. Und wenn man dann PicBoxen hernimmt, dann am besten wiederverwenden, bevor man 1000 im Voraus erstellt und die entsorgt, wenn sie vom Screen runter sind.
    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.
    Ich weiß die Try-Blöcke sind recht sinnlos gesetzt..
    Also der checker_timer ist dafür da das er die Collision überprüft und der down_timer ist dafür da das wenn der Spieler springt das er wieder auf eine Platform landet. Was ich dazu sagen muss hier einmal mein Code zum springen:

    VB.NET-Quellcode

    1. Private Sub Jump_tmr_Tick(sender As Object, e As EventArgs) Handles Jump_tmr.Tick
    2. Static x As Integer = 0
    3. If x < 20 Then
    4. player_pb.Top -= 5
    5. Else
    6. Jump_tmr.Stop()
    7. down_tmr.Start()
    8. x = 0
    9. End If
    10. x += 1
    11. End Sub
    12. ' In kombination mit:
    13. Private Sub down_tmr_Tick(sender As Object, e As EventArgs) Handles down_tmr.Tick
    14. player_pb.Top += 5
    15. For x = 0 To grounds.Count - 1
    16. If player_pb.Bounds.IntersectsWith(grounds(x).Bounds) Then
    17. 'Rotate_tmr.Stop()
    18. 'player_pb.BackgroundImage = RotateImage(0, Color.Transparent, My.Resources.player_1)
    19. down_tmr.Stop()
    20. isJumping = False
    21. End If
    22. Next
    23. End Sub
    24. ' Funktioniert Perfekt!


    Wenn ich mein Spieler springen lasse dann fällt er komischerweise durch keinen Block durch wenn ich aber konstant abfrage mit einem Timer ob er jetzt mit einem Boden in berührung ist dann fällt er einfach durch
    (hoffentlich verständlich)

    Die Picboxen sollen wenn sie außerhalb des bildes sind sollen sie entfernt werden damit sie nicht unötig resourcen fressen.

    // Edit: Ich weiß das ein Spiel mit Controls schrecklich ist aber ich wollte es mal austesten und das ist das erstmal das ich mich an so etwas rantraue ;) Und ganz wichtig: Das ich es auch durchziehe das mal fertig zu bauen.
    Wenn ich dir auf irgendeiner Art und Weise helfen konnte, drück doch bitte den "Hilfreich" Button :thumbup:

    Für VB.NET Entwickler: Option Strict On nicht vergessen!

    ClonkAndre schrieb:

    Ich weiß die Try-Blöcke sind recht sinnlos gesetzt.
    Wenn Du das schon vor Deinem ersten Post hier wusstest, stellt sich natürlich die Frage, warum sie überhaupt noch im Code sind. Daher gehe ich mal davon aus, dass Du es zwar ggf. ein bisschen im Hinterkopf hattest, aber Dich noch nicht um eine Alternative gekümmert hast.

    Static x As Integer = 0Ja gut ähh... OOP, wo bist Du?

    Ok, welcher Teil genau funktioniert nicht so wie gewünscht? down_tmr-Tick? Gibt es Phasen im Spiel, wo der Spieler und einer der Böden sichtbar überlappen? Der Spieler also im Boden steckt oder durchfällt? OK, ja gibt es, erwähntest Du ja, aber ist es manchmal auch ein Steckenbleiben im Boden?
    btw: Hast Du mal nen Screenshot, wo das passiert?

    ClonkAndre schrieb:

    Die Picboxen sollen wenn sie außerhalb des bildes sind sollen sie entfernt werden damit sie nicht unötig resourcen fressen.
    Das machen sie eh schon, weil sie ja schon im Voraus erschaffen werden.

    ##########

    @ClonkAndre:
    Ach, Moment mal. Wahrscheinlich liegt es einfach an Folgendem: Wenn der Spiele auf dem Boden steht, dann ergibt IntersectsWith ein False. Daher wird der down_Timer aktiviert und die Spielerposition um 5 Pixel nach unten verschoben. Du musst es schon so machen, dass Die Y-Position auf eine Nicht-Intersection-Y-Position des Spielers korrigiert wird, wenn eine Intersection auftritt. Klar, dadurch ist der Down-Timer natürlich daueraktiv. Aber das sagte ich ja schon: Es braucht nur einen Timer, in dem die ganze Physik abgehandelt wird* (im Timer_Tick wird natürlich dann nur an alle Objekte gemeldet, dass die sich selbst um ihre Physik kümmern sollen, aber das ist ein anderes Thema, wenn wir dann irgendwann mal bei OOP sind ;) )
    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.

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „VaporiZed“ ()

    VaporiZed schrieb:

    Das machen sie eh schon, weil sie ja schon im Voraus erschaffen werden.

    Jaaaaa das stimmt ^^

    Also ich würde sagen im "checker_timer" hab ich das Problem mit dem überprüfen der Collision.
    Moment mit Screenshots alleine kann ich es nicht so gut erklären einen Moment bitte :)

    // EDIT:
    Hier nun meine Erklärung:
    Wenn ich dir auf irgendeiner Art und Weise helfen konnte, drück doch bitte den "Hilfreich" Button :thumbup:

    Für VB.NET Entwickler: Option Strict On nicht vergessen!

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ClonkAndre“ () aus folgendem Grund: Link hinzugefügt

    Argh, ja klar: Deine Codelogik ist falsch. Du schreibst ja: "Wenn es keine Kollision mit Boden X gibt, dann falle". Das ist aber falsch. Du musst schreiben, dass er fallen soll, wenn er mit gar keinem Objekt/Boden kollidiert. Aber bei Deiner Logik würde der Spieler nur dann nicht fallen, wenn er mit allen Böden in Kontakt ist - was ja praktisch gar nicht möglich ist.
    btw: Im ersten Teil des Videos, sieht man, dass Dein Code eben nicht funktioniert, da der Spieler am Ende über den letzten Block schwebt, eben weil keine dauerhafte Kollisionserkennung stattfindet. Damit wären wir wieder beim Physiktimer ;)
    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.

    VaporiZed schrieb:

    eben weil keine dauerhafte Kollisionserkennung stattfindet


    Wie meinst du das? :)
    Ach ok ja das stimmt..

    Wie kann ich das denn verhindern das er nur dann nicht fällt wenn er mit wirklich allen Böden in berührung ist?
    Da häng ich ja schon seit gestern dran coden ist anstrengend^^

    //Edit

    VaporiZed schrieb:

    "Wenn es keine Kollision mit Boden X gibt, dann falle". Das ist aber falsch. Du musst schreiben, dass er fallen soll, wenn er mit gar keinem Objekt/Boden kollidiert


    Ach klaro... Aber wie könnte man das verwirklichen?
    Wenn ich dir auf irgendeiner Art und Weise helfen konnte, drück doch bitte den "Hilfreich" Button :thumbup:

    Für VB.NET Entwickler: Option Strict On nicht vergessen!

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „ClonkAndre“ ()

    Logik umkehren, wie gesagt.

    VB.NET-Quellcode

    1. Private Sub checker_tmr_Tick(sender As Object, e As EventArgs) Handles checker_tmr.Tick
    2. For Each ground In grounds 'da der Bodenindex nicht gebraucht wird, hab ich ne For-Each-Loop draus gemacht
    3. If player_pb.Bounds.IntersectsWith(grounds(x).Bounds) Then Exit Sub 'grounds(x) ist falsch, ground ist korrekt, s. Post#10
    4. Next
    5. IsJumping = True
    6. End Sub

    oder mit LINQ:

    VB.NET-Quellcode

    1. Private Sub checker_tmr_Tick(sender As Object, e As EventArgs) Handles checker_tmr.Tick
    2. If Not grounds.Any(Function(x) player_pb.Bounds.IntersectsWith(x.Bounds)) Then IsJumping = True
    3. End Sub

    oder noch kürzer:

    VB.NET-Quellcode

    1. Private Sub checker_tmr_Tick(sender As Object, e As EventArgs) Handles checker_tmr.Tick
    2. IsJumping = Not grounds.Any(Function(x) player_pb.Bounds.IntersectsWith(x.Bounds))
    3. End Sub


    (da ich Not ...Any() in meinem Code nicht so toll finde, hab ich mir ne billige None-Extension gemacht, aber das ist ne andere Geschichte)

    ##########

    Die letzte Variante ist zuviel gekürzt, da es die Logik verändert.
    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.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „VaporiZed“ ()

    Ahhh ok danke für deinen Code ich versuche ihn mal richtig einzusetzen

    // Edit
    Bei der For-Each Variante steht in den Klammern ja (grounds(x).Bounds)
    muss ich diese Variante in den For i = 0 to grounds.count - 1 Block setzen?
    Also so:

    VB.NET-Quellcode

    1. For x = 0 to grounds.count - 1
    2. for each ground in grounds
    3. If player_pb.Bounds.IntersectsWith(grounds(x).Bounds) Then Exit sub
    4. next
    5. next


    Wenn ich dir auf irgendeiner Art und Weise helfen konnte, drück doch bitte den "Hilfreich" Button :thumbup:

    Für VB.NET Entwickler: Option Strict On nicht vergessen!
    Ah, zu spät am Abend. Korrekt muss es da heißen:

    VB.NET-Quellcode

    1. Private Sub checker_tmr_Tick(sender As Object, e As EventArgs) Handles checker_tmr.Tick
    2. For Each ground In grounds 'da der Bodenindex nicht gebraucht wird, hab ich ne For-Each-Loop draus gemacht
    3. If player_pb.Bounds.IntersectsWith(ground.Bounds) Then Exit sub
    4. Next
    5. IsJumping = True
    6. End Sub
    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.
    Danke @VaporiZed !
    Es funktioniert nun perfekt :D
    Sobald mein Spiel fertig ist werde ich es hier im Forum veröffentlichen und ich habe schon eine coole Idee hehe ;)
    Wenn ich dir auf irgendeiner Art und Weise helfen konnte, drück doch bitte den "Hilfreich" Button :thumbup:

    Für VB.NET Entwickler: Option Strict On nicht vergessen!

    ClonkAndre schrieb:

    Es funktioniert nun perfekt
    Das werden die Tester bestimmt anders sehen ;)
    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.
    Ich hoffe einfach mal es fällt nicht auf ^^ (Trollfacegesicht bitte hier einfügen)
    Wenn ich dir auf irgendeiner Art und Weise helfen konnte, drück doch bitte den "Hilfreich" Button :thumbup:

    Für VB.NET Entwickler: Option Strict On nicht vergessen!