GW-Basic Quellcode Veröffentlichung ;)

  • Wegen hier

    Microsoft veröffentlicht Quellcode von GWBASIC

    und da

    Ballphysik programmieren zB bei Pong ??


    d.h. aus aktuellem und fast aktuellem Anlaß ( Jan1980 ), hier mal eine eigene, abgehangene und unveränderte GW-Basic Routine, die mich mächtig stolz gemacht, als sie dann lief. Wenn man jetzt da drauf schaut, "geht da" sogar immer "noch was"; und Sprünge auf REM Zeilen sind evtl. auch nicht so ganz glücklich, aber was solls.

    Wenn also jemand sein GW-Basic auspacken mag ... es eignet sich auf jeden Fall für allerlei Grafikspielerei und Kleinprogrämmchen.


    Das hier macht auch als optischer Benchmark was her und ist auf große PCs ( etwa 486DX oder gar Pentium ) anpaßbar - mit z.B. MODE 12 und Y=480 und v.a. mehr Linien mittels z.B. u=24




    QBREFL.zip




       




       




       

    -- 1982 gab es keinen Raspberry Pi , aber Pi und Raspberries

  • Hmm, also in QBasic läuft's zumindest (siehe Bilder). Keine Ahnung mehr was ich dazumal benutzt habe.

    QuickBasic zumindest hatte ich nicht. Und eigentlich muß es wohl am ehesten ein DOS 4.01 gewesen sein.


    Den Sprung am Ende muß man halt dann evtl. noch auf die passende Zeilennummer anpassen. Der Rest sollte eigentlich passen; Grafik konnte das GW auf alle Fälle schon.

    -- 1982 gab es keinen Raspberry Pi , aber Pi und Raspberries

    Einmal editiert, zuletzt von ThoralfAsmussen ()

  • Das ist definitiv kein GWBASIC. Ich würde auch sagen QBASIC oder QuickBasic.

    QBASIC wurde irgendwann als GWBASIC-Ersatz bei MS-DOS mitgeliefert.


    Und wenn man statt i0=i0*-1 einfach i0=-i0 schreibt, könnte das möglicherweise auch etwas bringen.

    • i-Telex 7822222 dege d

    • technikum29 in Kelkheim bei Frankfurt

    • Marburger Stammtisch

    Douglas Adams: "Everything, that is invented and exists at the time of your birth, is natural. Everything that is invented until you´re 35 is interesting, exciting and you can possibly make a career in it. Everything that is invented after you´re 35 is against the law of nature. Apply this list to movies, rock music, word processors and mobile phones to work out how old you are."

  • Ist doch selbstdokumentierend - weil Hochsprache. :)


    OK, OK. Die Grundidee ist halt die, die man auch beim Ball reflektieren am Bildschirmrand benutzt. Man hat eine Koordinate (X,Y) für einen bewegten Punkt, die in jedem Schritt um dx,dy verändert wird. Wenn nun etwa der linke oder rechte Bildschirmrand erreicht wird, darf der Ball / Punkt natürlich nicht nach außen weiterwandern, weshalb die Bewegungsrichtung umgekehrt wird - einfach indem man das dx mit * -1 multipliziert und darum im nächsten Schritt in die andere Richtung "gewandert" wird; solange bis der gegenüberliegende Bildschirmrand erreicht ist, wo das Gleiche wieder passiert und die Richtung wieder umgekehrt wird.

    Das Gleiche geschieht unabhängig davon auch für eine Veränderung in Y-Richtung, mittels einem dy.


    Wenn man damit nun einen einzelnen Punkt über den Bildschirm laufen läßt, wird der an jedem Rand direkt reflektiert. Auch das sieht schon hübsch aus und mit einem Sprite gibt das schon gute Effekte.

    Im Text oben sind die Bezeichungen halt ein wenig ungewöhnlich; dx wäre i0 und dy heißt i1. Reflexion in Zeile 14 und 15 bzw. 30 und 31.


    Und dann sieht man daß es da noch j0 und j1 gibt. Das ist das Gleiche - ein Bewegungsdelta, nur eben für einen weiteren, zweiten Punkt auf dem Bildschirm, der reflektiert wird.


    Zwischen beiden Punkten, die unabhängig (!) voneinander über den Bildschirm wandern, wird eine Linie gezeichnet.


    Und an der Stelle wird es dann häßlich, wenn man viele Linien zeichnen will und dazwischen den Bildschirm löschen will. Darum wird das Ganze so gebaut, daß man in jedem Durchgang nur eine neue Linie hinzufügt (Zeile 37) und die letzte, die am "Bandende", direkt löscht, indem man sie mit Hintergrundfabe übermalt (Zeile 39).



    Um nun den Überblick zu behalten werden die Daten der Start-/Endpunkte der Linien in ein Array geschrieben. Dieses wird ganz am Anfang mit Startwerten vorbelegt, damit was drin steht, wobei das schon genauso funktionert, wie die spätere Schleife. Reflexionen werden also hier bereits berücksichtigt.


    In der Schleife selbst (ab Label "1", Zeile 27) passiert:

    Ganz oben ins Array ( Position "a" ) kommt immer der neueste berechnete Punktwert ; in der Schleife also in Zeile 29 der eine Punkt nach x0(a) und y0(a) und in Zeile 33 Punkt 2 ins andere Array x1(a) und y1(a). Anschließend folgt der Test, ob der Rand überschritten worden ist und wenn ja werden dx und dy (also hier i0 und i1 für Punkt 1 und j0 und j1 für Punkt 2 der Line) umgekehrt. Diese gelten so dann aber natürlich erst im nächsten Durchlauf der Runde. Und da man ja nur eine Line pro Runde neu erstellt reichen dafür 2 normale Variablen pro Punkt völlig aus.

    Nun wird die neue Line gezeichnet - für die beiden Punkt ganz oben im Array, die gerade neu berechnet worden sind. Und direkt danach wird die unterste Linie im Array ( Position 1 im Array; x0(1),y0(1) bis x1(1),y1(1) ) gelöscht, indem sie mit Hintergrundfarbe gezeichnet wird.


    Ganz zum Schluß werden alle Daten im Array um eine Position nach unten kopiert. D.h. die Werte der Eckpunkte der eben gelöschten Line werden weggeworfen und an ihre Stelle kommen die direkt darüber im Array liegenden beiden Start-/Endpunkte. Der gesamte Arrayinhalt wandert so um eine Position tiefer. 1 <- 2 <- 3 <- 4 <- ... (a-1) <- a

    Die neuesten, gerade berechneten Punkte, die ja eben als echte Linie mit sichtbarer Farbe gezeichnet worden sind, landen so relativ schnell auf dem vorletzten Platz ( der zweit-oberste ) - und das nur, damit im kommenden Durchlauf ganz oben Platz für den nächsten neu berechneten Wert ist.


    Dadurch beschränkt sich alles i.P. darauf jeweils Start-/Endpunkt neu zu berechnen, die Werte für dx,dy (für beide Punkte) jeweils anzupassen wenn nötig, dann aber nur zwei Linien zu zeichnen - eine hell, und eine, um sie zu löschen und dann als Hauptrechenteil alle Daten im Array um eine Position nach unten zu kopieren.


    Man spart dadurch - wenn man z.B. 24 Linien gesamt hat - das Zeichnen von 23 Linien ein - die bleiben einfach da wo sie sind. Und das Bildschirmlöschen und damit einhergehend Flimmereffekte fallen auch weg.

    Da Linienzeichnen relativ komplex ist, spart das halt extrem viel Rechenzeit.


    Die Hauptarbeit ist einfach das Umsortieren des Arrays.


    Und auch das kann man noch gut Optimieren - indem man a.) IntegerArrays benutzt [und b.) mit einer Zeigeradressierung arbeitet, und damit einfach auf den gerade aktuellen untersten Wert der Tabelle zeigt und diesen Pointer nach oben verschiebt, zumindest solange bis man irgendwann doch mal den obersten Tabellenteil komplett umkopieren muß und wieder unten beginnt].

    -- 1982 gab es keinen Raspberry Pi , aber Pi und Raspberries

    Einmal editiert, zuletzt von ThoralfAsmussen ()

  • Und auch das kann man noch gut Optimieren - indem man a.) IntegerArrays benutzt [und b.) mit einer Zeigeradressierung arbeitet, und damit einfach auf den gerade aktuellen untersten Wert der Tabelle zeigt und diesen Pointer nach oben verschiebt, zumindest solange bis man irgendwann doch mal den obersten Tabellenteil komplett umkopieren muß und wieder unten beginnt].

    Man könnte mit einem Ringpuffer arbeiten. Dann muss man gar nicht umkopieren.

    Die komplette Initialisierung des Arrays kann man sich sparen. Das füllt sich von selbst. ;)

    • i-Telex 7822222 dege d

    • technikum29 in Kelkheim bei Frankfurt

    • Marburger Stammtisch

    Douglas Adams: "Everything, that is invented and exists at the time of your birth, is natural. Everything that is invented until you´re 35 is interesting, exciting and you can possibly make a career in it. Everything that is invented after you´re 35 is against the law of nature. Apply this list to movies, rock music, word processors and mobile phones to work out how old you are."

    2 Mal editiert, zuletzt von detlef ()

  • Also ungefähr so. Ich habe mal die Array-Größe hochgesetzt. Die spielt ja nun für die Geschwindigkeit keine Rolle mehr.

    Das Array ist mit 0 vorbesetzt. Also werden erst mal Linien von 0,0 bis 0,0 gelöscht, bis sich das Array gefüllt hat.

    a ist der Zeiger in den Ringpuffer (modulo u). Es wird immer die Linie an Array-Position a gelöscht und dann die Linie für diese Position neu berechnet und gezeichnet.

    Ja und auch BASIC geht ohne GOTO - meistens. ;)


    Ich sehe gerade, die Reflexion ist glaube ich nicht ganz korrekt, weil erstens zuerst die Linie berechnet und dann die Grenzen geprüft werden. Und zweitens wird auf <0 und >640 bzw. <0 und >200 geprüft. Ich weiss gerade nicht mehr, ob die Koordinaten in Basic von 1 bis n oder von 0 bis n-1 liefen.


    • i-Telex 7822222 dege d

    • technikum29 in Kelkheim bei Frankfurt

    • Marburger Stammtisch

    Douglas Adams: "Everything, that is invented and exists at the time of your birth, is natural. Everything that is invented until you´re 35 is interesting, exciting and you can possibly make a career in it. Everything that is invented after you´re 35 is against the law of nature. Apply this list to movies, rock music, word processors and mobile phones to work out how old you are."

    5 Mal editiert, zuletzt von detlef ()

  • Ja - genau sowas schwebte mir da gestern Abend vor.

    Und funktionieren tut es auch - sehr gut sogar ! :applaus: :thumbup:


    Und natürlich wieder mal was mit dem unvermeidlichen "MOD Trick".

    Der sich hier auch noch prima anbieten würde, um die Farben zu bestimmen.



    Die Überprüfung der Grenzen ist tatsächlich nicht "korrekt". Daß das überhaupt funktioniert, ist der Gutmütigkeit des BASICs zuzuschreiben, was alle Grafikpunkte nochmal clipped. Das ist übrigens m.E. eines der wirklich guten Sachen in GW-BASIC respektive QBasic. Es ermöglicht nämlich, ein wenig schluderig Grafik-Zeug zu tippen, ohne sich da zu sehr Gedanken machen zu müssen. Allerdings hat das auch seine Grenzen; etwa Tangens Werte laufen irgendwann in den Variablenüberlauf und der reißt dann das Programm mit.

    Korrekter müßte man entweder die Deltas mitberücksichtigen und entsprechend die Grenzen weiter innen ansetzen - z.B. bei dx=5 Testen auf 5 und Maximal-5 oder man muß es verwerfen und quasi einen Schritt zurückgehen in der Berechnung, dann wird es wieder aufwendiger.



    Die Dimensionierung macht man netterweise mit

    DIM x0(u), y0(u), x1(u), y1(u) AS INTEGER

    und schon hat man Integervariablen. Woanders gibt es dafür irgendwelche Anhängsel für den Variablennamen.


    Das Basic da hat schon ein paar nette Eigenschaften. Auch die Schleifen gehören natürlich dazu.

    Dann aber gibt es auch wieder so typische MS Konstrukte: etwa LINE ( x0,y0 - x1,y1 ) ... sieht ja nett aus, schreibt sich aber extrem dämlich. Oder die Geschichte mit den Stringvariablen, wo man explizit mit MID$ heranmuß, wenn man einen Einzelbuchstaben herauslösen will.



    Nochmal zum Linienzeichnen: Was auch sehr hübsch aussieht ist, wenn man einen Punkt als Lissajous-Figur wandern läßt und nur der andere wird reflektiert.

    -- 1982 gab es keinen Raspberry Pi , aber Pi und Raspberries

    2 Mal editiert, zuletzt von ThoralfAsmussen ()

  • Ja, BASIC (speziell Microsoft Basic) ist sehr genügsam. Das habe ich beim Umstieg auf C schnell lernen müssen. Da fliegen einem solche Schludrigkeiten gleich um die Ohren. ;)


    Der Line-Befehl macht ein Clipping? Das ist natürlich komfortabel. Ich habe mich schon gewundert, dass bei der Reflektion keine Linien fehlen.

    • i-Telex 7822222 dege d

    • technikum29 in Kelkheim bei Frankfurt

    • Marburger Stammtisch

    Douglas Adams: "Everything, that is invented and exists at the time of your birth, is natural. Everything that is invented until you´re 35 is interesting, exciting and you can possibly make a career in it. Everything that is invented after you´re 35 is against the law of nature. Apply this list to movies, rock music, word processors and mobile phones to work out how old you are."