Autoit Spiel (Logik)

  • Hey Com :)

    momentan probiere ich ein Spiel zu programmieren, welches eigentlich jeder kennt.
    Es heißt breakout. Eigentlich habe ich schon alles aber ein Bug stört total.

    Wenn sich die Kugel auf ein Objekt (Rechteck) bewegt, muss ich ja wissen, ob es sich oben/unten oder
    links/rechts vom Objekt befindet, sodass ich den Winkel (EInfallswinkel=Ausfallswinkel)
    richtig einstellen kann.

    Das eigentliche Problem besteht darin, dass sich die Kugel ja nicht immer um +1 Koordinaten
    bewegt. Und ich weiß jetzt nicht wie ich das abfragen soll, in welcher Richtung sich die Kugel
    des Objektes befindet, falls sie es berührt, weil theoretisch könnte es ja auch einen Pixel in dem
    Objekt sein und nicht immer genau am Rand vom Objekt. Deswegen habe ich z.B schon versucht,
    einen bestimmten Abstand abzufragen, wo sich die Kugel mit welcher Geschwindigkeit befinden kann,
    wenn es ein Objekt berührt. Aber dann überkreuzen sich die Abfragen und der Winkel stimmt nicht
    mehr, wenn es auf ganz bestimmten Stellen auf das Objekt prallt.

    Ich habe mir mal ein Projekt in C++ angesehen und da wird es so deklariert:

    C
    Dim speed As Single = 5
    Dim xVel As Single = Math.Cos(speed) * speed
    Dim yVel As Single = Math.Sin(speed) * speed


    Aber da gibt es das Problem nicht. Hat jemand damit auch Erfahrungen
    gemacht oder weiß eine Lösung? Ich bin echt ratlos. :|


    Liebe Grüße,
    xSunLighTx3

  • Weiß nicht in wie weit das performant ist, aber eine Möglichkeit wäre es nicht ständig zu prüfen ob eine Kollision stattfindet sonder nach einem Abpraller einmal berechnen wo und wann sie stattfindet. Wenn du weißt wo in der Flugbahn hast du den Winkel und durch die Geschwindigkeit der Kugel weißt du wann sie dort ankommt.

    Andy hat mir ein Schnitzel gebacken aber da war ein Raupi drauf und bevor Oscar das Bugfixen konnte kam Alina und gab mir ein AspirinJunkie.

  • Das eigentliche Problem besteht darin, dass sich die Kugel ja nicht immer um +1 Koordinaten
    bewegt.

    Natürlich tut sie das... :D
    Nur wirst du aus Geschwindigkeitsgründen die DARSTELLUNG DER KUGEL (genauer, des Kreises) immer um mehrere "Pixel" verschieben.
    Da die Berührung des Kreises mit einem der Rechtecke immer nur (idealerweise) an einem Punkt/Pixel stattfindet, ist die Berechnung simpel:

    - Der Kreis besteht aus dem Mittelpunkt C und dem Radius r
    - Das Rechteck besteht aus 4 Eckpunkten ABUW, Teile in 4 Strecken auf: AB,BU,UW,WA

    - Wenn der Abstand des Kreismittelpunktes zu einer der Strecken kleiner/gleich r, gibt es eine Berührung.
    Beispiel für Abfrage, ob der Kreis die Strecke AB berührt, dazu benötigt man nur die Streckenlängen AB, AC und BC (diese Berechnung sollte wohl kein Problem darstellen^^)
    Jetzt zur Auswertung:
    Wenn AC<=r oder BC<=r dann Berührung!

    BC² ist das Quadrat der Strecke BC usw, zuerst wird der Abstand des Kreismittelpunktes C senkrecht zur Strecke AB berechnet:
    x = (BC²-AC²-AB²)/(-2*AB)
    Auswertung:
    Wenn x>=0 und x<=AB und sqrt(AC²-x²)<=r dann Berührung!

    Script:

    //EDIT Beachte die Vereinfachung bei der Rückgabe der Funktion! 1 wenn die Strecke berührt wurde, 2 wenn einer der "Ecken"(Endpunkte) berührt wurden. das braucht man für die anschließende Berechnung der Winkel für den weiteren Flug...


    Die Berechnung, ob die Linie den Kreis berührt, dauert auf meinem Rechner ca. 0.03ms .
    Angenommen, das Spiel enthält 100 "Bricks", das ergibt 400 Linien/Seitenwände a 0.03ms ergibt 12ms für die Berechnung der Kollision ALLER 100 Bricks mit dem Kreis....

    Wenn eine Kollision festgestellt wurde, ist der Rest doch nur noch den weiteren Winkel für die Flugrichtung anpassen. Das kann man sehr leicht machen, denn man weiß ja, ob eine obere, untere, rechte oder linke Seitenwand oder eine "Ecke" (Endpunkt der Strecke) getroffen wurde!


    Alternativ könnte man "Raytraycing" machen, so wie es von Chip vorgeschlagen wurde. Dabei würde man parallele "Strahlen" von der Kreishälfte in Flugrichtung "aussenden" und schauen, wo diese ein (und welches) Objekt/Seitenteil treffen. Auf dem Weg des Kreises bis zum Kollisionspunkt hat man nichts weiteres zu tun als den Kreis darzustellen...
    Es bietet sich an, nicht von jedem Punkt des Halbkreises ein "Ray" auszusenden, je nach Größe des Kreises und der Rechengeschwindigkeit reichen 10-12 Strahlen sicher aus.
    Da nur der Kollisionspunkt "Ray" mit den Seitenwänden abgefragt werden muss (also nur der Schnittpunkt zweier Linien) ist die Berechnung schnell erledigt.
    Wenn man dann noch clever selektiert ("rechte" Seitenwände können nur von einem nach links fliegenden Kreis getroffen werden, "untere" Seitenwände nur von einem nach oben fliegenden Kreis usw.), dann reduziert sich die Berechnung massiv! Dazu noch eine clevere Anordnung der Seitenteile im Array und auch AutoIt hat massig Zeit übrig um für ausreichende FPS zu sorgen :D

  • Das mit den Strahlen hatte ich irgendwo schonmal ausprobiert. Wenn ich mich nicht irre haben 3 Strahlen ausgereicht, nämlich in Flugrichtung mit den Startpunkten Senkrecht links, senkrecht rechts am Kreis und einer in der Mitte. Da man via Vektorrechnung und ohne "feste" Schritte Arbeitet überprüft man nur ob die Strecken (Bewegungsvektoren) andere Strecken schneiden, und das tun sie unabhängig von der Objektgröße.

    Das Vorgehen bei "korrekter" Kollision ist wie folgt: ("Zeit zwischen den Frames" = T = 1)
    - Man hat z.B. 10 Kugeln.
    - Man überprüft ob es im nächsten Frame überhaupt irgendeine Kollision gibt. Wenn nein -> bewegen, fertig. Wenn ja gehts weiter.
    - Man findet die zeitlich gesehen erste Kollision (zum Zeitpunkt t < T) und berechnet diese. Man bewegt alle Kugeln um ihrem Richtungsvektor mit Faktor dt/T.
    - Man führt den vorherigen Schritt solange aus, bis die zeitlich gesehen nächste Kollision bei einem t > T stattfindet. Dann bewegt man die Kugeln noch das kleine Stück (im Normalfall der Faktor 1 - t) bis T voll ist, und hat den zu berechnenden Frame fertig.

    Edit: Das ist hier nur die Weganleitung, wie man die Kollisionen im Konkreten berechnet kann man woanderst nachlesen :P

  • Danke für eure awesome Hilfe. Ich glaube raytraycing ist mir noch zu schwer. :x (Hab mal sowas Ähnliches versucht, aber da bin ich schon mit der DrawLine überfordert, die richtig zu setzen. :D )

    Ich hab das jetzt mal mit einem Rechteck versucht und irgendwie klappt es da nicht. Bestimmt habe ich was falsch gemacht. :o

  • Ich hab das jetzt mal mit einem Rechteck versucht

    Was habe ich denn oben geschrieben?

    Das Rechteck besteht aus 4 Eckpunkten ABUW, Teile in 4 Strecken auf: AB,BU,UW,WA

    Wie soll denn eine Funktion, die Beruehrung_Kreis_Strecke() heißt, etwas anderes machen als den Berührungspunkt von einem Kreis und einer Strecke berechnen?
    DU sollst aus dem Rechteck 4 Strecken(Seitenteile) machen, und die kannst du dann mit der Funktion überprüfen.


    aber da bin ich schon mit der DrawLine überfordert,

    Wenn du mit Trigonometrie, also simplen Sinus, Cosinus, Tangens auch so überfordert bist, solltest du dich dahingehend DRINGEND fit machen....
    Wie siehts damit aus, den Kreis auf einem völlig leeren Spielfeld an den Wänden abprallen zu lassen, bekommst du das hin?

  • Oh Mist, sorry hab das vorhin falsch interpretiert oder war einfach neben der Spur.
    Ich glaube so müsste das ca. stimmen oder? Da fehlen noch die Auswertungen der
    returns von der Funktion Beruehrung_Kreis_Strecke().


    Mit Sin und Cos habe ich schon den Ausfallswinkel berechnet.

    Danke nochmal für die Hilfe!, hast es echt drauf.

  • Hi,
    "so ähnlich" habe ich mir das gedacht ^^
    Allerdings hast du mit AutoIt das Problem, dass du nicht viel Rechenzeit zur Verfügung hast. Daher auch der Hinweis auf die Seitenwände der Rechtcke.
    Deine Funktion _BallHitBrick() funktioniert natürlich nur, weil dein Ball von unten kommt... :Face:
    Fliegt der Ball von oben nach unten, wird die Kollision erst festgestellt, wenn die untere Seitenwand berührt wird :S

    Löse dich von dem RECHTECK!
    Wenn dein Ball nach rechts oben fliegt, kann NIEMALS ein linkes oder ein oberes Seitenteil getroffen werden, die Kollisions-Überprüfung reduziert sich auf die HÄLFTE!!!
    Hast du dir mal Gedanken gemacht, wie du die 100 Rechtecke nacheinander auf Kollision prüfen willst?


    Ich glaube, ich hack mal die 100 Zeilen zusammen um das Spiel zu programmieren^^

  • Die Kollisionsberechnung für 1000 Rechtecke geht in konstanter Zeit und dauert genausolang wie die Kollisionserkenung von einem einzigen Rechteck. Nimm eine Bitmap in Spielfeldgröße mit der Farbe 0x00000000, anschließend nummerierst du alle Rechtecke mit 0x00000001, usw usw und zeichnest diese in die Bitmap. Dann kann man per Pixelgetcolor (oder per Dllstruct, wenn man es schnell haben will) innerhalb weniger Takte wissen ob in der Nähe des Balls ein Rechteck ist. Anschließend überprüft man die Vektorkollision (Also die Rechnung für die Bewegung des Balls) nur mit den Rechtecken die in der direkten Umgebung des Balls sind (sollten immer unter 8 Stück sein, sonst wirds unlogisch :D).

  • Deine Funktion _BallHitBrick() funktioniert natürlich nur, weil dein Ball von unten kommt...
    Fliegt der Ball von oben nach unten, wird die Kollision erst festgestellt, wenn die untere Seitenwand berührt wird

    Maaahlzeit,
    Bei mir funktioniert das (der Ball kommt von oben rechts und fliegt nach unten links)
    [Blockierte Grafik: http://puu.sh/rwfM5/6ee4a62258.png]


    Oder habe ich das falsch verstanden? Das mit der Reduzierung kann man dann ja einbauen,
    wenn:

    AutoIt
    $deg = ACos(-1) / 180
    $ballSpeed = 7
    $ballAngle = 270
    $ballX1 += Cos($ballAngle * $deg) * $ballSpeed
    $ballY1 -= Sin($ballAngle * $deg) * $ballSpeed


    berechnet ist. :D


    Zitat von Andy

    Hast du dir mal Gedanken gemacht, wie du die 100 Rechtecke nacheinander auf Kollision prüfen willst?

    Man könnte ja die Distanz berechnen: d=sqrt( (x2−x1)²+(y2−y1)² )
    Aber ob das viel schneller ist, weiß ich auch nicht ehrlich gesagt. :D


    Zitat von Mars

    Die Kollisionsberechnung für 1000 Rechtecke geht in konstanter Zeit und dauert genausolang wie die Kollisionserkenung von einem einzigen Rechteck. Nimm eine Bitmap in Spielfeldgröße mit der Farbe 0x00000000, anschließend nummerierst du alle Rechtecke mit 0x00000001, usw usw und zeichnest diese in die Bitmap. Dann kann man per Pixelgetcolor (oder per Dllstruct, wenn man es schnell haben will) innerhalb weniger Takte wissen ob in der Nähe des Balls ein Rechteck ist. Anschließend überprüft man die Vektorkollision (Also die Rechnung für die Bewegung des Balls) nur mit den Rechtecken die in der direkten Umgebung des Balls sind (sollten immer unter 8 Stück sein, sonst wirds unlogisch :D).


    Hätten die dann nicht alle Rechtecke eine Farbe oder makiert man das intern?

    Einmal editiert, zuletzt von xSunLighTx3 (3. Oktober 2016 um 14:55)

  • Hi,
    hat mir natürlich keine Ruhe gelassen 8o


    Schnell zusammengehackt, ohne den Sleep(1) in Zeile 87 habe ich knapp 500FPS...
    Oben im Script kann man eine Variable $debug setzen, dann sieht man, wie ich versucht habe, die Kollisionsberechnungen zu minimieren.
    Ich detektiere zwei Treffer, einmal auf die Fläche(Linie) eines der Seitenteile und dann die "Ecke". Bei einem Eckentreffer habe ich mir die Winkelberechnung geschenkt (es wird sowieso kein einziger Winkel berechnet!) und den Ball in eine zufällige Richtung zurückgeworfen.
    Es werden nur Kollisionen berechnet, wenn AKTIVE Seitenteile in der Nähe sind. Aktiv heisst, das sind nur die, die aus der Richtung des Balls überhaupt getroffen werden können!
    Diese werden im debug-Modus rot eingefärbt, die "Nähe" für die Kollisionsberechnung wird durch den grünen Kreis sichtbar gemacht.
    Die im Fensterrahmen dargestellten "Misses" sind die Kollisionsberechnungen, welche keinen Treffer ergeben haben.

  • Man kann das natürlich wesentlich vereinfachen, indem man Rechtecke verwendet und für die Kollisionsabfrage auch das oben schon besprochene "Raytracing".
    Allerdings ist das nicht ganz so einfach wie von Mars vermutet. Bei großen Kugeln und kleinen Rechtecken muß man mehrere Strahlen verwenden um den genauen Kollisionspunkt zu finden. Es reicht ja nicht, DASS eine Kollision stattfindet, sondern man muss auch wissen WO! Das wird vor allem dann interessant, wenn sich mehrere Objekte bewegen. Intersection von Rechtecken (der Weg der Kugel beschreibt ja ein Rechteck und der "erste zu treffende" Brick) ist da sicherlich ein Ansatz.

    Mir ging es jedenfalls darum, die "Logik" umzusetzen, so wenige wie möglich Kollisionsabfragen einzubauen. Man wartet so lange, bis Objekte sich in der unmittelbaren Nähe befinden und lässt erst dann eine Kollisionsabfrage laufen.

  • Hallo,

    bitte entschuldigt. Aber vielleicht hilft das hier (in AutoIt geschrieben) weiter. Ich weiß nicht mehr wo ich diese Zip-Datei her habe. Wahrscheinlich aus dem autoitscript.com/forum. Über Google konnte ich es allerdings nicht mehr finden. Jedoch ist es fast genau das, was Du suchst meine ich. Die Zip ist groß (11,7 MB), weil Sound und Bilder integriert sind.

    Hier der Link zu meiner Dropbox: _Arkanoid.rar
    Event. kann mir jemand einen Link nennen, wo ich die Datei sinnvoller hochladen kann damit meine Dropbox nicht überläuft. Ich habe einen eigenen Server, möchte aber mit dem Upload hier keine Werbung für meine HP machen.

    Also, hier der Inhalt der AutoIt Datei:

    Allerdings ist die Geschwindigkeit von Andy's Script mit diesem nicht vergleichbar. Also das Script von Andy läuft bei mir viel flüssiger. Auf meinem Notebook ruckelt es zumindest mit der Arkanoid.au3. Aber ich finde zum einen die Aufmachung und zum anderen die Umsetzung des Spieles sehr gut. Event. könnten sich die Scripte und die Ideen ergänzen.

  • Zum Arkanoid:
    Sehr gut gemacht, eigene Maps supereinfach zu erstellen, klasse Sound, ausreichende Grafik, was will man mehr :thumbup:

    Genau SO muss das aussehen und sich spielen lassen! Dazu noch simpel programmiert, wirklich gute Arbeit!

  • Mal ne doofe Frage, wo nimmt er die Bilder her o,O

    Sieh zu, dass du mal etwas Schlaf bekommst!
    Guckst du Ordner! :Face::rolleyes:

  • "Solo" startet das Script nicht 8) . Vielleicht solltest du doch mal über das Ausschlafen nachdenken, wir haben Wochenende :thumbup:
    "Früher" konnte man mal Programme aus ZIP-Dateien heraus starten, die haben die benötigten Dateien selbstständig aus der ZIP extrahiert....