zatzen hat geschrieben:Ziemlich verspätet nun noch ein paar Antworten an DOSferatu:
DOSferatu hat geschrieben:
Auf C64 konnte man sich ja auf die Hardware-Sprites verlassen - da mußte man keinen "Hintergrund löschen".
Ich habe es nicht genau durchgedacht, aber die Idee (die sicher auch manch anderer schon hatte), hatte ich schon früher:
Statt mit Hintergrund komplett wieder drüber kopieren und Pufferung könnte man sich vielleicht merken bzw. bestimmen, welche Bildschirmbereiche von einem Sprite überdeckt sind und bei Umpositionierung des Sprites, welche Hintergrundbereiche wieder frei werden. Und dann eben nur immer das "umzeichnen" was sich wirklich verändert hat. Ist bei der praktischen Umsetzung wahrscheinlich langsamer und aufwändiger als die Puffer-Neuzeichnen-Methode, aber ein Gedanke daran kostet ja nix.
Das wäre eine ziemliche Aufgabe. Ich klamüsere das mal kurz auseinander:
Zuerst wird ein Sprite, z.B. 24x21 Pixel, gesetzt, der komplette vorherige Hintergrund in einen Puffer geschrieben. Nun wird das Sprite "verschoben", um 5 Pixel nach rechts und 3 Pixel nach oben. Das bedeutet: Es muß ein L-förmiger Bereich aus dem o,g, Puffer auf den Hintergrund wiederhergestellt werden, nämlich dort, wo vorher die "Ecke" des Sprites war, die jetzt nicht mehr dort ist.
Der Puffer muß intern ebenfalls verschoben werden um 5 Pixel nach links und 3 Pixel nach unten, dann das "Wiederhergestellte" wird nun nicht mehr gebraucht - außerdem muß ja Platz für das neu zu speichernde geschaffen werden. Beim Neuspeichern wird also ein L (eher 7-) förmiger Bereich aus dem Hintergrund gelesen (der Rest ist ja schon gelesen) und an den nun freigewordenen Bereich im Puffer geschrieben. Dieses Lesen muß natürlich passieren, bevor das Sprite neu gesetzt wird - eventuell auch während das Sprite gesetzt wird - dann aber nur für den neuen Bereich.
Somit braucht man soviele Puffer, wie man maximal Sprites darstellen will (auch für 2 gleiche Sprites natürlich 2 verschiedene Puffer). Eine andere Möglichkeit wäre, als Puffer gleich eine virtuelle Pixelmatrix zu verwenden, die quasi "hinter" dem Grafikbildschirm gedacht ist, mit der gleichen Größe und die Hintergründe immer gleich da hinein zu puffern, an der entsprechenden Stelle.
In beiden Fällen ist aber noch nicht davon geredet worden, was passiert, wenn sich Sprites (teilweise oder vollständig) überdecken. Hier muß dann natürlich erst Sprite 1 bis 20 gesetzt werden und beim "Löschen" (bzw Hintergrund wiederherstellen) von Sprite 20 bis Sprite 1 vorgegangen werden, bevor man erneut Sprite 1 bis 20 setzt - d.h. in solchen Fällen müßten trotzdem alle Sprites mindestens 1x gesetzt/gelöscht werden. Will man nur die gerade genutzten Sprites bewegen, geht das nur ohne Überdecken - denn sonst ergäben sich Probleme, wenn ein Sprite, das von einem anderen verdeckt wird, verschoben wird (es würde den unter ihm liegenden Hintergrund wiederherstellen - es sei denn, es das darüberliegende Sprite würde zusätzlich eine Bitmatrix setzen für nicht wiederherzustellende Bereiche.
Das ganze geht natürlich nur, wenn man Sprites nur rechteckig dreht und spiegelt, nicht in "krummen" Winkeln (wie es z.B. bei meinen Units möglich ist). Außerdem dürfte man, bei der "ein Puffer pro Sprite" Methode (s.o.) natürlich die Sprites nicht vergrößern - oder müßte die Puffer entsprechend groß anlegen.
Bei der "Wiederherstellen" Methode gehe ich davon aus, daß man nur mit einem Bild (also kein Double-/Triple-/... usw. Buffern) arbeiten will, denn anders wäre es ohnehin nicht möglich.
Dann sollte man nicht mit zu vielen Sprites arbeiten, wenn diese sich überdecken. Denn das Setzen Sprite 1 bis 100, dann Löschen Sprite 100 bis 1 und dann wieder Setzen Sprite 1 bis 100 usw. fällt irgendwann durch "Flackern" auf - es sei denn, man setzt zusätzliche Flags für verdeckte und nicht verdeckte Sprites.
Will man das ganze dann auch noch Scrollen und manche der Sprites sollen mitscrollen und manche nicht - oder Sprites sollen halb angeschnitten dargestellt werden - ergäbe das ganze eine nochmalige Steigerung der Schwierigkeit der Bearbeitung.
Ob diese ganzen komplexen Dinge wirklich den zusätzlichen Rechenzeitverbrauch, der durch permanentes Neuzeichnen entstehen würde, am Ende kompensieren, müßte wohl getestet werden. Ich selbst scheue mich davor, das wäre mir zuviel Geraffel.
Es gäbe noch eine weitere Methode, über die ich auch schon mal nachgedacht hatte: Man reduziert das ganze Spiel auf 128 Farben.
125 wäre eine gute Zahl: 5 Rot-, 5 Grün-, 5 Blau-Phasen, jeweils 0, 64, 128, 192, 255 für jede Phase. Von den restlichen 3 Farben wäre eine für die "Volltransparenz" bei Sprites gedacht, die anderen beiden beliebig belegbar, könnten z.B. dauerhaft "blinken" oder so, damit kann man im Hintergrund bestimmte Effekte erzielen.
Der Witz wäre nun der, für Sprites ausschließlich die Farben 0-127, für Hintergrund ausschließlich die Farben 128-255 zu benutzen - somit wäre eindeutig festlegt, was Sprite und was Hintergrund ist - dann wäre das Überdecken von Sprites vielleicht weniger ein Problem. Allerdings würde dies natürlich dazu führen, wieder mehr Auslesen zu müssen - und Auslesen von Grafikspeicher ist in der Regel langsamer als Schreiben (weil Schreiben in Grafikspeicher wesentlich häufiger vorkommt, wird dies von der Hardware meist schneller umgesetzt als Lesen).
Welches Bit man für Sprite/Hintergrund benutzt, ist hier unerheblich, es wäre auch z.B. statt Bit7 das Bit0 möglich: Gerade Farbnummer=Sprite, Ungerade Farbnummer=Hintergrund - oder umgekehrt.
zatzen hat geschrieben:Allerdings wäre diese Idee vielleicht eine mögliche Lösung bei zu langsamem Datendurchsatz der VGA Karte.
Ja, hier wäre vieles möglich. Ich frage mich immer noch, wie die Typen von ID-Software es bei Commander Keen geschafft haben, mit EGA Grafik (wirklich extrem besch...eiden anzusteuern) Scrolling und Sprites und dann noch auf 286er-Leistung hinzukriegen...
Naja, es sind immerhin die Leute, die dann Wolfenstein 3D[tm], Doom[tm] (und seine Nachfolger), Quake[tm] (und seine Nachfolger) gemacht haben - da frage ich mich sowieso öfter, ob die eine Hardware-Erweiterung im Gehirn haben oder sowas...
zatzen hat geschrieben:Ich finds ganz interessant, werd mal drüber nachdenken, ganz egal ob ich dann früher oder später merke dass es vielleicht Blödsinn ist.
Ja, wie man oben vielleicht lesen kann, habe ich das Problem schon von mehreren Seiten beleuchtet (das alles habe ich mir nicht gerade jetzt ausgedacht, das sind auch so die Gedanken, die mir über die ersten Jahre dazu gekommen waren) - und für mich persönlich (das kann natürlich jeder anders sehen) hatte sich hier schon recht früh der "Blödsinn" ganz klar herauskristallisiert.
Aber da ich auf PC sowieso vorhabe, meine 2D-Spiele mit Scrolling auszustatten, hatte sich diese Frage ohnehin nie wirklich gestellt - es waren eher "was wäre wenn" Überlegungen meinerseits.
zatzen hat geschrieben:DOSferatu hat geschrieben:[...ZVID clipping...] Ich weiß nicht, was Du in diesem Zusammenhang mit Clipping meinst. Betrifft das das "Verhalten am Bildrand" (z.B. bei halb-gescrollten "Kacheln")?
Ja, es geht einfach darum, dass man ein Sprite von einer Breite von sagen wir 16 Pixel auch z.B. an der x-Koordinate 316 darstellen kann, und dann eben nur die ersten 4 senkrechten Zeilen dargestellt werden sollen und der Rest abgeschnitten.
Ebenso oben, unten, und links. Das ist mit simplen Sprites einfach, aber in so einem komplexen Gefüge, aus 8x8 großen Blöcken mit jeweils unterschiedlichen Bit-Tiefen zusammengesetzt, und dabei auch noch je nachdem bei gleichen aufeinanderfolgenden Blöcken mit blockweiser Lauflängenkodierung, das überfordert mich erstmal.
Ja, das würde mich wohl auch überfordern.
Ich habe auch schon mal ein neueres Spriteformat angedacht, das, ähnlich wie mein DBM-Bildformat, die Daten senkrecht speichert, aber dabei zussätzlich bitbasiert arbeitet - um damit entsprechend der Farbanzahl des Sprites entscheiden zu können.
Ich supporte ja derzeit 15-Farb und 255-Farb-Sprites (1 Farbe jeweils für Transparenz), wobei es aber oft mal so wirkt, als wären 15 Farben zu wenig und 255 zuviel, 31 Farben sähen schon besser aus - aber 5 Bit ist echt eine blöde Zahl, um damit zu arbeiten.
Der Plan sähe nun vor, daß ein Sprite zu Anfang eine Festlegung hat, wieviele Bit UND wieviele Farben es hat, nehmen wir an 5 Bit, 20 Farben. Dann würde immer 5 Bit-weise aus dem "Datenstrom" des Sprites die Daten gezogen werden, 0 wäre die Transparenz, die Werte 1 bis 20 wären in dem Fall die ungepackten Farben, die Werte 21 bis 31 würden für die Lauflängencodierung oder ähnliches benutzt werden. Beim "Packen" des Sprites würde nun für 5 Bit, 6 Bit, 7 Bit, 8 Bit und 9 Bit geprüft werden (also mindestens ab Farbanzahl aufgerundet auf ganze 2er Potenz), ab wo sich die geringste Größe einstellt.
Die Lauflängencodierung könnte ihrerseits weiter gesplittet werden, z.B. könnte man für eine Anzahl von mehr als 2 Pixeln einen Bereich nehmen, z.B. Werte 21 bis 27, damit könnte man dann 3 bis 9 Pixel "packen" (wobei ein Pixel auch der 0-Pixel wäre). Ab 3 deshalb, weil dies 2 "Frames" (5-bit Werte) bräuchte: Anzahl und Farbnummer. Werte 28 bis 31 (2 Bit) wären dann die oberen oder unteren 2 Bit einer Adresse im Sprite, gefolgt von den restlichen 5 bit, rückwärts ausgehend vom derzeitigen Standpunkt, um auf dortige Daten hinzuweisen, um diese zu "wiederholen" (ähnlich GIF). Damit ein Sprite nur "halb" dargestellt werden kann, ohne alle Spalten vorher zu lesen, gäbe es eine Konvention, daß gepackte Daten nicht über das untere Ende von Spalten hinausgehen dürften.
Beim Lauflängen-Packen (s.o. mit dem Beispiel Werte 21 bis 27) wäre ja auch die Farbnummer wieder nur 0 bis 20, somit wären die Werte 21 bis 31 invalid, könnten aber natürlich eine Erweiterung der Anzahl darstellen, d.h. es gäbe dann so viele 5-Bit-Werte 21 bis 31, die immer weiter multipliziert/aufaddiert würden, bis die gewünschte Anzahl erreicht wäre und dann käme ein Farbwert 0 bis 20.
Klingt alles schick, würde weniger Sprite-Speicher verbrauchen, aber mehr Rechenzeit, um Sprites darzustellen. Außerdem wären damit nur Sprites darstellbar, die gespiegelt, in 90° Winkeln gedreht und evtl vergrößert/verkleinert wären möglich, aber NICHT solche, die in beliebigen krummen Winkeln gedreht wären (außer man entpackt das Sprite in einen Puffer und stellt es dann erst dar - für die Methode mit dem "Verweis auf andere Bereiche" müßte dies ohnehin geschehen).
Enthielte ein 20-Farb-Sprite nun viele Flächen oder viele "wiederholende Bereiche", könnte eine Erweiterung auf 6-Bit hier sogar Vorteile/Einsparungen bringen. Der Sprite-Packer würde somit die entsprechenden Möglichkeiten durchtesten und die mit dem geringsten Speicherverbrauch am Ende ausgeben. Das Problem mit den Spalten könnte nun so gelöst werden, daß das Sprite, wenn es größer ist, am Anfang optional eine Tabelle für die Spaltenanfänge enthält (wäre nicht nötig, wenn sowieso vorher in einen Puffer entpackt wird), die angibt, an welchem BIT (nicht Byte!) in den Spritedaten als nächstes gelesen werden soll, d.h. der Byte-Offset stünde z.B. in den oberen 13 bit und der Bit-Offset dann in den unteren 3 (für eine Tabelle aus Words).
Das sind nur so Ideen, die ich so habe, wenn es um das Speicher-Spar-Thema geht. Aber ich versuche ja immer, einen guten "Trade-Off" zwischen Speichersparen und Rechenzeitsparen zu finden. Außerdem kann es auch manchmal passieren, daß man, um Datenspeicher zu sparen, soviel Code schreibt, daß der zusätzliche Code die Menge des gesparten Datenbereichs überschreitet und zusätzlich auch mehr Rechenzeit verbraucht. In solchen Fällen rudere ich dann gern auch mal zurück. Die komplizierte Lösung ist nicht in jedem Fall die beste.
Außerdem gibt es Grafiker, die auch ein 15-Farb-Sprite (15 aus 255 Farben) gut aussehen lassen können und andererseits welche, die selbst mit 255 Farben nicht auskommen, weil sie so an ihre 16 Millionen-Farb-Malprogramme gewöhnt sind, daß darunter gar nichts mehr geht.
Gerade im Bereich der 640kB Speichergrenze, der 50 bis 200 MHz Leistung usw. sind aber wohl eher die die wahren Helden, die mit wenigen Mitteln viel leisten können als umgekehrt. Solche Leute sucht man, wenn man ein DOS-Spiel bauen will.
zatzen hat geschrieben:Leider aber kriege ich das vorerst nicht mit dem Clipping hin, ich kann also ZVID nur für Hintergründe bzw. für "Level-Steine" benutzen, oder eben für Sprites in einem Spiel wo die Sprites niemals über den Bildschirmrand hinausgehen.
Ja, ist eben etwas schade. Du bist Dir natürlich klar, daß, selbst wenn man ZVID für ein 2D-Spiel einsetzen wollen würde, natürlich ein Block-/Sprite-/Level-Editor vonnöten wäre, der dann alles im entsprechenden Format speichert.
Die Stärken von ZVID sehe ich da vor allem bei 2D-Point&Click-Adventures.
zatzen hat geschrieben:Ich kann mich an deinem Musikprogramm gerne mal versuchen, allerdings tue ich mich schwer mit Benutzerinterfaces die anders sind als die von meinem Tracker, der im Borland-Stil gehalten ist.
Oh, den Borland-Stil wirst Du in prISM auch wiedererkennen. Hält man ALT gedrückt oder schiebt den Mauszeiger auf die oberste Bildzeile, erscheint oben diese Menüzeile mit den entsprechenden Auswahlpunkten, die dann jeweils ein Pulldown erzeugen. Die untere Zeile ("Statuszeile") ist kontextabhängig, je nachdem, ob man gerade in einem der Musikfenster arbeitet oder in einem der Pulldowns steht.
Es ist einfacher als es auf den ersten Blick den Anschein hat.
Ich habe soeben auf meinen Webspace unter
http://www.imperial-games.de/z/prism.zip
hochgeladen. Dieses enthält:
* prISM.exe, wav2smp.exe, sndcheck.exe, outwave3
* die ISM-Beschreibungstexte _ISM.TXT und _ISMFILE.TXT
* die Beispielfiles playbox.ism und shooter.ism
* Ente.wav (als Hörbeispiel)
Du kannst ja mal schauen, ob Du etwas damit anfangen kannst.
zatzen hat geschrieben:Ich habe übrigens noch ein paar Basic-Spiele, die bis 1992 zurückgehen, aber alles schon mit 256 Farben VGA Grafik. Die habe ich nur bisher nicht präsentiert, weil sie auf einem 286er konzipiert wurden und natürlich auf späteren Rechnern zu schnell liefen. Aber in dosbox lässt sich das ganz gut regeln.
Ich interessiere mich bekanntermaßen immer für die Arbeit von Programmierer-Kollegen.
Naja, man könnte auch nachträglich Timerschleifen oder Timing mit dem DOS-Ticker einbauen. Für Timerschleifen habe ich übrigens mal eine Unit geschrieben, die den DELAY Befehl ersetzt und mit einem 63-Bit (statt 16-Bit) Wert arbeitet.