Bildschirm füllen beschleunigen

  • Das ist eben der Unterschied zwischen meinen Programmen und herkömmlichen Programmen.
    Da die von mir geposteten Lösungen meist auch ziemlich schnell und kurz für Basic sind kann ich es mir natürlich auch leisten zusätzlich Doppelpunkte einzubauen ohne das das Programm länger oder langsamer als andere Programme ist.

    . statt 0 wurde früher empfohlen, da der Punkt schneller verarbeitet wird, als die 0.
    Beides ist aber vom Wert her Null.

    Schönen Gruß.
  • Hallo, wenn es um das Nachladen von Levelscreens geht, dann könnte auch folgendes Listing interessant sein:


    Quellcode
    1. 0 :rem---datei-a
    2. 1 :a=a+1:printa:ifa=1then:poke44,192:load"level"+str$(a),8
    3. 0 :rem---level 1
    4. 10 :print"hallo":poke44,8:goto


    Schönen Gruß.
  • bei geschwindigkeitsproblemen in basic empfehle ich einfach auf assembler umzusteigen. noch besser: maschinensprache mit einem monitorprogramm.

    mit basic wird das alles nichts. da wirst du immer wieder probleme mit der geschwindigkeit haben. da löst du vielleicht das, aber das nächste wartet schon. das wird immer zu langsam sein.

    so einfach gehts in maschinencode:

    ldx #$00
    lda $8000,x
    sta $0400,x
    inx
    bne $0902

    und schon hast du in einem augenzwinkern 256 zeichen auf den bildschrim gefüllt. in $8000 schreibst du deine zeichen rein.
  • Noch mal zur Erklärung zu meinem letzten Listing.

    Mit dieser Methode kannst du deine Level-Screens ganz normal mit print-Befehlen coden und dann normal als Programm abspeichern.

    Mit Load in Zeile 1 wird dann dein Level-Screen nach 49152 ins obere RAM(4kB) geladen und gleichzeitig gestartet.

    Schnelligkeit ist natürlich auch eine Frage, welche Methode man anwendet.


    Schönen Gruß.
  • So nun versuch ich mal zu Antworten. Als erstes Vorweg ihr erschlagt mich ja fast mit Infos und Hilfestellungen, da komme ich ja fast nicht dazu das alles auszutesten aber nur weiter so :)
    @RKSoft, danke für den Tipp, aber das mit den DATA und RESTORE ist mit soweit bekannt, die Daten können nur einmal und zwar genau so wie sie im Code aufeinander folgen, verarbeitet werden. Mit RESTORE jedoch kann man DATA sozusagen zurückholen und erneut mit READ ab Anfang lesen.

    @Hexworx und alle anderen, die Levels beschränken sich nun nur noch auf zwei Zeichen, entweder chr$(32) also Leerstelle, oder aber chr$(230). Die ersten 3 Zeilen werden nicht benutzt, da diese zum HUD/Stautsbar gehören, es geht also um 880 Zeichen die befüllt werden wollen.

    Ich teste jetzt gerade an 3 Methoden rum:
    Methode 1: so wie anfangs erwähnt, jedes Zeichen ist als Byte in DATA gespeichert und wird in einer for-Schleife gelesen und gepoked. Das sind dann 880 Byte für jedes Level.
    Im BASIC Editor kommen dann nochmal fast soviele Kommas hinzu.

    Quellcode

    1. 12050 for i=0to879:reads:pO55296+120+i,c1(s):pO1024+120+i,h(s):next


    Methode 2: Ähnlich wie 1 jedoch werden die Zeichen nun bitweise kodiert, da nur zwei Zeichen benutzt werden. Damit verringert sich der Platzbedarf der DATA Zeilen auf 1/8 also auf 110 Byte. Das dekodieren der einzelnen Bits aus den Bytes dauert aber natürlich wesentlich länger womit das Level nun nochmals deutlich langsamer aufgebaut wird.
    Bei dieser Methode baue ich dann einen String zusammen der 16 Zeichen enthält und verwende dann den sys z-Befehl von oben um die Zeilen raus zu schreiben oder PRINT.

    Quellcode

    1. 5 a=55296+120:b=1144:ro=1
    2. 490 z=704:for i=0 to 25:reads:pokez+i,s:next: rem init fast print
    3. 500 gosub 12200
    4. 600 end
    5. 12200 rem *print levels from data bits
    6. 12205 sysz,10,2,chr$(31)+"loading level "+chr$(48+ro)+chr$(144);
    7. 12210 ?:fori=0to39:?chr$(230);:next i:for o=4 to 23:a$=""
    8. 12220 for m=0 to 4:
    9. 12230 read s:ab=256: for n=0to7:
    10. 12240 ab=(ab*0.5):if (s and ab)=ab then a$=a$+chr$(32):goto 12260
    11. 12250 a$=a$+chr$(166)
    12. 12260 next n:next m:
    13. 12270 ?a$;:next o:rem sysz,0,o,a$;:next o
    14. 12280 fork=0to38:?chr$(230);:next k:pOb+879,102
    15. 12285 sysz,10,2," ";
    16. 12290 return
    17. 38010 data 32,253,174,32,158,183,138,72,32,253,174,32,158
    18. 38020 data 183,104,168,24,32,240,255,32,253,174,76,164,170
    19. 40000 rem level 1
    20. 40010 data 127,191,191,255,254,127,191,191,255,254
    21. 40020 data 127,191,191,255,126,127,191,191,255,126,127,187,191,223,126
    22. 40030 data 127,251,191,223,254,127,251,191,223,254,127,251,191,223,254
    23. 40040 data 255,251,191,192,127,240,3,191,255,127,247,127,191,255,127
    24. 40050 data 119,127,191,248,126,119,127,191,255,126,119,112,63,255,126
    25. 40060 data 119,123,255,255,126,119,59,255,255,126,127,123,255,255,126
    26. 40070 data 127,127,255,239,254,126,127,255,207,246,127,127,255,207,230
    Alles anzeigen

    Methode 3 beinhaltet nur PRINT und die Zeichen also auf die Art so habt ihr das doch gemeint oder nicht? Das was ihr da jetzt seht, ist aber nur ca. der halbe Bildschirm, bin noch nicht weiter gekommen.

    Quellcode

    1. 8000 rem *print level 1
    2. 8010 ?:fori=0to39:?chr$(230);:next i:
    3. 8020 ?chr$(230)spc(8)chr$(230)spc(7)chr$(230)spc(21)chr$(230);
    4. 8030 ?chr$(230)spc(8)chr$(230)spc(7)chr$(230)spc(21)chr$(230);
    5. 8040 ?chr$(230)spc(8)chr$(230)spc(7)chr$(230)spc(14)chr$(230)spc(6)chr$(230);
    6. 8050 ?chr$(230)spc(8)chr$(230)spc(7)chr$(230)spc(14)chr$(230)spc(6)chr$(230);
    7. 8060 ?chr$(230)spc(8)chr$(230)spc(3)chr$(230)spc(3)chr$(230)spc(8);:
    8. 8061 ?chr$(230)spc(5)chr$(230)spc(6)chr$(230);
    9. 8070 ?chr$(230)spc(12)chr$(230)spc(3)chr$(230)spc(8)chr$(230)spc(12)chr$(230);
    10. 8080 ?chr$(230)spc(12)chr$(230)spc(3)chr$(230)spc(8)chr$(230)spc(12)chr$(230);
    11. 8090 ?chr$(230)spc(12)chr$(230)spc(3)chr$(230)spc(8)chr$(230)spc(12)chr$(230);
    12. 8100?chr$(230)spc(12)chr$(230)spc(3)chr$(230)spc(8);:fori=0to6:?chr$(230);:next
    13. 8101 ?spc(6)chr$(230);
    14. 8110?chr$(230)spc(3);:fori=0to9:?chr$(230);:next:?spc(3)chr$(230)spc(14);
    15. 8111 ?chr$(230)spc(6)chr$(230);
    16. 8500 return
    Alles anzeigen
    Wenn ich auf diese Art und Weise z.B. 10 Levels realisieren möchte, dann sind das einige Zeilen für den Interpreter. Schneller ist es allemal! Aber mir stellt sich nun die Frage, was ist Speicherplatz schonender, viele DATA Daten oder viele PRINT Zeilen im Code?

    Besten Dank schonmal für eure Mühe mir zu helfen :)
    Experto credite - 3d-druck-community.de
  • also mir wuerden da auch eher ein zwei kleine asm hilfroutinen reichen,die man ja auch als basicloader mir im programm haben koennte.
    die binaecodierten daten klingen fuer mich erstmal gut um platz zu sparen. diese koennte man schoen bei was weis ich $c000(45192) parken
    und mit einer kleinen asm routine auf den screen "poken".

    gegebenenfals koennte man so unzaelige leveldaten sogar unter den roms parken, auch waere ein nachladen der daten recht flott denk ich.
    coden muesste das dann aber mal wer anders, ich muesste mich erst wieder einarbeiten :anonym :P

    evtl koennte man auch den code von glaube hexworx fuer dieses kleine spielchen mit den leitern und platformen von (glaube RKSoft) benutzen,
    dann muessten aber glaube deine leveldaten nochmal anders ausschaun.

    salute
  • @zumili:

    Also grundsätzlich könntest du die chr$(230) durch einen String z.B. a$ ersetzen.
    Das würde den Code schon mal um einiges reduzieren.

    :a$=chr$(230):

    Für doppelte Zeichen :
    b$=a$+a$

    Steht ein spc() am Ende der Zeile kann das Semikolon glaub ich weggelassen werden.


    Schönen Gruß.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von BIF ()

  • zumili schrieb:

    Methode 3 beinhaltet nur PRINT und die Zeichen also auf die Art so habt ihr das doch gemeint oder nicht?
    Oder nicht. Was soll das Rumgewürge mit CHR$()? Das brauchst Du nur für das Anführungszeichen. Ansonsten kann man *jedes* Zeichen direkt im Zeichenliteral von PRINT unterbringen. Und dann sehen die Leveldaten z.B. so aus:

    Shell-Script

    1. 30 PRINT"****************************************";
    2. 31 PRINT"*.......*.......**********************.*";
    3. 32 PRINT"*.*************.........**************.*";
    4. 33 PRINT"*...............*******................*";
    5. 34 PRINT"****.******************.****************";
    6. 35 PRINT"*....******************.****************";
    An geeigneter Stelle fügst Du dann die Farbsteuercodes ein.

    Falls wo mal ein Anführungszeichen vorkommt (was man durch geschickte Kodierung des Zeichensatzes sicher minimieren kann), solltest Du es wie folgt ersetzen: Q$=CHR$(34)+CHR$(20)+CHR$(34). "Eingeflochten" wird es dann so: PRINT"blablubb"Q$"blubberblubb" (Semikolons zwischen " und Q$ und Q$ und " sind nicht notwendig). Der Delete-Code (20) löscht das erste Anführungszeichen, und das zweite dann erscheinende Anführungszeichen hebt den Quote-Mode beim PRINTen auf, den man da bestimmt nicht haben will.

    Du schreibst, daß Du ein PC-Entwicklungssystem zur Cross-Programmierung nutzt. Wenn das nicht mal anhand einer vorher definierten Bildschirmmaske (sprich: Level) genau solche PRINT-Anweisungen generieren kann, dann ist das an dieser Stelle sicher verbesserungswürdig.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Mike ()

  • Mikes Lösung ist schön einfach und gut editierbar. Und schnell.
    Man kann natürlich auch Levels packen und entpacken nach einer Anleitung, aber wenn der Speicherplatz ausreicht, würde ich die Levels in Unterprogramme packen die mit PRINTs bestückt sind. Da spart man sich auch die Verarbeitung durch DATAs.

    Ich selbst halbe mal in V2 Basic eine Art Editor geschrieben, mit dem man einen Bildschirmbereich frei mit Zeichen beschreiben kann und diesen Bereich dann auf Diskette abspeichern. Gespeicherte Bereiche können auch geladen und weiter bearbeitet werden. Das sollte für Petscii Logos sein oder auch als Level-Editor dienen. Nur schnell war das eben auch nicht, es wurde peek und poke benutzt, open und read und val und asc.

    Heute würde ich das in Basic so machen wie von Mike empfohlen.
  • Wenn Zeilen der Level öfter vorkommen, könnte man auch alle Zeilenvarianten in einem String-Array ablegen - und für die einzelnen Level benötigt man dann nur noch 22 Bytes: für jede Zeile den jeweiligen Index auf das Array. Die Leveldaten würde ich dann wiederum in einem Integer-Array mit Index für jedes Level ablegen. Kommt aufs Leveldesign und die Anzahl der Level an, wie hoch das Sparpotential ist. Aber so könnte eine schnelle Level-Ausgabe in BASIC mit sparsamen Speicherverbrauch kombinieren.
  • zumili schrieb:


    Ich teste jetzt gerade an 3 Methoden rum:
    [...]
    Methode 3

    Quellcode

    1. 8010 ?:fori=0to39:?chr$(230);:next i:
    2. 8020 ?chr$(230)spc(8)chr$(230)spc(7)chr$(230)spc(21)chr$(230);
    3. 8030 ?chr$(230)spc(8)chr$(230)spc(7)chr$(230)spc(21)chr$(230);
    4. 8040 ?chr$(230)spc(8)chr$(230)spc(7)chr$(230)spc(14)chr$(230)spc(6)chr$(230);
    5. 8050 ?chr$(230)spc(8)chr$(230)spc(7)chr$(230)spc(14)chr$(230)spc(6)chr$(230);
    6. 8060 ?chr$(230)spc(8)chr$(230)spc(3)chr$(230)spc(3)chr$(230)spc(8);:
    7. 8061 ?chr$(230)spc(5)chr$(230)spc(6)chr$(230);
    8. 8070 ?chr$(230)spc(12)chr$(230)spc(3)chr$(230)spc(8)chr$(230)spc(12)chr$(230);
    9. 8080 ?chr$(230)spc(12)chr$(230)spc(3)chr$(230)spc(8)chr$(230)spc(12)chr$(230);
    10. 8090 ?chr$(230)spc(12)chr$(230)spc(3)chr$(230)spc(8)chr$(230)spc(12)chr$(230);
    11. 8100?chr$(230)spc(12)chr$(230)spc(3)chr$(230)spc(8);:fori=0to6:?chr$(230);:next
    12. 8101 ?spc(6)chr$(230);
    13. 8110?chr$(230)spc(3);:fori=0to9:?chr$(230);:next:?spc(3)chr$(230)spc(14);
    14. 8111 ?chr$(230)spc(6)chr$(230);
    Alles anzeigen
    Die reine Levelinformation könnte man z.B. auch so ablegen:

    Quellcode

    1. data 0,41,8,1,7,1,21,2,8,1,7,1,21,2,8,1
    2. data 7,1,14,1,6,2,8,1,7,1,14,1,6,2,8,1
    3. data 3,1,3,1,8,1,5,1,6,2,12,1,3,1,8,1
    4. data 12,2,12,1,3,1,8,1,12,2,12,1,3,1,8,1
    5. data 12,2,12,1,3,1,8,7,6,2,3,10,3,1,14,1
    6. data 6,1,-1

    Das sind Paare von Sequenzlängen (erst Spaces, dann nicht-Spaces), und der negative Wert markiert das Ende. Aber im Augenblick sieht das hier sehr nach "premature optimization" aus - mach das Programm erst mal mit der einfachsten Variante lauffähig (d.h. Mikes Vorschlag). Irgendwelche fiesen Optimierungen kann man später vornehmen, dann hat man auch einen besseren Überblick darüber, ob es überhaupt einen spürbaren Vorteil bringen könnte.
    Insbesondere bei Leveldaten lässt sich nach dem Leveldesign viel besser abschätzen, auf welche Art und Weise sich die Daten am besten/einfachsten komprimieren lassen.
    Yes, I'm the guy responsible for the ACME cross assembler
  • Hallo, die Methode von @Mike funktioniert natürlich, wenn ich z.B. einen Stern * nehme. Möchte ich ein Sonderzeichen wie z.B. chr$(230) verwenden, dann kann ich das in VISE auch direkt eingeben mit STRG +, ich schreibe den Code jedoch noch in Notepad++ und kopiere dann die jeweiligen Zeilen in VISE hinein. Zu dem Sonderzeichen gibt es ja leider kein ASCII Pendant, daher habe ich die Variante mit den vielen chr$(230) gewählt. Ich habe mir auch schonmal C64Studio angeschaut, aber auch da muss ich chr$(230) verwenden und beim CBM prg Studio ebenfalls, soweit ich das bis jetzt durchschaut habe.
    Ich denke es dürfte auch nicht Sinn der Lösung sein nun das Zeichen zu wechseln. Ich könnte jetzt natürlich den Level z.B. mit Sternen aufbauen, aber dann sieht es nicht mehr so aus wie eigentlich gedacht.

    Schreibt ihr eure BASIC Programme immer direkt in VISE? Dann könnte man natürlich alle Sonderzeichen direkt vernwenden, das stimmt.

    @Mac Bacon, das mit den Paare von Sequenzlängen hatte ich auch schon überlegt, jedoch auch da habe ich wie beim bitweise kodierten Level das Problem, dass das Aufbauen des Levels bedingt durch einen größeren Rechenaufwand natürlich deutlich langsamer vonstatten geht.
    Experto credite - 3d-druck-community.de
  • zumili schrieb:

    Zu dem Sonderzeichen gibt es ja leider kein ASCII Pendant, daher habe ich die Variante mit den vielen chr$(230) gewählt.
    Auch dann ist es deutlich einfacher, einmal am Anfang c$=chr$(230) zu schreiben und danach die Variable zu verwenden. Schneller abgearbeitet wird es auch.
    Übrigens kommt mir "CHR$(230)" suspekt vor; am Anfang des Threads wurde der Screencode 230 verwendet. Das ist die invertierte Form des Screencodes 102, und dafür lautet der CHR$()-Code dann 166 (und chr$(230) ergibt das gleiche Zeichen - aber dann fehlt immer noch die Invertierung).

    zumili schrieb:

    das mit den Paare von Sequenzlängen hatte ich auch schon überlegt, jedoch auch da habe ich wie beim bitweise kodierten Level das Problem, dass das Aufbauen des Levels bedingt durch einen größeren Rechenaufwand natürlich deutlich langsamer vonstatten geht.
    Gib nicht jedes Zeichen einzeln aus, sonder benutz z.B. Stringfunktionen. Beispiel:

    Quellcode

    1. 1 data0,41,8,1,7,1,21,2,8,1,7,1,21,2,8,1
    2. 2 data7,1,14,1,6,2,8,1,7,1,14,1,6,2,8,1
    3. 3 data3,1,3,1,8,1,5,1,6,2,12,1,3,1,8,1
    4. 4 data12,2,12,1,3,1,8,1,12,2,12,1,3,1,8,1
    5. 5 data12,2,12,1,3,1,8,7,6,2,3,10,3,1,14,1
    6. 6 data6,1,-1
    7. 9 a$=chr$(166):b$=a$+a$+a$+a$+a$+a$+a$+a$
    8. 10 b$=b$+b$:b$=b$+b$:b$=b$+b$
    9. 11 printchr$(18);:rem reverse
    10. 12 reada:ifa>=0thenreadb:printspc(a)left$(b$,b);:goto12

    Hier ist a$ das Zeichen, b$ ein längerer String daraus. Aber wie schon gesagt: Halte Dich nicht mit solchen oder ähnlichen Optimierungen auf; Du würdest sie zum Schluss eh alle wieder ändern wollen.

    EDIT: In einem längeren Programm würde die Schleife wegen des GOTOs wieder bedeutend langsamer, da müsste man dann wieder mit FOR/NEXT herumfrickeln oder die Zeile an den Anfang des Programms stellen und per GOSUB anspringen - dies nur der Vollständigkeit halber.
    Yes, I'm the guy responsible for the ACME cross assembler
  • Wenn es um Schnelligkeit geht ist die Ablage in Datas wohl eher langsamer, da man dann noch so etwas wie einen Interpreter basteln muß.

    Ansonsten hier der komprimierte Code, mit der Ersetzung von chr$(230) mit a$ und b$.
    Das :poke19,1: bewirkt, daß echte Leerzeichen von spc() erzeugt werden.


    Quellcode
    1. 8010 a$=chr$(230):b$=a$+a$:poke19,1:fori=0to19:?b$;:next i:
    2. 8020 ?a$spc(8)a$spc(7)a$spc(21)
    3. 8030 ?b$spc(8)a$spc(7)a$spc(21)
    4. 8040 ?b$spc(8)a$spc(7)a$spc(14)a$spc(6)
    5. 8050 ?b$spc(8)a$spc(7)a$spc(14)a$spc(6)
    6. 8060 ?b$spc(8)a$spc(3)a$spc(3)a$spc(8)
    7. 8061 ?a$spc(5)a$spc(6)
    8. 8070 ?b$spc(12)a$spc(3)a$spc(8)a$spc(12)
    9. 8080 ?b$spc(12)a$spc(3)a$spc(8)a$spc(12)
    10. 8090 ?b$spc(12)a$spc(3)a$spc(8)a$spc(12)
    11. 8100?b$spc(12)a$spc(3)a$spc(8);:fori=0to6:?a$;:next
    12. 8101 ?spc(6)
    13. 8110 ?b$spc(3);:fori=0to9:?a$;:next:?spc(3)a$spc(14)
    14. 8111 ?a$spc(6)a$;:poke19,.


    Schönen Gruß.
  • Hier noch mal weiter koprimiert.
    Die FOR-Schleifen kann man natürlich auch noch z.T durch a$ und b$ ersetzen.

    Quellcode
    1. 8010 a$=chr$(230):b$=a$+a$:poke19,1:fori=0to19:?b$;:next
    2. 8020 ?a$spc(8)a$spc(7)a$spc(21)
    3. 8030 ?b$spc(8)a$spc(7)a$spc(21)
    4. 8040 ?b$spc(8)a$spc(7)a$spc(14)a$spc(6)
    5. 8050 ?b$spc(8)a$spc(7)a$spc(14)a$spc(6)
    6. 8060 ?b$spc(8)a$spc(3)a$spc(3)a$spc(8)
    7. 8061 ?a$spc(5)a$spc(6)
    8. 8070 ?b$spc(12)a$spc(3)a$spc(8)a$spc(12)
    9. 8080 ?b$spc(12)a$spc(3)a$spc(8)a$spc(12)
    10. 8090 ?b$spc(12)a$spc(3)a$spc(8)a$spc(12)
    11. 8100 ?b$spc(12)a$spc(3)a$spc(8)b$b$b$b$spc(6)
    12. 8110 ?b$spc(3)b$b$b$b$b$spc(3)a$spc(14)
    13. 8111 ?a$spc(6)a$;:poke19,.
    Schönen Gruß.
  • TheRyk schrieb:

    @Beef mit BIF:

    bei . statt 0 muss ich BIF verteidigen, besonders wenn es um Tempo geht (siehe Thread-Thema), ist . immer erste wahl
    Ja schon, aber das steht im Widerspruch zu den Doppelpunktorgien. Einmal soll die "Schnelligkeit" hervorgehoben werden und gleichzeitig soll es (nach biffschen Kriterien) auch "schön" ausschauen. Also, wenn man eine Lösung demonstriert, dann möglichst klar und möglichst ohne Finessen, die noch dazu nicht oder mäßig erklärt werden (wie beim vorig Genannten üblich).
    Zudem würde ich nicht eine mögliche Optimierung auch abwägend einsetzen, also dort wo es wirklich sinnvoll ist, etwa in einer Schleife, sonst fällt es nicht auf und hat auch vom Speicherplatz her keinen Nutzen. ;)