HoPi's Mixup-Freund - programmierter Practice-Dummy

    Das Hardedge Forum wurde am Abend des 30.01.2023 eingestellt und in ein Archiv umgewandelt. Bitte nicht versuchen sich zu registrieren oder einzuloggen.

    • HoPi's Mixup-Freund - programmierter Practice-Dummy

      Moin,

      wie wir alle wissen, ist der Practice-Dummy ein wenig begrenzt. Schön, dass man mit ihm Aktionen aufnehmen und abspielen kann, aber für einige Sachen braucht man immer noch 'nen menschlichen Gegner. Hier kommt ein kleines Gimmick ins Spiel:

      HoPi's Mixup-Freund

      Die Idee ist, wie bei einem programmierbaren Controller, allerdings als Software-Lösung, den Dummy per Knopf-Druck ein Mixup ausführen zu lassen, dessen Follow-Up zufällig ausgewählt wird. Beispiele dafür: Rufus Dive Kick Follow Up oder Abels CoD.

      Ihr braucht, um diese Sache zu benutzen, nur ein kleines Tool namens GlovePIE. Ursprünglich wurde dieses Tool geschrieben, um Eingaben eines Handschuhs (Essential Reality P5 Gaming Glove) einzulesen: im Skript, das man schreibt, steht, was bei einem Knopf-Druck passieren soll - vergleichbar mit einem Makro-Tool. Bekannt wurde das Programm, weil man damit die Wiimote am PC benutzen konnte, aber das gehört hier erstmal nicht hin :)

      Ihr bekommt das Tool von der Seite des Programmieres: glovepie.org/

      ---

      Um kurz in das Tool einzuweisen, ein kleines Beispiel-Skript:

      Quellcode

      1. keyboard.a = true
      2. wait 100ms
      3. keyboard.a = false


      Nicht wirklich nützlich, aber trotzdem: wenn dieses Skript gestartet wird, hält das Programm die Taste a auf der Tastatur für 100 Millisekunden gedrückt. Clevere Kerlchen ahnen jetzt schon, worauf das hinausläuft ;)

      Bevor ich auf die GlovePIE-Skripte eingehe, müssen die Einstellungen von SF4 evtl. angepasst werden. Steuergerät für Spieler 1 sollte die Tastatur sein (Optionen -> blah...), Spieler 2 bekommt im Trainingsmodus den Joystick. Wichtig ist außerdem, dass ihr für durchgängige 60fps sorgt - warum und was passieren könnte, wenn das nicht der Fall ist, kommt später.

      GlovePIE bietet 'ne umfrangreiche Dokumentation, die man sich gerne mal anschauen darf. Ich gehe hier nur ein wenig auf die Skripte ein, die ich bisher geschrieben habe - zum Starten das Skript einfach laden und oben auf "Run" drücken.

      Nehmen wir an, wir wollen, dass Ryu einen Hadoken macht. Keine unlösbare Aufgabe, oder? Kleine Anmerkung: 2 Schrägstriche deuten auf einen Kommentar hin, der nicht vom Programm ausgewertet wird.

      Spoiler anzeigen

      Quellcode

      1. // Ryu: Hadoken
      2. // Wenn die Shift-Taste auf der Tastatur getippt wird, dann...
      3. if keyboard.shift then begin
      4. // Warte 1 Sekunde
      5. wait 1000ms
      6. // Druecke auf der Tastatur nach unten
      7. keyboard.down = true
      8. wait 1ms
      9. // lasse wieder los
      10. keyboard.down = false
      11. wait 1ms
      12. // Druecke auf der Tastatur nach unten und vorne
      13. keyboard.right = true
      14. keyboard.down = true
      15. wait 1ms
      16. // lasse wieder los
      17. keyboard.right = false
      18. keyboard.down = false
      19. wait 1ms
      20. // Druecke auf der Tastatur nach vorne
      21. keyboard.right = true
      22. wait 1ms
      23. // lasse wieder los
      24. keyboard.right = false
      25. wait 1ms
      26. // Druecke Taste A (Standardbelegung: jab)
      27. keyboard.a = true
      28. wait 1ms
      29. keyboard.a = false
      30. // Warte 1 Sekunde
      31. wait 1000ms
      32. // fertig
      33. end if
      Alles anzeigen


      Ziemlich einleuchtend: das Programm "drückt" die nötige Tastenkombination. Die Wartezeiten von 1ms zwischen Drücken und Loslassen einer Taste müssen sein, damit die Engine den Druck überhaupt akzeptiert. Die Abfrage, ob die Shift-Taste gedrückt wird, mache ich, damit Ryu nicht die ganze Zeit Hadokens spammt (bzw. die Motion eingibt).

      Die Überlegungen, die ich nun hatte, waren folgende:
      a) ich möchte eine Abkürzung für "warte 1 Frame", damit man sich nicht mit Millisekunden rumärgern muss; außerdem kann man so leichter "4 mal 1 Frame" warten
      b) ich brauche eine Zufallszahl, von der ich abhängig machen kann, welche Taste gedrückt wird

      Fall a ist nicht weiter wild: an den Anfang des Skripts setze ich eine Variable mit dem Namen "frame" und gebe ihr einen fixen Wert von 16,7ms (denn 60 Bilder pro Sekunde -> 16,67ms pro Bild). Fall b gestaltet sich auch einfach, da GlovePIE eine Funktion bietet, die bei Aufruf eine Zufallszahl zwischen 0 und 1 mit 2 Nachkommastellen ausspuckt.

      Das erste Mixup zum Warmwerden: Blanka Ball in verschiedenen Stärken.

      Spoiler anzeigen

      Quellcode

      1. /* Blanka: Ball Mixup, best from mid range */
      2. var.frame = 16.67ms;
      3. if keyboard.shift then begin
      4. var.zufall = random
      5. wait 1000ms
      6. // Charge anfangen
      7. keyboard.left = true
      8. keyboard.down = true
      9. // Warte 70 Frames
      10. wait 70 * var.frame
      11. // Charge aufloesen
      12. keyboard.left = false
      13. keyboard.down = false
      14. wait 1ms
      15. // Nach rechts druecken
      16. keyboard.right = true
      17. // Mixup
      18. if var.zufall < 0.25 then begin
      19. // LP
      20. keyboard.a = true
      21. else if var.zufall < 0.5 then begin
      22. // MP
      23. keyboard.s = true
      24. else if var.zufall < 0.75 then begin
      25. // HP
      26. keyboard.d = true
      27. else begin
      28. // d.h. wenn die Zufallszahl zwischen 0.75 und 1 liegt
      29. // EX
      30. keyboard.a = true
      31. keyboard.s = true
      32. end if
      33. wait 1ms
      34. // Alle Tasten loslassen
      35. keyboard.right = false
      36. keyboard.a = false
      37. keyboard.s = false
      38. keyboard.d = false
      39. wait 1000ms
      40. end if
      Alles anzeigen

      Wenn man das Hadoken-Beispiel verstanden hat, sollte das hier keine große Sache sein.

      Ok, das war nun kein richtiges Mixup. Man könnte das Skript umschreiben und Blanka eine zufällige Zeit warten lassen, bis der Ball kommt, um dann mit 'nem Jab drauf reagieren zu können - das dürft ihr gerne ausprobieren :)

      Schauen wir uns Rufus Dive-Kick Follow-Up an:

      Spoiler anzeigen

      Quellcode

      1. /* Rufus Dive Kick Mixup */
      2. var.frame = 16.67ms;
      3. if keyboard.shift then begin
      4. var.zufall = random
      5. wait 1000ms
      6. keyboard.down = true
      7. wait 1ms
      8. keyboard.right = true
      9. wait 1ms
      10. keyboard.down = false
      11. wait 1ms
      12. keyboard.z = true
      13. wait 1ms
      14. keyboard.right = false
      15. keyboard.z = false
      16. wait var.frame * 60
      17. if var.zufall < 0.33 then begin
      18. keyboard.z = true
      19. wait 1ms
      20. keyboard.z = false
      21. else if var.zufall < 0.66 then begin
      22. keyboard.x = true
      23. wait 1ms
      24. keyboard.x = false
      25. else begin
      26. keyboard.c = true
      27. wait 1ms
      28. keyboard.c = false
      29. end if
      30. wait 1000ms
      31. end if
      Alles anzeigen


      Je nach Zufallszahl wird ein anderes Followup ausgewählt. Kleine Besonderheit: wegen des englischen Tastaturlayouts muss man Z statt Y verwenden.

      ---

      Soviel zur Theorie. In der Praxis klappt die Sache leider nicht ganz so, wie ich mir das vorgestellt habe - die Zeit, die GlovePIE benutzt, macht die Sache schwierig. Durch Schwankungen der Zeit (ich vermute, die wird von der CPU kommen) und durch leichte Schwankungen der FPS im Spiel (im meinem Fall selbst bei Einstellung "konstant" zwischen 59,8 und 60,4) ist es nicht 100% möglich, Sachen wie 1-Frame-Links umzusetzen. Diese funktionieren nur ab und zu. Was ich mir bisher ebenfalls nicht erklären konnte: die Frame-Länge von 16,67ms kommt in keinem meiner Skripte hin, ich musste einen Wert von 13,85ms nehmen. Den müsst ihr evtl. selbst in den Skripten anpassen.

      Hier noch ein paar Skripte, die ich geschrieben habe (aber nicht aufgeräumt oder kommentiert habe):

      Akuma Demon
      Spoiler anzeigen

      Quellcode

      1. if Keyboard.Shift = true then begin
      2. Keyboard.Right = true
      3. Keyboard.A = true
      4. Keyboard.C = true
      5. Wait 1ms
      6. Keyboard.A = false
      7. Keyboard.C = false
      8. Keyboard.Right = false
      9. Wait 1ms
      10. Keyboard.A = true
      11. Wait 1ms
      12. Keyboard.A = false
      13. Wait 1ms
      14. Keyboard.Left = true
      15. Wait 1ms
      16. Keyboard.Z = true
      17. Keyboard.D = true
      18. Wait 1ms
      19. Keyboard.Z = false
      20. Keyboard.D = false
      21. Keyboard.Left = false
      22. Wait 1000ms
      23. end if
      Alles anzeigen


      Boxer: Jab xx Ultra
      Spoiler anzeigen

      Quellcode

      1. /* Boxer: Jab xx Ultra; does only work from time to time */
      2. var.frame = 13.85ms; // 16.67ms;
      3. if keyboard.shift then begin
      4. var.zufall = random
      5. debug = "geht los: " + var.zufall
      6. wait 1000ms
      7. // charge down + back
      8. keyboard.down = true
      9. keyboard.left = true
      10. wait 70 * var.frame
      11. // let go of down to do the jab
      12. keyboard.down = false
      13. wait 1ms
      14. keyboard.a = true
      15. wait 1ms
      16. keyboard.a = false
      17. // wait for jab to finish
      18. // this is a one frame link! might not work all the time
      19. wait 160ms
      20. // ultra
      21. keyboard.left = false
      22. wait 1ms
      23. keyboard.right = true
      24. wait 1ms
      25. keyboard.right = false
      26. wait 1ms
      27. keyboard.left = true
      28. wait 1ms
      29. keyboard.left = false
      30. wait 1ms
      31. keyboard.right = true
      32. keyboard.z = true
      33. keyboard.x = true
      34. keyboard.c = true
      35. wait 1ms
      36. keyboard.right = false
      37. keyboard.z = false
      38. keyboard.x = false
      39. keyboard.c = false
      40. // wait a few moments for piano madness...
      41. wait var.frame * 120
      42. keyboard.z = true
      43. wait 1ms
      44. keyboard.z = false
      45. wait 1ms
      46. keyboard.x = true
      47. wait 1ms
      48. keyboard.x = false
      49. wait 1ms
      50. keyboard.c = true
      51. wait 1ms
      52. keyboard.c = false
      53. wait 1ms
      54. keyboard.z = true
      55. wait 1ms
      56. keyboard.z = false
      57. wait 1ms
      58. keyboard.x = true
      59. wait 1ms
      60. keyboard.x = false
      61. wait 1ms
      62. keyboard.c = true
      63. wait 1ms
      64. keyboard.c = false
      65. wait 1ms
      66. keyboard.z = true
      67. wait 1ms
      68. keyboard.z = false
      69. wait 1ms
      70. keyboard.x = true
      71. wait 1ms
      72. keyboard.x = false
      73. wait 1ms
      74. keyboard.c = true
      75. wait 1ms
      76. keyboard.c = false
      77. wait 1ms
      78. keyboard.z = true
      79. wait 1ms
      80. keyboard.z = false
      81. wait 1ms
      82. keyboard.x = true
      83. wait 1ms
      84. keyboard.x = false
      85. wait 1ms
      86. keyboard.c = true
      87. wait 1ms
      88. keyboard.c = false
      89. wait 1ms
      90. keyboard.z = true
      91. wait 1ms
      92. keyboard.z = false
      93. wait 1ms
      94. keyboard.x = true
      95. wait 1ms
      96. keyboard.x = false
      97. wait 1ms
      98. keyboard.c = true
      99. wait 1ms
      100. keyboard.c = false
      101. wait 1ms
      102. keyboard.z = true
      103. wait 1ms
      104. keyboard.z = false
      105. wait 1ms
      106. keyboard.x = true
      107. wait 1ms
      108. keyboard.x = false
      109. wait 1ms
      110. keyboard.c = true
      111. wait 1ms
      112. keyboard.c = false
      113. wait 1ms
      114. keyboard.z = true
      115. wait 1ms
      116. keyboard.z = false
      117. wait 1ms
      118. keyboard.x = true
      119. wait 1ms
      120. keyboard.x = false
      121. wait 1ms
      122. keyboard.c = true
      123. wait 1ms
      124. keyboard.c = false
      125. wait 1ms
      126. keyboard.z = true
      127. wait 1ms
      128. keyboard.z = false
      129. wait 1ms
      130. keyboard.x = true
      131. wait 1ms
      132. keyboard.x = false
      133. wait 1ms
      134. keyboard.c = true
      135. wait 1ms
      136. keyboard.c = false
      137. wait 1ms
      138. wait 1000ms
      139. debug = "fertig"
      140. end if
      Alles anzeigen


      Abel CoD
      Spoiler anzeigen

      Quellcode

      1. /* Abel: CoD Mixup */
      2. var.frame = 13.85ms; // 16.67ms;
      3. if keyboard.shift then begin
      4. var.zufall = random
      5. debug = "geht los: " + var.zufall
      6. wait 1000ms
      7. // qcf + lp
      8. keyboard.down = true
      9. wait 1ms
      10. keyboard.right = true
      11. wait 1ms
      12. keyboard.down = false
      13. wait 1ms
      14. keyboard.a = true
      15. wait 1ms
      16. keyboard.a = false
      17. keyboard.right = false
      18. // wait for 1st hit to retaliate
      19. wait var.frame * 30
      20. // Mixup: 2nd hit
      21. if var.zufall < 0.5 then begin
      22. keyboard.right = true
      23. keyboard.s = true
      24. wait 1ms
      25. keyboard.right = false
      26. keyboard.s = false
      27. wait var.frame * 35
      28. // Mixup: throw
      29. if var.zufall < 0.25 then begin
      30. keyboard.right = true
      31. keyboard.d = true
      32. wait 1ms
      33. keyboard.right = false
      34. keyboard.d = false
      35. else begin
      36. keyboard.right = true
      37. keyboard.c = true
      38. wait 1ms
      39. keyboard.right = false
      40. keyboard.c = false
      41. end if
      42. else begin
      43. keyboard.right = true
      44. keyboard.x = true
      45. wait 1ms
      46. keyboard.right = false
      47. keyboard.x = false
      48. wait var.frame * 40
      49. // Mixup: throw
      50. if var.zufall < 0.75 then begin
      51. keyboard.right = true
      52. keyboard.d = true
      53. wait 1ms
      54. keyboard.right = false
      55. keyboard.d = false
      56. else begin
      57. keyboard.right = true
      58. keyboard.c = true
      59. wait 1ms
      60. keyboard.right = false
      61. keyboard.c = false
      62. end if
      63. end if
      64. wait 1000ms
      65. debug = "fertig"
      66. end if
      Alles anzeigen


      Sagat: TU FADC Throw / TU / Block Mixup
      Spoiler anzeigen

      Quellcode

      1. /* Sagat: TU FADC Throw / TU / Block */
      2. var.frame = 13.85ms; // 16.67ms;
      3. if keyboard.shift then begin
      4. var.zufall = random
      5. debug = "geht los: " + var.zufall
      6. wait 1000ms
      7. // Kara
      8. keyboard.right = true
      9. keyboard.z = true
      10. wait 1ms
      11. keyboard.z = false
      12. keyboard.right = false
      13. wait 1ms
      14. // TU
      15. keyboard.right = true
      16. wait 1ms
      17. keyboard.right = false
      18. keyboard.down = true
      19. wait 1ms
      20. keyboard.right = true
      21. keyboard.down = true
      22. keyboard.a = true
      23. wait 1ms
      24. keyboard.down = false
      25. keyboard.right = false
      26. keyboard.a = false
      27. // Wait for...
      28. wait 15 * var.frame
      29. // FADC
      30. keyboard.s = true
      31. keyboard.x = true
      32. wait var.frame * 10
      33. keyboard.right = true
      34. wait 1ms
      35. keyboard.right = false
      36. wait 1ms
      37. keyboard.right = true
      38. wait 1ms
      39. keyboard.right = false
      40. keyboard.s = false
      41. keyboard.x = false
      42. // Mixup
      43. if var.zufall < 0.33 then begin
      44. // Wait for Dash to complete
      45. // time differs depending on mixup
      46. wait var.frame * 20
      47. // TU
      48. keyboard.right = true
      49. wait 1ms
      50. keyboard.right = false
      51. keyboard.down = true
      52. wait 1ms
      53. keyboard.right = true
      54. keyboard.down = true
      55. keyboard.a = true
      56. wait 1ms
      57. keyboard.down = false
      58. keyboard.right = false
      59. keyboard.a = false
      60. else if var.zufall < 0.66 then begin
      61. // Wait for Dash to complete
      62. // time differs depending on mixup
      63. wait var.frame * 29
      64. // Throw
      65. keyboard.a = true
      66. keyboard.z = true
      67. wait 1ms
      68. keyboard.a = false
      69. keyboard.z = false
      70. else begin
      71. // no wait needed, just hold block
      72. keyboard.left = true
      73. keyboard.down = true
      74. wait 1500ms
      75. keyboard.left = false
      76. keyboard.down = false
      77. end if
      78. wait 1000ms
      79. debug = "fertig"
      80. end if
      Alles anzeigen
      Lattenrost ist keine Geschlechtskrankheit