Zwei Fragen: 1.) Kollision Ellipse(Kugel) mit Rechteck, 2.) FPS

  • Hallo!

    Ich habe 2 Fragen:

    1.) Ich mache gerade eine eigene Version des Spiels Breakout und es klappt bis jetzt ganz gut. Die Kollision des Balles mit den Wänden und dem Schläger funktioniert, leider aber nicht die des Balles mit den Ziegelsteinen.

    Vorweg ein paar Infos:

    Den Ball

    [autoit]

    Global $ball[3] = [200, 300, 20] ; x, y, width
    Global $ballSpeed = 8
    Global $ballVX = $ball[0]
    Global $ballVY = $ballSpeed

    [/autoit]


    zeichne ich mit

    [autoit]

    _GDIPlus_GraphicsFillEllipse($hGraphics, $ball[0], $ball[1], $ball[2], $ball[2], $brush_ball)

    [/autoit]

    Die Ziegelsteine

    [autoit]

    Global $brick_width = 50
    Global $brick_height = 25

    [/autoit][autoit][/autoit][autoit]

    Dim $bricks[10][4] ; [amount of bricks][x, y, brush, life]
    For $i = 0 To UBound($bricks)-1
    $bricks[$i][0] = 10 + $i * ($brick_width+5)
    $bricks[$i][1] = 10
    $bricks[$i][2] = 0 ; Dies hier kann ignoriert werden. Ursprünglich wurde hier der Brush festgelegt, jetzt steht hier einfach
    ; zu Demonstrationszwecken 0, da ich alle Ziegel mit dem selben Brush $brush_brick färbe (s. unten)
    $bricks[$i][3] = 1 ; der Einfachheit halber haben alle Ziegelsteine jeweils 1 Leben
    Next

    [/autoit]


    zeichne ich mit

    [autoit]

    For $i = 0 To UBound($bricks) - 1
    If $bricks[$i][3] > 0 Then _GDIPlus_GraphicsFillRect($hGraphics, $bricks[$i][0], $bricks[$i][1], $brick_width, $brick_height, $brush_brick)
    Next

    [/autoit]

    Nach den ganzen Kollisionschecks setze ich die Koordinaten des Balles neu:

    [autoit]

    $ball[0] += $ballVX
    $ball[1] += $ballVY

    [/autoit]

    So, jetzt zu dem Problem mit der Kollision Ball mit bricks:

    [autoit]

    For $i = 0 To UBound($bricks)-1
    If $bricks[$i][3] > 0 Then
    If $ball[1] <= $bricks[$i][1] + $brick_height And $ball[1] >= $bricks[$i][1] Then
    If $ball[0] + $ball[2] >= $bricks[$i][0] And $ball[0] <= $bricks[$i][0] + $brick_width Then ; von unten
    $ballVY = -$ballVY
    Else ; von links
    $ballVX = -$ballVX
    EndIf
    $bricks[$i][3] -= 1 ; 1 Leben vom Stein abziehen, geht aber auch nicht (es wird komischerweise von der kompletten Reihe 1 Leben abgezogen)
    ElseIf $ball[1] + $ball[2] >= $bricks[$i][1] And $ball[1] <= $bricks[$i][1] Then ; von oben
    If $ball[0] + $ball[2] >= $bricks[$i][0] And $ball[0] <= $bricks[$i][0] + $brick_width Then
    $ballVY = -$ballVY
    Else ; von rechts
    $ballVX = -$ballVX
    EndIf
    $bricks[$i][3] -= 1 ; 1 Leben vom Stein abziehen
    EndIf
    EndIf
    Next

    [/autoit]

    Die ist total bugged.... aber ich komme einfach nicht weiter
    Was ich sagen kann ist, dass es funktioniert, dass, wenn der Ball von oben oder unten auf einen Ziegelstein trifft, er die Richtung entsprechend ändert. Manchmal jedoch schlüpft er einfach durch die nur einige Pixel großen Lücken zwischen den Steinen.
    Naja und der Check von links/rechts funnktioniert nur sehr bugged....

    2.) Im Moment sind die FPS während eines Spiels mit z.B. 120 bricks ca. 32. Wenn aber einige bricks zerstört wurden und demnach nicht mehr gezeichnet werden (s. oben), steigen die FPS auf ein maximum von ca. 64 (wenn alle bricks zerstört wurden).

    Dagegen hätte ich absolut nichts, wenn das komplette Spiel dadurch nicht schneller würde... es wird dann alles doppelt so schnell dargestellt und das möchte ich verhindern, aber wie? Vielleicht manuell die FPS senken? Hm...

    Ich wäre sehr dankbar für eure Hilfe

  • Bei 1 kannst du es vielleicht vereinfachen mit dem Script

    Bei 2 würde es glaub ich so klappen:

    [autoit]


    $Sleep=70;beispiel

    [/autoit][autoit][/autoit][autoit]

    While 1
    $Timer = TimerInit
    ;Dein Script
    Sleep($Sleep-TimerDiff($Timer))
    WEnd

    [/autoit][autoit][/autoit][autoit][/autoit]

    Sind TV-Quizfragen zu einfach? A) Ja B) Harry Potter

    Spoiler anzeigen

    Ich gebe zu dieser Post hat wahrscheinlich nicht viel geholfen,
    aber ich versuche wenigstens zu helfen :rolleyes:

  • Hi,

    Zitat

    Die Kollision des Balles mit den Wänden und dem Schläger funktioniert, leider aber nicht die des Balles mit den Ziegelsteinen.

    Einfach bei der Kollisionsabfrage die Breite und Höhe der Steine größer machen, so daß keine "Lücke" entsteht.

    [autoit]

    And $ball[0] <= $bricks[$i][0] + $brick_width + 5 Then

    [/autoit]

    Die Größen können ruhig überlappen, das führt dann dazu, dass bei einem Treffer der "Lücke" beide Steine verschwinden.

    Zitat

    Vielleicht manuell die FPS senken? Hm...

    sleep(25) beschränkt die FPS auf 40, egal wie schnell der Code ist. Ich würde aber per adlib eine Funktion einbauen, die den Parameter für Sleep() dynamisch anpasst. Die FPS sind eigendlich egal, solange sich die Geschwindigkeit des Balles nicht ungewollt ändert.

  • Danke für eure Antworten.

    Der Kollisionscheck funktioniert immer noch nicht, aber ich werde es weiter versuchen!

    Zu den FPS: Andy, könntest du vielleicht ein Mini-Beispiel machen mit der dynamischen Anpassung? Ich weiß gerade überhaupt nicht wie es das angehen sollte. Ich habe das mal mit Sleep(25) ausprobiert, aber das ist mit einfach zu... wie soll ich sagen, stockig und träge.
    Ich würde also gerne mein Sleep(10) behalten und dann eine adlib Funktion haben.

    Spoiler anzeigen
    [autoit]

    AdlibRegister("MyAdlib")

    [/autoit] [autoit][/autoit] [autoit]

    Func MyAdlib()
    ;... execution must be non blocking, avoid ...Wait(), MsgBox(), InputBox() functions
    If WinActive("Error") Then
    ;...
    EndIf
    EndFunc ;==>MyAdlib

    [/autoit]
  • Am besten misst du die Zeit in der Schleife mit TimerInit und TimerDiff.
    Bei einer Framerate von 40 machst du ein Sleep mit (25 - TimerDiff)

    Das fiese daran ist, dass ein Sleep(1) genausoviel Zeit benötigt wie Sleep(10), also hast du trotzdem eine Schwankungsbreite von 10ms.
    evtl. hilft hier die Funktion HighPrecisionSleep (hier im Forum zu finden), oder du machst es etwas anders:

    Sleep(10), wenn gemessene Zeit <= 15
    Wenn Zeit >= 25ms, dann werden die Berechnungen ausgeführt.
    (Wenn ich mich richtig erinnere, ist dies die Methode, wie ich sie bei SuperMario verwendet hab)


    Zum KollisionsCheck:
    Du könnest die Bricks in Gruppen verwalten. z.B. alle Bricks einer Zeile gehören zusammen.
    Somit kannst du die ganze Gruppe überspringen, wenn die Y-Koordinate des Balles nicht passt. anstatt jedesmal einen kompletten Kollisionscheck durchzuführen...


    E

  • Zu dem was eukalyptus geschrieben hat, kannst du dir auch das Spiel "Arena Fight" in meiner Signatur anschauen. Dort verwende ich die "HighPrecisionSleep" Methode mit Timern um die Framerate möglichst nahe am Sollwert zu halten.
    Außerdem gibt es die Möglichkeit, alle Geschwindigkeiten von Objekten Zeitbasiert und nicht Framebasiert zu verarbeiten. Dann sind FPS und Geschwindigkeit der Objekte unabhängig voneinander.
    Genau das hab ich auch in Arena Fight gemacht, weil die Framerate dort frei einstellbar ist, und einen viel zu großen Einfluss auf den Spielverlauf hätte.

  • Ah okay, danke für die Antworten!

    Ich werde das mal in den nächsten Tagen ausprobieren und gucken, ob ich es hinbekomme.

    Vielen Dank