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

letzter Beitrag von FrankDrebin am

multiplexer

  • hi jungs und maedels,


    bin gerade dabei einen multiplexer zu schreiben.
    stosse aber zur zeit auf meine grenzen.
    also 64 sprites aufeinmal anzeigen ist kein problem, das problem ist diese dann auch unabhaengig voneinander zu bewegen.
    habe jetzt einfach mal nur mit 8 sprites aufeinmal also 2 figuren die jeweils aus 4 sprites bestehen (2 x aufeinander und dann uebereinander = 2 sprite pointer).
    ich habe es erstmal damit versucht die rasterzeilen mitzubewegen...
    da liegt das problem, wenn die rasterzeilen sich ueberschneiden, dann bremst das system natuerlich...
    ich frage mich jetzt wie umstaendlich ich die routine schreiben muss?
    sollte ich jede sprite position abfragen und ueberpruefen lassen ob auf der bildschirmposition ein sprite sich befindet, was das system noch langsamer machen wuerde...?
    oder gibt es da eine elegantere loesung?

  • sprites anhand der Y position sortieren und dann immer in portionen von 8 sprites von oben nach unten darstellen.


    wenn du einen "generischen" multiplexer bauen willst, also alle sprites prinzipiell frei bewegbar sein sollen, würde ich auch mal weniger als 64 ansetzen - es gibt kaum ein game das mehr als 32 benutzt (die meissten kommen sogar mit noch viel weniger aus). das reduziert den verwaltungsaufwand drastisch.

  • -Ein "richtiges", komplettes Sortieren kann ganz schön Zeit fressen. Aber da Animationen ja keine rein zufälligen Positionen erzeugen kann man davon ausgehen, daß der nächste Frame mehr oder weniger genauso sortiert sein wird wie der aktuelle. In der großen Ursprungs-Spriteliste, die Farbe, Block, X-Y-Position... sammelt, habe ich darum ncoh einen Pointer für einen Verweis in eine kleine, sortierte Tabelle mit Spritenummer/Y-Pos abgelegt. Immer, wenn eine YPos in der Spritetabelle gesetzt wird, wird sie über den Pointer auch in der sortierten Liste eingetragen. Deise kleine Liste kann dann prima mit einem Straight-Insert sortiert werden. Das Ein/Ausschalten von Sprites ist aber recht teuer, es lohnt sich imho, auch ein abgeschaltetes Sprite einfach weiter mitzusortieren.


    -Die große Liste ist auch besser als viele kleine Listen quergedacht. Also nicht X/Y/Farbe/Block... hintereinander und dann das nächste Sprite, sondern eine kleine Liste mit allen X, eine kleine Liste mit allen Y...


    -Nach dem Sortieren habe ich mir immer eine Jobliste zusammengestellt: Rasterzeile-1,Register,Wert,Register,Wert,Register,Wert...,$FF,Rasterzeile-1,Register.... Wenn im IRQ ein Stückchen der Liste abgearbeitet war habe ich dann geprüft, ob es sich noch lohnt, den IRQ zu verlassen, ohne aus Versehen eine Zeile zu verpassen, oder ob man besser wartet.


    -Die ersten 8 Sprites werden am Anfang des Bildschirms komplett gesetzt, danach rechnet man dann für weiteres Umschalten besser mit der ersten Zeile nach einem verbrauchten Sprite als mit der ersten Zeile vor dem gewünschten Sprite weiter. Besser ein Beispiel: Sprite 0 soll in den Zeilen 70 und 100 angezeigt werden. Naheliegend wäre, alles in den Zeilen 69 und 99 einzurichten. Besser ist's aber, in Zeile 0 einmal alle 8 und dann in Zeile 91 (=70+21) das neue Sprite einzurichten. So darf sich hier das Einrichgten um bis zu 9 Rasterzeilen verzögern, ohne daß es Probleme gibt.


    -Diese Jobliste hätte man auch noch ganz schön auf Rasterzeit-Verbrauch optimieren können, schliesslich sind die berechneten Rasterzeilen immer nur der Anfang eines Fensters, in dem die Werte gesetzt werden sollten. Für die Y-Position der Sprites ist das Fenster sogar wesentlich größer, die kann ja schon während des alten Sprites gesetzt werden. Im Prinzip kann man sogar alle 8 Sprite-Y-Positionen auf einen Schlag setzen, aber imho lohnt sich das Ganze nicht, da hat man sich schnell was zusammenoptimiert, was nicht mehr in eine Rasterzeile Rechenzeit passt. Ist insgesamt wohl besser, das Programm auf den schlimmsten Fall als auf insgesamt geringen Rasterzeitverbrauch zu optimieren.


    -Bei Figuren, die aus mehreren Sprites nebeneinander bestehen, würde ich eine der Spalten vertikal versetzen, also die Y-Position um 1 oder 2 erhöhen. Das gleicht man dann halt im Sprite-Editor aus. Das verhindert, daß man zu viele Sprites je Rasterzeile ordentlich einrichten muß, falls es dann doch mal sehr eng wird. Bei Obermotzen ist es dann auch ganz gut, mit einem Sprite Reserve zu rechnen: 8 Sprites - 1 Playersprite- 1 Reserve= 6 Sprites Obermotz-Breite. Das sorgt dafür, daß nie ein Sprite gleich im Anschluß an sich selber kommt.


    -Statt der Jobliste bietet es sich sehr an, eine laaange Lda#123, Sta $d000-Kette mit den Werten/Registern zu modifizieren und für die nächste Rastrerzeile jeweils ein Sta durch ein Rts zu überschreiben. Hab sowas aber nie fertiggestellt. Frisst beim generieren vermutlich was mehr Zeit, spart dann aber Zeit im Rasterirq, wo's ja drauf ankommt.

  • @sauhund
    klar werden das weniger sprites, mir war es erstmal wichtig, dass ihr wisst wovon ich eigentlich rede.
    z.zt plane ich mit 24 sprites, werde aber noch versuchen eine figur mehr einzubauen sprich 32 sprites....


    Hoogo
    ich werde mir das mal zu gemuetige fuehren.
    muss mir das alles nochmals durchlesen, ich verstehe auf jedenfall, dass du ein register generiert hast, was ich denke auch das beste ist, muss ich sowieso machen, fuer die sprite bewegung braucht mal halt ein register (oder programmiere ich den figuren einfach eine kuenstliche intelligenz ;)).

  • Hoogo
    so langsam steige ich da durch, was du meinst, liegt wohl auch daran, dass es nicht mehr so heiss ist....
    also erstmal fallen bereits 4 sprites fuer die spielfigur weg, da ich diese nicht im raster teilen moechte.
    fuer die anderen figuren bleiben, dann noch 4 sprites uebrig, auf der selben rasterzeile + 21 uebrig, daher muss ich diese aufteilen also koennen 2 figuren zusaetzlich auf der selben rasterzeile angezeigt werden.
    moeglich soll es dann sein noch weitere sprites weiter oben oder unten anzuzeigen, ist aber erstmal nebensaechlich....
    das ziel ist es das programm so zugestalten, dass die rasterzeile erkennt, ob bereits ein oder mehrere sprites in der naechsten raster angezeigt wird oder nicht, wenn ja soll in diesem fall der/die sprites mit in den spritepointer aufgenommen werden und wenn von noeten, bei gleichem spritepointer einer geaendert wird.
    da wuerde sicherlich eine tabelle wie du vorgeschlagen hast die allein die y pos. festlegt sehr hilfreich sein, fuer mein geschmack ist das aber arg aufwendig.....
    desweiteren sollte es auch eine tabelle geben wo festgelegt ist welcher sprite welchen spritepointer hat, sodass man dem raster eine weitere rechenarbeit ersparen kann.
    aber ich frage mich ob man nicht gleich die spritepointer direkt abruft um dann das programm vergleichen zu lassen, welcher sprite wo ist ohne eine eigene tabelle zuschreiben, es sind ja nicht mehr viele sprites, die man vergleichen muss, sollte, dann koennte man diese routine dann auch fuer zukuenftige projekte brauchen, ein problem erkenne ich aber jetzt schon, denn die spritepointer werden pro rasterzeile veraendert, koennen also von dem programm falsch zugeordnet werden.....
    klar das die figuren eine y + x liste brauchen, damit sie wissen wo sie hin laufen sollen.
    ausserdem frage ich mich ob es vielleicht moeglich ist die rasterzeilen starr zu programmieren.
    die sprites aber voll beweglich und jedesmal wenn sie einen raster ueberschreiten von der spriteanzeige neu zugeordnet werden ....
    worauf hab ich mich da bloss eingelassen .... :baby:
    hier mal der source code, von dem was ich bereits geschrieben habe.... ist nicht viel, habe eigentlich noch garnichts von dem was ich weiter oben machen wollte geschrieben. :roll:


    !to "compiled.prg" ,cbm ; Filename deines Programmes !!!



    *= $0800 ; Basicstart, damit das über "RUN" zu starten geht,
    ; kann man Einstellen über "Einfügen->Basicstart (Umrechen!über "Extras->HEX/DEZ/BIN-Konverter)
    ; in dem Fall hier $0850 (HEX) = 2128 (DEZ)


    !byte $00,$0c,$08,$0a,$00,$9e,$32,$31,$32,$38,$00,$00,$00,$00



    ;--------------------------------------------------


    *=$1ffe
    !bin "C:\relaunch\relaunch\bunnyspiel\bunny.spr"
    ;--------------------------------------------------




    *=$0850 ; Einsprungadresse

    jsr $e544 ; kernal Routine zum Bilschirm löschen
    lda #06
    sta $d020
    sta $d021
    sei
    lda #<irq
    sta $0314
    lda #>irq
    sta $0315
    lda #$7f ; normaler IRQ Einsprung
    sta $d01a
    sta $dc0d
    lda #$14
    sta $d011
    lda #$00
    sta $d012
    cli
    rts


    ;--------------------------------------------------
    irq
    ;--------------------------------------------------
    lda #$01
    sta $d019
    sta $d01a
    jsr multiplex
    jmp $febc
    ;--------------------------------------------------
    multiplex
    ;--------------------------------------------------


    lda #255
    sta 53248+21
    start ldx $d012
    move1 cpx #81
    bne start
    jsr gegner1
    neu ldx $d012
    move2 cpx #102
    bne neu
    jsr spritea
    start1 ldx $d012
    cpx #123
    bne start1
    jsr gegner2
    neue ldx $d012
    cpx #144
    bne neue
    jsr spriteb
    inc move1+1
    inc move2+1
    dec run1+1
    dec run2+1
    rts


    ;--------------------------------------------------
    gegner1
    ;--------------------------------------------------
    lda #128
    sta 2040
    clc
    adc #40
    sta 2041
    run1 lda #200
    sta 53248
    stx 53248+1
    sta 53248+2
    stx 53248+3
    lda #10
    sta 53248+28 ; multi sprite
    lda #15
    sta 53248+37
    lda #09
    sta 53248+38
    lda #00
    sta 53248+39
    lda #06
    sta 53248+40
    rts
    spritea lda #148
    sta 2040
    clc
    adc #40
    sta 2041
    run2 lda #200
    sta 53248
    stx 53248+1
    sta 53248+2
    stx 53248+3
    lda #10
    sta 53248+28 ; multi sprite
    lda #15
    sta 53248+37
    lda #09
    sta 53248+38
    lda #00
    sta 53248+39
    lda #06
    sta 53248+40
    rts
    ;--------------------------------------------------
    gegner2
    ;--------------------------------------------------
    lda #129
    sta 2042
    clc
    adc #40
    sta 2043
    run3 lda #200
    sta 53248+4
    stx 53248+5
    sta 53248+6
    stx 53248+7
    lda #10
    sta 53248+28 ; multi sprite
    lda #15
    sta 53248+37
    lda #09
    sta 53248+38
    lda #00
    sta 53248+41
    lda #06
    sta 53248+40
    rts
    spriteb lda #149
    sta 2042
    clc
    adc #40
    sta 2043
    run4 lda #200
    sta 53248+4
    stx 53248+5
    sta 53248+6
    stx 53248+7
    lda #10
    sta 53248+28 ; multi sprite
    lda #15
    sta 53248+37
    lda #09
    sta 53248+38
    lda #00
    sta 53248+41
    lda #02
    sta 53248+42
    rts

  • Hm, nun versteh ich nciht so ganz, wovon Du sprichst... Allerdings weiß ich nun auch nicht, wie "frei" die Sprites eigentlich positioniert werden sollen. Klingt eher nach IK+ oder so, wo halt mehrere große Sprites immer in der gleichen Y-Position sind. In so einem Fall kann man sich allerdings das Leben schon erleichern.


    Ansonsten war ich halt von einem möglichst freien Multiplexer ausgegangen

  • was hoogo meint ist, du solltest dir sehr genau darüber klar sein welche sprites wie frei bewegt werden sollen/müssen. bei einem typischen jump'n'run zb wo die gegner mehr oder weniger ihre feste position im level haben und sich nicht grossartig in Y bewegen (ausser wenn das komplette level scrollt) kann man den multiplexer sehr viel einfacher auslegen. zb in dem man den screen in sagen wir 4 zonen einteilt in denen jeweils die sprites wiederverwendet werden, diese zonen können dann relativ statisch sein wenn man das leveldesign bzw die position der gegner passend anlegt. (anders als zb bei einem wilden shooter wo alle möglichen gegner wild durcheinander fliegen - da kommt man um das sortieren und dynamische zonen kaum rum)

  • @sauhund
    ja danke hatte ich mir auch schon so aehnlich gedacht.
    der hintergrund ist aber der, dass ich diese routine gern auch fuer zukuenftige projekte benutzen wollte, deshalb sollte diese so aufwendig wie moeglich programmiert werden....
    aber mal sehen man lernt ja mit der zeit dazu und werde vielleicht doch erstmal so verfahren wie ihr beide es vorschlagt

  • Zitat

    Originally posted by FrankDrebin


    der hintergrund ist aber der, dass ich diese routine gern auch fuer zukuenftige projekte benutzen wollte, deshalb sollte diese so aufwendig wie moeglich programmiert werden....


    In die 64er (ich glaube im Jahre Anfang 1994) gab's mal einen Sprite Multiplexer Kurs mit dokumentierem Assembler-Listing. Die Routine stammt vom Autor des Spiels EON und ist sehr universell und flexibel.


    Gruss,
    [HP]