Da ja eine Sprite-Hintergrundkollision mir nur den Wert zurückgibt dass eine Kollision stattgefunden hat aber nicht mit welchen Zeichen, wollte ich fragen wie ihr das so löst.
Meine Idee wäre es die Sprite Koordinaten mit einer Tabelle zu vergleichen um dann an gegebener Stelle die Hintergrund Kollision abzuschalten und dann eine dementsprende Aktion ausführen.
Wäre das so der richtige Ansatz?
Hallo Besucher, der Thread wurde 9,1k mal aufgerufen und enthält 43 Antworten
letzter Beitrag von Acorn am
Sprite Hintergrund Kollision
- giben
- Erledigt
-
-
in der Praxis wird die Spritekollision fast nie verwendet.
Es ist recht einfach, die Sprite Position zu nehmen, ein Offset abzuziehen und dann via LSRs durch 8 zu teilen, um auf die Charposition zu kommen. -
ein Offset abzuziehen und dann via LSRs durch 8 zu teilen, um auf die Charposition zu kommen
Verstehe ich jetzt nicht ganz
Hast du vieleicht ein Beispiel? -
Sprite Position ist in Pixeln, Chars jeweils 8 pixel.
Also teilt man durch 8.
Die Spritekoirdinaten bei Zeichen 0,0 sind aber nicht 0,0. Daher das offset.
Für y nimmt man eine Tabelle die Zeilenanfänge enthält oder rechnet 40*y.
Dazu addiert man x und hat die Position bzw Adresse des Chars beim Sprite.
Über den Offset bestimmt man auch, wo im Sprite man sein möchte. In Turrican werden zB drei Chars unter den Füßen ständig überprüft. -
Also vom Prizip her habe ich es verstanden.
Gibt es irgend wo ein code Beispiel wie ich das umsetzen könnte? -
Vielleicht hilft Dir das Beispiel aus der Codebase64 weiter.
-
-
Ypos ist nicht MSB des screenram pointers.
Y * 40 + SCREENRAM_START ist es.
Oder um sich das * 40 zu sparen eine lookuptable. -
ich trau mich schon fast nicht mehr zu fragen, aber was ist eine Lookuptable?
Und wie setzt man so was ein? -
Lookup = Nachschlagen
Lookup-Table = Eine Tabelle zum schnellen Nachschlagen von Werten, damit diese während des Spiels nicht umständlich berechnet werden müssen.In der Tabelle speichert man vorberechnete Werte, um Programme zu beschleunigen. Besonders in Graphikroutinen z. B. bei der Adreßberechnung sind solche Tabellen sehr hilfreich, zumal sie - wie im vorliegenden Fall - auch gar nicht so viel Platz einnehmen.
Je nach Assembler läßt sich die Tabelle für die Bildschirmadressen nach folgendem Schema anlegen:
Code- bildschirm: .equ $400 ; Adresse des Textschirms
- bildschirm_low:
- .byte (bildschirm + 0 * 40) & $ff ; Low-Anteil der Adresse der ersten Bildschirmzeile
- .byte (bildschirm + 1 * 40) & $ff ; Low-Anteil der Adresse der zweiten Bildschirmzeile
- .byte (bildschirm + 2 * 40) & $ff ; Low-Anteil der Adresse der dritten Bildschirmzeile
- usw.
- .byte (bildschirm + 24 * 40) & $ff ; Low-Anteil der Adresse der untersten Bildschirmzeile
- insgesamt sind es 25 Werte von 0 bis 24.
- bildschirm_high:
- .byte (bildschirm + 0 * 40) >> 8 ; High-Anteil der Adresse der ersten Bildschirmzeile
- .byte (bildschirm + 1 * 40) >> 8 ; High-Anteil der Adresse der zweiten Bildschirmzeile
- .byte (bildschirm + 2 * 40) >> 8 ; High-Anteil der Adresse der dritten Bildschirmzeile
- usw.
- .byte (bildschirm + 24 * 40) >> 8 ; High-Anteil der Adresse der untersten Bildschirmzeile
- insgesamt sind es 25 Werte von 0 bis 24.
Achtung: Die Syntax variiert hierbei von Assembler zu Assembler. Einige Assembler erlauben es auch, Tabellen mit einer FOR-Schleife zu erzeugen. Dazu müßtest Du Dir mal passende Codebeispiele für Deinen Assembler ansehen.
Es existieren nun zwei Tabellen für den Bildschirm: die eine enthält nur den niederwertigen (low) Anteil der Adresse, die andere nur den höherwertigen (high). Diese Spaltung in low und high hat den Vorteil, daß man die Tabellen sehr einfach mit einem Indexregister indizieren kann, um die passende Adresse zu bekommen:
CodeWenn Du ganz schnellen Code haben willst, kannst Du auch Tabellen erzeugen für jede Sprite Y-Position, ohne vorher Y durch 8 zu teilen, d. h. die Tabelle wird entsprechend 8 mal so groß, da jeder Eintrag (von 0..24) 8 mal nacheinander geschrieben wird. Dadurch spart man sich dann das umständliche dreifache LSR. Außerdem läßt sich noch mehr Code sparen, indem man den festen Offset nicht mehr von Y abzieht, sondern einfach die Anfangsadresse der Tabellen im Code um diesen festen Wert reduziert:
Dies wäre die schnellste Methode, um die Adresse einer Zeile zu berechnen. Da es eher nicht wahrscheinlich ist, daß Dein Programm den ganzen Speicher des C64 belegt, kannst Du Dir ruhig den komfortablen Luxus erlauben, solch große Tabellen anzulegen.
Nebenbei: Man kann diese Tabellen auch vom Programm zu Beginn einmalig berechnen lassen und muß sie damit nicht in den Programmcode einfügen, oder man läßt sie zusammen mit dem restlichen Programm mit dem Exomizer packen.
Eine Sache noch zu den X-Koordinaten:
Die Sprite-X-Koordinaten benötigen auch immer ein Highbyte, selbst wenn dieses nur die Werte 0 und 1 annehmen kann. Bei der Subtraktion des X-Offsets (24) müßte man also so etwas schreiben wie:CodeUnd zum Schluß noch der Hinweis, daß man unbedingt die Sonderfälle berücksichtigen muß, bei denen das Sprite teilweise außerhalb des Bildschirms ist. Entweder vermeidet man dies generell, oder die Berechnungen werden ein wenig komplizierter.
-
Ich werde es mir genau anschauen.Danke!
Gibt es irgendwo eine genaue Beschreibung damit ich das hier verstehe?
.byte (bildschirm + 0 * 40) & $ff
speziell das "$ff" und ">>8"
-
>> und << sind bitweises rotieren = /2 und *2.
>> 8 ist also ein /256
das & ist ein bitweises UND.
Das gibt zusammen als das MSB eines 16 bit words aus.
Viele Assembler nehmen zB auch #>adresse und deuten das '>' als MSB.
(MSB hier: most significant byte) -
-
-
Stimmt das ! voraus nicht der .
Copy paste Fehler von mir -
Hab mal was dank eurer Hilfe sowas zusammengebastelt und funktioniert auch soweit:
Codeist das so der richtige Weg?
-
Genau so geht das.
Es fehlt nur noch das MSB (=9. bit) für die x-Positionen des sprites -> vgl. Beispiel auf der codebase. -
Cool, dann bin ich also auf den richtigen Weg.
Bin jetzt sogar so weit, dass ich das Zeichen abfragen kann mit dem das Sprite kollidiert
Nur vertehe ich noch nicht das mit der x-Position MSB.
Wozu brauche ich das, wenn es doch funktioniert?
Ach ja, danke für eure Gedult -
Wozu brauche ich das, wenn es doch funktioniert?
Es funktioniert nur, solange Du die X-Position der Sprites auf 0 .. 255 beschränkst. Der Bildschirm hat in X-Richtung jedoch mehr als 256 Pixel. Um Dein Sprite auch am rechten Rand anzeigen lassen zu können, brauchst Du für einen kompletten X-Wert noch ein 9. Bit. Damit kann man von 0 .. 511 zählen, was für den C64 ausreicht. Dieses 9. Bit speichert man in einem zusätzlichen Byte des X-Wertes. Anders als für Y nimmt man für den X-Wert also stets zwei Bytes. MSB ist hierbei die Abkürzung für "Most Significant Bit" oder einfacher gesagt "das höchste Bit". Wenn der vollständige X-Wert aus 9 Bits besteht, werden die ersten 8 in das erste Byte der Koordinatenvariable gespeichert (Low Wert) und das MSB (das 9. Bit) dann in ein weiteres Byte (High Wert) - auch wenn es vielleicht etwas verschwenderisch erscheint, für ein Bit gleich ein ganzes Byte im Speicher zu verbrauchen.
Nebenbei: Guck Dir mal die Register des VIC an. Dort findest Du bei $d000, $d002, $d004 jeweils die ersten 8 Bit des Sprites. Bei $d010 jedoch liegen die gesammelten MSBs der Sprites. -
Nächstes Problem :
Zuerst hatte ich nur Die Sprites nach $2000 kopiert dann den "level1" nach $0400.Ok, so weit so gut und es funktionierte tadellos.
Nur wenn ich jetzt die Zeile mit "title" hinzufügen, dann ist mein Sprite "zerschossen"
ich habe den Verdacht, dass damit meine Sprites überschrieben werden, zumindest ein Teil davon.