Hallo Besucher, der Thread wurde 3,3k mal aufgerufen und enthält 26 Antworten

letzter Beitrag von Mnemonic am

Sprites und Timing... ein paar Fragen!

  • Hallo zusammen,


    ich bin grade mal wieder an einen Punkt gekommen, an dem ich mir die Zähne ausbeisse... :aerger:


    Wie bekommt man denn einen Bereich auf dem Screen, über den unregelmäßig ein paar Sprites fliegen, so stabil, dass man da noch zu einen fixen Punkt z.B. die Scrollregister in $d016 setzen kann?


    Konkretes Problem ist, ich habe meine 8 Sprites, die in einem Sinus über den ganzen Bildschirm rauschen, und ich will in der unteren Hälfte halt noch 3 Bereiche mit unterschiedlichen Geschwindigkeiten scrollen (halt so Charset als Pseudohintergrund), und die stoßen grafikmäßig halt auch direkt aneinander, also nix mit Luft dazwischen für irgendwelches geflatter.


    Geht das überhaupt? Wie löst Ihr denn so etwas? In dem Bereich, den die Sprites kreuzen, kann ich ja auch net mit 'nen Doppel-IRQ stabilisieren, da haut's mir ja jedesmal mein Timing wieder kaputt.


    Irgendwie muss dass doch zu machen sein, oder nicht?


    Ich hab' ja jetzt auch schon in mehreren Demos gesehen, dass da sogar Sprites kreuz und quer über irgendwelche Rasterbars schwirren und da trotzdem nix flattert...


    Etwas verzweifelte Grüße,


    der Mnemonic

  • tjaaa.... das mit den sprites über stabilen rasterklamotten ist eins der frickeligsten sachen auf dem c64 :)


    bei demos ist das oft so das die sprites sich in Y garnicht wirklich bewegen, sondern per d017 stretching oder sprite-crunching über den bereich gestretcht werden, und um den bewegungseffekt zu simulieren dann zeilenweise spritepointer umgeschaltet werden.


    eine andre möglichkeit wäre 8 verschiedene interrupt routinen zu stricken, die dann jeweils so ausgetimed sind das sie mit 1 ... 8 sprites an der stelle richtig sind. oder halt eine einzelne routine die per selbstmodifikation entsprechend angepasst wird.


    wie gesagt, frickelig :)

  • Das Einfachste wär natürlich, zwischen den unterschiedllichen Scrollbereichen Minimum eine Line freizulassen, in der Du in Ruhe umschalten kannst. Aber wir sind ja keine Mädchen! :)


    Ansonsten würde ich, die Idee von Sauhund aufgreifend, wie folgt vorgehen:


    Du löst den Rasterirq bereits 2-3 Zeilen vor der Line aus, in der $D016 gesetzt werden muss. Die Zeit zwischen dem Rasterirq und dem eigentlichen Umschaltzeitpunkt überbrückst du mit einer einfachen Warteschleife auf dex beq wait Basis. Mittels unterschiedlicher Werte im X-Register kannst Du nun das Timimg variieren. Der Wert X ist also unsere Variable, mit der wir auf unterschiedliche Timingkonstellationen bzw. -erfordernisse reagieren.


    Jetzt musst Du "nur" noch vor Aufruf der IRQ-Routine jeweils alle Y Koordinaten der Sprites prüfen und checken, ob diese in die Umschaltline hineinreichen. Für jedes Sprite, dass diese Bedingung (Überlappen mit der Umschaltrasterline) erfüllt, erhöhst Du einen jeweils vor der Prüfung auf 0 gesetzten Pointer um 1. Dieser nimmt jetzt also je nach Anzahl der Sprites, die überlappen, Werte von 0 bis 8 an. Diesen Pointer nutzt Du nun als Zeiger auf eine Tabelle, in der 8 verschiedene Werte stehen, die Du als Timer im Interrupt ins X-Register lädst.


    (Heist natürlich, dass Du vorher zunächst von Hand für 0-7 Sprites, die Überlappen, den entsprechenden Timingwert fürs X-Register ermitteln musst. Hier ist ausprobieren angesagt.)


    Ich hoffe, das war verständlich soweit... Wenn nicht frag gerne nach. So denke ich aber , könnte es funktionieren.


    Gruß, André

  • Hmm. Laut Pasi Ojalas "Missing Cycles" Artikel in C=Hacking 3 könnte die Sache noch wesentlich komplizierter sein. Demnach "verbraucht" VIC 3 Cycles pro Sprite, alle hintereinander weg. Die CPU muss nur (so Pi mal Daumen) für jeweils 2 davon gestoppt werden, aber der CPU wird der Bus schon 3 Cycles bevor VIC was lesen muss der Bus abgedreht, wodurch dann je nach Spritekonstellation zusätzlich was verloren geht, weil die Zeit nicht reicht um den Bus zwischen 2 Spritelesungen wieder freizugeben (oder so ähnlich jedenfalls).


    Falls das stimmt würd ichs einfach flackern lassen und noch n Scrolltext dazu machen, wo ich mich beim Betrachter für die Unannehmlichkeiten entschuldige :)

  • Ja, der Artikel von Pasi Ojala ist mir dazu eben auch eingefallen...


    Zumal ja die Sprites, die da meine Grafik kreuzen, auch nicht zwingend in der richtigen Reihenfolge kommen.


    Mal sind z.B. Sprite #4 und #7 darüber, dann wieder #0 und #1, des gibt echt nur Chaos, glaub ich. :buhu


    Naja, vielleicht bekomme ich's ja doch hin, das ganze springt ja auch "nur" um maximal 10 Cycles, das bekomme ich vielleicht im 38 Spalten-Modus beim scrollen grade so unter den Sideborder bzw. in die vertikale Austastlücke.


    Gruß,


    der Mnemonic

  • Zur Not schnappste dir halt n Byte und setzt für jedes Sprite das im Weg ist n Bit, um damit den passenden Verzögerungswert aus ner Tabelle mit allen 256 möglichen Kombinationen zu holen, wenn du Zschigis Idee umsetzen willst.


    Ansonsten sorg halt dafür, dass immer irgendwie alle Sprites den kritischen Bereich überdecken, wie Sauhund vorgeschlagen hat. Dann bleibt zwar nicht viel Zeit, aber die ist wenigstens konstant. Vielleicht hast du ja Glück und es reicht schon ein einfacher Multiplexer dafür.

  • So, hab's jetzt halt unter den Border gefummelt, da sieht man's net mehr. :rotwerd:


    Ich weiss auch net, seit ich mir den stabilen IRQ draufgeschafft habe, nervt's mich halt total, wenn sich was net stabilisieren lässt. Naja, dann soll's halt zappeln, muss ich mit leben. :whistling:


    Gruß,


    der Mnemonic

  • So, ihr macht mich noch ganz wuschig!!! :)


    Hab mir jetzt mal fix ne Miniroutine gestrickt, um den Spass zu testen. Testkonstellation waren in der Bildmitte gesetzte Sprites über einer einzeln eingefärbten $d021 Line. Ausgetimet habe ich diese mittels der "dex-bne wait-Schleife", wobei ich die Werte hier jewiels vor dem Programmstart von Hand geändert habe. (Dies entspricht letztlich dem "Probierteil", von dem ich oben sprach.)


    Fakt ist mit X-Werten zwischen 02 bis 0a kann man es sauber timen. Dabei kommt es für das Timing allein auf die Anzahl der überlappenden Sprites an. Es ist also völlig egal, ob Sprite 1 und 8 oder Sprite 4 und 5 drüberliegen. Entscheidend ist nur, dass es zwei an der Zahl sind. Somit sollte die Routine so funktioinieren, wie ich denke, also mit lediglich 8 unterschiedlichen Timings


    Noch ein weiterer Gedanke, solltest Du mit der Verzögerungsschleife nicht genau genug timen können, kannst du es auch mit einem NOP-Unterprogramm machen. Du springst also einfach ein Unterprogramm an, das nur aus NOP´s besteht. Vor dem Anspringen schreibst Du jedoch eine $60 (=RTS) an eine bestimmte Stelle (Offset) nach der Basisadresse des Programms. Den Offsetwert holst Du Dir wieder aus der Timingtabelle (wie bei der Warteschleife). Ist der Offsetwert also z.B. 4 Schreibst du an die vierte Stelle nach der Ansprungadresse ein NOP. Im Ergebnis werden dann vor dem RTS vier NOP´s ausgeführt. Aber wie gesagt, m.E. schafft man es schon mit der Verzögerungsschleife.


    Gruß, André

  • Zitat

    Vor dem Anspringen schreibst Du jedoch eine $60 (=RTS) an eine bestimmte Stelle (Offset) nach der Basisadresse des Programms.


    das kann man aber einfacher haben....



    mmmh geht das so? zu faul zu testen jetzt =) aber die idee dahinter sollte klar sein =)

  • @sauhund: Du hast natürlich Recht! Da stand ich mir selbst im Weg. Die Routine, wie ich sie verwendet hatte kommt in Enforcer II im Level 2 in starker Abwandlung für einen grafischen Effekt zur Anwendung, wo es nicht nur um ein Austimen geht, sondern ganz konkret unterschiedliche Befehlsabläufe vom Start bis zu einem gewissen (jeweils in Abhängigkeit von der Frame zu bestimmenden) Stopp abgearbietet werden müssen. Da gehts dann nur so, wie ich es gemacht habe. Aber beim Austimen wie hier, ist das freilich auf Deine Weise viel (!!) einfacher zu haben. Das hatte ich durch meine "Enforcer-Scheuklappen" völlig verpeilt! :)

  • nur nochmal zur info, dass du nicht zu tode rumexperemierst...
    nur die anzahl der sprites allein sagt nix über die "verlorenen zyklen" aus.


    bsp: sprites 1,2,3,4,5,6,7 zusammen verbrauchen genausoviel zyklen wie 1,3,5,7 zusammen!!!
    d.h. es kommt sehr wohl auf die zusammensetzung an... und da gibt es eben 256 möglichkeiten (wenn man alle 8 sprites verwendet).
    Diese Werte könnte man natürlich einfach ein eine Tabelle ablegen und dann eine entsprechende verzögerung machen...


    jedes sprite an sich verbraucht 5 zyklen, wobei sich diese zyklen im 2er abstand von sprite zu sprite überschneiden.
    also folgendermassen (zeilennummer entspricht dem sprite, und die horizontal sind die zyklen die verbraucht werden als X markiert)


    Code
    1. XXXXX--------------
    2. --XXXXX------------
    3. ----XXXXX----------
    4. ------XXXXX--------
    5. --------XXXXX------
    6. ----------XXXXX----
    7. ------------XXXXX--
    8. --------------XXXXX


    da sieht man dann auch, dass wenn sprite 1 und 3 schon da sind, es völlig irrellevant ist, ob sprite 2 noch hinzukommt oder nicht, da sprite 2 sich die zyklen von sprite 1 und 3 teilen würde