Hallo Besucher, der Thread wurde 25k mal aufgerufen und enthält 172 Antworten

letzter Beitrag von Drachen am

Scrolling Workshop

  • Mahlzeit!


    Da ich es in sehr naher Zukunft endlich mal auf die Reihe kriegen muss, und ich glaube, dass auch andere gerne mehr verständlichen Code sehen möchten, eröffne ich hiermit eine Art Scrolling-Workshop.


    Ich hatte schon das eine oder andere Mal mit Scrolling gespielt (Flapper, mein erster Cartridge-Spiel-Entwurf), und bin da auf die eine und andere Hürde gestossen. Als Endziel sollte hier eine brauchbare Routine rauskommen (bzw. mehrere), die nach Bedarf Characters und Farbe scrollen können, und denen man einen nicht direkt im Speicher ausgepackten Level vorgeben kann (also nicht die Bildschirmdaten entpackt, sondern Teil-basiert; oder evtl. sogar Element-basiert).
    Dass das nicht generisch funktioniert ist leider eine der ersten Erkenntnisse.


    Ich versuche hier nach und nach Verbesserungen einzubringen und hoffe auf rege Teilnahme und Verbesserungsvorschläge (und dass zumindest ich was lerne).


    #1: Naiv
    -nur Zeichen
    -eine feste Richtung
    -Befüllung mit fixem Zeichenmuster


    Den Anfang mache ich mit der Routine aus Flapper. Pro Frame wird ein Pixel gescrollt. Der simple Ansatz, für die 7 ersten Schritte wird lediglich das Softscroll-Register bei $D016 verwendet, beim 8 Schritt werden alle Zeichen stupide ein Zeichen nach links versetzt. Danach wird in der rechtsäußersten Spalte ein neuer Inhalt dargestellt.


    Zur Veranschaulichung kann per Knopfdruck (Port II) die Dauer der Routine dargestellt werden.

  • die paar zyklen sind da aber schon fast egal - auf was spider hinaus wollte ist vmtl das man typischerweise über die zeilen ausrollt.


    davon ab würde ich die loop, die man an der stelle zu demonstrationszwecken durchaus so machen kann (weil schnell genug), statt dessen so schreiben:


    ldx #0
    lda $0400+1,x
    sta $0400,x
    lda $0500+1,x
    sta $0500,x
    lda $0600+1,x
    sta $0600,x
    lda $06e7+1,x
    sta $06e7,x
    inx ; bne ; etc

  • Wie soll denn die Reise weitergehen?


    Ich kann mich gar nicht mehr erinnern, wo ich mal ein ordentliches Scrolling gebaut habe... Ich meine, das eigentliche Scrolling hatte ich im IRQ untergebracht, das Hardscrolling in der Hauptschleife, die auf Signale aus dem IRQ wartet.


    Wenn noch Sprites hinzukommen muß man im Kopf behalten, was man für den gerade sichtbaren Frame macht und was für den nächsten.


    Wenn es ohne 2. Screen als Puffer laufen soll, dann war es noch so ne Sache, den besten Moment für das Hardscrollen zu finden.


    Im Prinzip könnte man nach der ersten Badline mit dem Hardscrollen für den nächsten Frame anfangen, wenn man wie hier kopiert, dann hat man rund 500 Rasterzeilen Zeit.


    Üblicher ist es aber, die Schleife bis 39 Zählen zu lassen und darin dann Zeilenweise zu kopieren. Das spart Rasterzeit, dafür kann man aber nicht mehr so früh mit dem Kopieren anfangen. Wenn es wirklich eng wird, dann ist eine Kombination gut.


    Erfreulicherweise steckt beim Scrollen nach Rechts das neu hinzugefügte Zeichen hinter dem Border, so daß man da noch einen Frame mehr für die neuen Zeichen schinden kann - Bei dieser Geschwindigkeit und dieser Richtung.


    EDIT: Bei Sauhunds Lösung muß man glaub ich sehr darauf achten, die passende Rasterzeile zum Start zu nehmen, wäre beim Kopieren aller Zeilen in einer Schleife auch so. Wenn man nicht in "schöner" Reihenfolge von oben nach unten kopiert, dann bleiben halt ziemlich lang im oberen Bereich des Bildschirms Stellen mit altem Inhalt übrig. Bevor das Kopieren fertig ist, ist der Rasterstrahl schon längst wieder im Textteil des Bildschirms, und dann sollte der nur fertig erstellte Zeilen sehen.

  • Auja, rege Beteiligung!


    Das das Scrolling das mieseste aller Zeiten ist, ist mir klar ;)
    Ich möchte das ganze Feedback ja benutzen, um auf den bisherigen Fehlern aufzubauen, da erkennt man wesentlich besser, warum etwas auf eine bestimmte Art und Weise getan wird. Das höchste an Scrolling, das ich bisher hinbekommen habe, war bei dem genannten Cartridge-Versuch. Das war links/rechts-Scrolling, Sprites je nach Position einblenden (und mitbewegen). Das ganze mit Doppelpuffer und auf die Kopiererei auf 4 Frames aufgeteilt. Für Farbscrolling hat es aber nicht gereicht :)


    Grade aufgrund meines Wissenstandes ist Kurs nicht so ganz die richtige Bezeichnung, eben daher Workshop.


    Die weitere Reise soll in Richtung Kontrollierbarkeit, Geschwindigkeitsoptimierung (gibt ja mehrere Möglichkeiten) und vor allem Scrolling mit Farbram gehen. Hoffentlich kommen wir da auch an.


    Anbei schonmal ein weiterer Schritt, diesmal nur Scrolling in die andere Richtung. Hier hat sich schon mal gezeigt, dass hier die Page (256-Byte)-weise Kopiererei wegen der Arbeitsrichtung Probleme verursacht. Theoretisch müsste man von ganz "unten" anfangen, dadurch schafft man es aber nicht mehr bis zur Darstellung zu den obersten Zeilen. Im Code daher erstmal Zeilenweise kopieren, dann nur 39 Zeichen (statt alle), und selbstmodifizierender Code.

  • Das hier ist glaube ich das, was hoogo meinte:

    Code
    1. ldy #0
    2. -
    3. !for i, 25 {
    4. lda SCREEN_CHAR+((i-1)*40)+1,y
    5. sta SCREEN_CHAR+((i-1)*40),y
    6. }
    7. iny
    8. cpy #38
    9. bne -


    Halte ich persönlich auch für einen guten Kompromiss zwischen RAM und Rasterzeit. Wenn man RAM genug hat, kann man natürlich auch komplett ausrollen und den Loop weglassen.


    EDIT: oh, Code geändert - lief vorhin falsch =)
    EDIT2: achso, der !for Loop ist acme Syntax. Das nervt leider etwas, dass der immer bei 1 anfängt zu zählen und man deswegen den (i-1) Kram machen muss.

  • Aber da muß man dann wohl teilweise aufpassen, dass der Rasterstrahl nicht schon von oben reinkommt, während man sich nach rechts durcharbeitet.


    Nunja, mit dec/inc $d020 lässt sich das ja relativ einfach sichtbar machen und man kann die Position leicht anpassen, wo der Loop ausgeführt wird. Das ist kein Hexenwerk. Der Vorteil, wenn man den Loop-Code etwas auf Geschwindigkeit hin optimiert, dass man eben *kein* Doppelpuffer braucht.
    EDIT: achso und für Farbram mal die Sachen ansehen, die Cadaver/Covertbitops dazu geschrieben hat. Sein Rants sind gerade für Spieleentwickler sehr interessant.

  • Ich habe mir vor ziemlich genau 1 jahr mal tierisch einen abgebrochen und single-bufferd komplettes Screen + Farbram gescrollt
    http://csdb.dk/release/?id=105927
    aber beim Farbram reichlich beschissen, um ohne Double Buffering auszukommen (je nach Bild wird das Farbram nur gescrollt, wenn in der Zeile wirklich eine Farbänderung ist)
    Fred gibt es auch hier im Forum dazu:
    25x-Scroller: Mal wieder irres Geflacker<- Beispiele für Pitfalls/wie man's nicht macht :P
    Auch zum Thema:
    Frabram $d800 rollen geht zu schnell

  • EDIT: achso und für Farbram mal die Sachen ansehen, die Cadaver/Covertbitops dazu geschrieben hat. Sein Rants sind gerade für Spieleentwickler sehr interessant.


    Ja, die habe ich mir auch schon zu Gemüte geführt. Das sind auf jeden Fall Dinge, die einfliessen werden.


    Was mir noch ein bißchen Sorgen macht, die letzten Spiele von mir waren nicht Tile-basiert, sondern Elemente (Elemente im Sinne von Charset-Blöcken beliebiger Größe). Das macht es beim Nachfüllen am Rand etwas (sprich deutlich) schwieriger. Das werde ich vermutlich nicht so ohne Weiteres beibehalten können.

  • Was mir noch ein bißchen Sorgen macht, die letzten Spiele von mir waren nicht Tile-basiert, sondern Elemente (Elemente im Sinne von Charset-Blöcken beliebiger Größe). Das macht es beim Nachfüllen am Rand etwas (sprich deutlich) schwieriger. Das werde ich vermutlich nicht so ohne Weiteres beibehalten können.

    Macht Turrican doch auch, das wird sich schon lösen lassen. Schlimmstenfalls mit Puffer von Bildschirmhöhe und Elementbreite (+1?), um ein ganzes Element Voraussicht zu haben.

  • Für das Hinzufügen von tile-Zeilen oder -Spalten gibt es auf der codebase und auf der covertbitops-Seite hilfreiche Beispiele. Wenn man sich den Zusammenhang von charset, mapdata und tileset klar gemacht hat, ist das weiter kein Problem.

  • bei GGS wird aber nichtmal in Echtzeit entpackt. Das zaehlt dann wohl kaum. Hawkeye2 entpackt aber z.B. in Echtzeit beim Scrolling allerdings nur vertikale Stripes.
    Ich denke Times of Lore ist da wirklich das Glanzstueck was variable Tile-size bzw verschachtelte Tiles angeht.
    Eine meiner Toy-engines hat auch variable Tile-Groessen geht aber ganz anders an die Sache ran. Da wird PRO tile ein offset errechnet und die map quasi ge'raytraced'.
    Mal sehen :)