DisplayList für Neueinsteiger #1

Moderator: Rockford

Antworten
Online
Benutzeravatar
Dr. Irata
Beiträge: 937
Registriert: 24.08.2021 14:40
Has thanked: 110 times
Been thanked: 268 times
Kontaktdaten:

DisplayList für Neueinsteiger #1

Beitrag von Dr. Irata »

DisplayList #1

Wenn man (so wie ich damals in den 80-igern) Programme in einer Hochsprache entwickelt - damals auf dem Atari 800 z.B. in BASIC, dann ist man nicht unbedingt darauf angewiesen ein tieferes Verständnis der grafischen Bildschirmausgabe zu besitzen. Das BASIC hat bereits entsprechende Befehle integriert und übersetzt am Ende alles in den entsprechenden Maschinencode. So ist es dann einfach z.B. eine „Hallo Welt“- Ausgabe zu programmieren:
10 Print „Hallo Welt“
20 Goto 10

Ein entsprechender Print-Befehl existiert in Assembler nicht und wenn man etwas auf den Bildschirm bekommen möchte, dann stößt man recht bald unweigerlich auf die DisplayList. So erging es auch mir!
Aber was genau passiert denn da? Der Name zunächst ist völlig irreführend, denn es handelt sich dabei gar nicht um eine Bildschirm Liste, sondern um Programmanweisungen eines ganz eigenen Prozessors - dem ANTIC. Vielfach gehört, aber wie genau erzeugt dieser Chip das Bild und wie kann ich das beeinflussen und steuern?

Die Idee eines solchen Prozessors war zwar damals nicht neu, für den Heimcomputerbereich aber schon fast revolutionär. Der ANTIC liest dabei Daten aus dem Hauptspeicher, verarbeitet sie und baut dann entsprechend den Bildschirm auf.
Zusätzlich sorgt der ANTIC-Prozessor auch für die Generierung der Player-/Missile Grafik.
Der Antik kann nur lesen und keine Daten in den Prozessor zurückschreiben, um dieses Problem zu lösen gibt es die Schattenregister…

Die Befehle, die der Anti verarbeiten kann sind eigentlich recht simpel. Es gibt einen Vectorbefehl, wo angegeben ist, wo der Bildschirm anfängt und einen Sprungbefehl, der saget, wo die Displaylist wieder startet. Alle anderen Displaylisteinträge sind keine Befehle im eigentlichen Sinn, sondern stellen nur Werte dar, wie die einzelnen Zeilen aufgebaut werden.

Wenn man jetzt weiß, an welcher Speicherstelle der Bildschirm bei Graphics 0 (in Basic) anfängt, kann man relativ einfach durch ein Poke-Befehl im Basic oder durch LDA / STA in Assembler eine Ausgabe auf den Bildschirm machen:
Zum Experimentieren empfehle ich das in Basic, das kann man dann relativ einfach in Assembler umsetzen:

Poke 40000,33 läßt links oben ein A entstehen, denn dort fängt der Bildschirm im Speicher an… und dieser Anfang wird in der DL festgelegt!

In den Speicherstellen 560 (LoBi) und 561 (HiBi) steht die Adresse des DL:
Print Peek(560)
32
Print Peek(561)
156
Print 32+256*156
39968

Am Beispiel von Graphics 0 fängt die DL also an der Stelle 39968 im Hauptspeicher an.
Hier geht es los mit drei Einträgen 112
? Peek(39968), Peek(39969), Peek(39970)
112 112 112
Das sind die drei schwarzen Zeilen am oberen Rand, die einfach leer sind.
Poke 39968,2 würde eine leere Textzeile am Oberrad erzeugen (die man aber nicht beschreiben kann).

An Stelle 4 des DL (also bei Speicherstelle 39971 kommt ein erster echter Befehl: 64 - dieser benennt die Adresse des Bildschirmstartes mit den zwei folgenden Stellen (Stelle 5 und 6):
Peek(39972) liefert 64 und Peek(39973) liefert 156

64+256*156 ergibt 40000 - also die Startadresse des Bildschirmes.
Will man also die Startadresse des Bildschirmes ändern (wird z.B. scrollen wichtig), dann ändert man einfach diese beiden Adressen entsprechend!

Danach folgen 23 x die Speichereinträge 2 - diese legen letztlich den Textmodus für Graphics 0 fest und danach kommt der Sprungbefehl (65) mit den nachfolgenden beiden Speichereinträgen, die festlegen wohin gesprungen werden soll - nämlich wieder zum Anfang der DL, die ja ständig wiederholt abgearbeitet werden muss.
Warum nur 23x2 ? Wir haben ja 24 Zeilen! Das steckt witzigerweise in Stelle 4 der DL im Befehl mit drin. Der Befehl an Stelle 4 der DL ist eigentlich Dezimal 64, in der Stelle 4 steht aber 66. Hier wird einfach schon die erste zu generierende Zeile zum Befehl addiert. 64+2=66
Ich denke, die Atari-Entwickler wollten damit ein wenig Verwirrung stiften ;-)

Das wars eigentlich schon, was den Aufbau der DL angeht. Im Anhang noch eine schöne Übersicht über die DL bei Graphic 0.

In Teil 2 wird man dann erfahren, was es für Auswirkungen haben kann die DL zu verändern, wie flexibel man alles mischen kann und wie man einfach eigene Grafikmodi erstellen kann.
Dateianhänge
DisplayList.png

Online
Benutzeravatar
Dr. Irata
Beiträge: 937
Registriert: 24.08.2021 14:40
Has thanked: 110 times
Been thanked: 268 times
Kontaktdaten:

Re: DisplayList für Neueinsteiger #1

Beitrag von Dr. Irata »

Hier noch kurz mein Listing für "Hallo Welt":

Basic:
10 Print "Hallo Welt"
20 Goto 10

Assembler:

Code: Alles auswählen

10 ;Hallo Welt Demo einfach
20		*= $4000
30		LDA #40
40		STA $9C40
50		LDA #33
60		STA $9C41
70		LDA #44
80		STA $9C42
90		STA $9C43
100		LDA #47
110		STA $9C44
120		LDA #55
130		STA $9C46
140		LDA #37
150		STA $9C47
160		LDA #44
170		STA $9C48
180		LDA #52
190		STA $9C49
200		LDA #00
210		STA $9C45
220		STA $9C4A
Dieser Assemblercode ist hier bewusst ganz einfach gewählt!
Etwas komplexer wird es dann hier:

Code: Alles auswählen

10 ;Hallo Welt Demo Komplex
20		.OPT OBJ
30		*= $4000
40 RET = $9B
50 IOCB = $0340
60 CIOV = $E456
70 DEVICE .BYTE "E:",RET
80 TEXT .BYTE "HALLO WELT!",RET
90		LDX #$20
100		LDA #$03
110		STA $0342,X
120		LDA #DEVICE&255
130		STA $0344,X
140		LDA #DEVICE/256
150		STA $0345,X
160		LDA #$08
170		STA $034A,X
180		LDA #$00
190		STA $034B,X
200		JSR CIOV
210		LDA #$09
220		STA $0342,X
230		LDA #TEXT&255
240		STA $0344,X
250		LDA #TEXT/256
260		STA $0345,X
270		LDA #$00
280		STA $0348,X
290		LDA #$FF
300		STA $0349,X
310		LDA #$FF
320		STA $02FC
330 LP	JSR CIOV
340		LDA $02FC
350		CMP #$FF
360		BNE STOP
370		JMP LP
380 STOP	BRK
390		.END
Das Programm startet nicht bei 4000, sondern bei 400F !!
Man sieht an diesem Beispiel wie komplex die Programmierung einfacher Anwendungen in Assembler werden kann.
Zur Ausgabe von Hallo Welt wurde zudem in diesem Beispiel die CIOV des Ataris benutzt, man könnte den Text natürlich auch direkt auf den Bildschirm ausgeben - was allerdings in diesem Fall etwas weniger elegant ist.
Dies würde dann den Text "Hallo Welt!" quasi Buchstabe für Buchstabe zerlegen und dann in den Bildschirmspeicher direkt kopieren - ähnlich wie im ersten etwas plumpen Listing.
Zuletzt geändert von Dr. Irata am 03.09.2021 21:37, insgesamt 3-mal geändert.

Benutzeravatar
cas
Beiträge: 813
Registriert: 18.06.2021 21:01
Wohnort: Solar System
Has thanked: 181 times
Been thanked: 362 times
Kontaktdaten:

Re: DisplayList für Neueinsteiger #1

Beitrag von cas »

Prodehl hat geschrieben:
03.09.2021 20:16

Leider macht dieser Editor alle Tabs weg, die müssen natürlich im Assembler rein!
Umschliesse Quellcode mit [ code ] [ /code ] Bloecken (nur ohne die Leerzeichen hinter [ und ]), z.B.:

Code: Alles auswählen

10 ;Hallo Welt Demo einfach
20		*= $4000
30		LDA #40
40		STA $9C40
50		LDA #33
60		STA $9C41
70		LDA #44
80		STA $9C42
90		STA $9C43
[...]
Dann sieht es besser aus ;)
Prodehl hat geschrieben:
03.09.2021 20:16
Wenn man dies jetzt per copy/paste in den Assembler überträgt, dann werden die Anführungszeichen nicht mitkopiert ...
In deinen Beispielen sind typografische Anfuehrungszeichen, wie sie von Textverarbeitungen erzeugt werden. Die kennt der Atari nicht, daher verschwinden die. Ggf. oben im Post durch echte Anfuehrungszeichen "" ersetzen.

Online
Benutzeravatar
Dr. Irata
Beiträge: 937
Registriert: 24.08.2021 14:40
Has thanked: 110 times
Been thanked: 268 times
Kontaktdaten:

Re: DisplayList für Neueinsteiger #1

Beitrag von Dr. Irata »

thx ;-)

Online
Benutzeravatar
Dr. Irata
Beiträge: 937
Registriert: 24.08.2021 14:40
Has thanked: 110 times
Been thanked: 268 times
Kontaktdaten:

Grobscroll durch Manipulation der Displaylist

Beitrag von Dr. Irata »

Der Graphikbildschirm hat im Textmodus 24 Zeilen a 40. Jede Zeile in der Displaylist bekommt also eine 2 eingeschrieben (die ersten 24 Scanlines bleiben leer).
Die erste Zeile hat dabei nicht den Wert 2 sondern 66 (64+2) - wobei die 64 einen Adressbefehl darstellt - nämlich den des Bildschirmanfanges. Es folgen dann die 23 nächsten Zeilen mit dem Wert 2 und danach kommt noch der Sprungbefehl mit Adresse des Displaylistanfanges.

Nun möchten wir folgendes machen: In jede Zeile schreibe ich statt einer 2 eine 66 (alles dezimal) rein mit der jeweiligen um eine Zeile höheren Adresse für den Bildschirm:
66 64 156 (40000)
66 104 156 (40040)
66 144 156 (40080)
66 184 156
66 224 156
.......... usw
am Ende wieder der Sprungbefehl für den Start der Displaylist.

Als nächstes (mein Grobscroll) kopiere ich einfach die Displaylist um - verschiebe also alle Zeilen um eins nach oben:
66 104 156
66 144 156
66 184 156
66 224 156
66 08 157
.....
66 64 156
Sprungbefehl Displaylistanfang

die letzte Zeile vor dem Sprungbefehl müsste dann wohl immer die vorherige erste sein.
Damit bekomme ich ein fortlaufendes Grobscroll des gesamten Bildschirmes.
Will ich jetzt einen Shooter damit machen, überschreibe ich einfach die komplette erste Zeile der Displaylist mit den neuen Landschaftsdaten (meine "letzte Reihe") - anschließend wird die erste Reihe durch Umsortierung der Displaylist letzte Reihe.
Theoretisch könnte ich auch ganz einfach 24 verschiedene Displaylist mit entsprechend versetzten Zeilen vorbereiten und dann einfach nur jeweils von Displaylist 1 zu 2 zu 3 zu .... zu 24 umschalten.
Die Displaylist wird dann noch so aufgebaut, daß der entsprechende Graphicmodus plus Feinscroll mit drin ist, der Grobscroll wird entsprechend immer einmal nach 7 Feinscrollaktionen durchgeführt.

So habe ich die Theorie verstanden.... das möchte ich demnächst mal umsetzen.
Habe ich das korrekt verstanden??
Liebe Grüße
Peter

Online
Benutzeravatar
Kveldulfur
Beiträge: 624
Registriert: 17.08.2021 02:32
Has thanked: 237 times
Been thanked: 163 times
Kontaktdaten:

Re: DisplayList für Neueinsteiger #1

Beitrag von Kveldulfur »

In dem Beispiel von mir im "Return to Phobos"-Thread sieht das Scrolling wie folgt aus.
Scrolling.png
Nur in der letzten Zeile muss man aufpassen, da dort der Code $42 steht und nicht $62 !!!
Deine Aussage trifft also zu.

Grüße
Janko

Online
Benutzeravatar
Dr. Irata
Beiträge: 937
Registriert: 24.08.2021 14:40
Has thanked: 110 times
Been thanked: 268 times
Kontaktdaten:

Re: DisplayList für Neueinsteiger #1

Beitrag von Dr. Irata »

ha... so habe ich es verstanden! Cool! Das sieht ja prinzipiell viel einfacher und vor allem viel schneller aus... mit der Methode müsste man doch auch eine hochaufgelöste Graphik ganz schnell scrollen können!!
Wenn ich also eine Graphik mit 320x192 scrollen möchte, dann erstelle ich einfach 192 verschiedene Displaylisten (dann fällt ja auch noch die Rechenzeit für die Umkopiererei weg) und schalte die einfach hintereinander um und habe so einen hochaufgelösten schnellen Scroll ....

Online
Benutzeravatar
Kveldulfur
Beiträge: 624
Registriert: 17.08.2021 02:32
Has thanked: 237 times
Been thanked: 163 times
Kontaktdaten:

Re: DisplayList für Neueinsteiger #1

Beitrag von Kveldulfur »

Hallo!

Einzelne Displaylisten bei 192 Zeilen? In jeder Liste sind doch min. 200 Bytes enthalten, oder?
Also 192 Schritte x 200 Bytes = 38400 Bytes = 37,5kb = Atari voll :-)

Oder mache ich jetzt einen Denkfehler?

Grüße
Janko

Online
Benutzeravatar
Dr. Irata
Beiträge: 937
Registriert: 24.08.2021 14:40
Has thanked: 110 times
Been thanked: 268 times
Kontaktdaten:

Re: DisplayList für Neueinsteiger #1

Beitrag von Dr. Irata »

ähhhh .. ja das stimmt ... das geht nicht. Da müsste man umkopieren... :D

Online
Benutzeravatar
Kveldulfur
Beiträge: 624
Registriert: 17.08.2021 02:32
Has thanked: 237 times
Been thanked: 163 times
Kontaktdaten:

Re: DisplayList für Neueinsteiger #1

Beitrag von Kveldulfur »

Hallo Peter!

Irgendwie hast Du mich neugierig gemacht ein Scrolling für 320x192 Punkte hinzu bekommen :-)
7,5k zu scrollen, kann man nur über Displaylist-Manipulation hinbekommen, aber wie?
192 Displayliste? Nein zu wenig Speicher
1 Liste Rotieren lassen, wie in meinem Beispiel für den Textmodus Gr. 0 ? Das wären fast 600 Bytes, die ständig 1/50s rotieren...

In Endeffekt habe ich nun zwei Displaylisten und lasse darin den MemScan wandern. Also $40 in der Displaylist mit der Angabe des Speicherbereiches.
Es müssen nun 15 Bytes ständig neu gesetzt werden. Die Logik ist aufwendig, wird wegen unterschiedlichen Zuständen nur tlw. immer abgearbeitet.
Insgesamt scheint das Scrolling gut zu funktionieren.

Hier mein Beispiel (Quick & Dirty :D ) :

Code: Alles auswählen

; ############################################################################
; # Programm um den Bildschirm im Grafikmodus 8 (320x192) zu scrollen,
; # ohne den Speicherbereich zu verschieben
; #
; # ZeroPage A0 bis A5 werden für notwendige Zeiger genutzt
; # Der Bildschirmspeicher liegt ab Adresse $2150 bis $3F4F
; # Die Displaylist wird in den Bereich $2000 geschrieben
; #
; # Das Programm selbst beginnt ab Adresse $4000, direkt hinterm 
; # Bildschirmspeicher
; #
		org $4000
		
		icl 'Systemkonstanten.asm'
		
; ############################################################################
; ### Variabeln definieren

ScrMemZero	equ $a0
DListZero	equ $a2
LastLine	equ $a4

ScrMemZ		.word $2150
DListZ		.word $2000

VScrollPos	.byte 99
VScrollCnt	.byte 00

; ############################################################################
; ### Daten definieren

; # DisplayList
; # Da der ANTIC nur 4K-Daten verarbeiten kann, muss man den Bildschirm in zwei
; # Bereiche aufteilen, die jeweils < 4096 Bytes haben.
; # Beim scrollen muss man dies berücksichtigen, weshalb ich in zwei Abschnitten
; # scrolle und deshalb 2 Displaylisten benötige
; # Jeweils mit vertauschten 4K Block
; # Um einen zusammenhängenden Bild-Bereich zu haben, beginnt man bei
; # $2150 und endet bei $3F4F

DList1		.byte $70,$70,$70
		.byte $4F,$50,$21				; Der MEMSCAN wird hier beim scrollen
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F	; regelmäßig der neuen Situation angepasst
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F,$0F		
		.byte $4F,$00,$30				; Dieser MEMSCAN wird "nach oben" wandern,
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F	; und immer auf die selbe Adresse zeigen
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F,$0F,$0F,$0F,$0F
		.byte $4F,$28,$3F 				; Dieser MEMSCAN wird einmalig korigiert und 
								; anschließend wander er ebenfalls "hoch"
		.byte $41,$00,$20
		.byte $ff

DList2		.byte $70,$70,$70
		.byte $4F,$00,$30				; Der MEMSCAN wird hier beim scrollen
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F	; regelmäßig der neuen Situation angepasst
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $4F,$50,$21				; Dieser MEMSCAN wird "nach oben" wandern,
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F	; und immer auf die selbe Adresse zeigen 
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
		.byte $0F,$0F
		.byte $4F,$D8,$2F				; Dieser MEMSCAN wird einmalig korigiert und
								; anschließend wander er ebenfalls "hoch"
		.byte $41,$00,$20
		.byte $ff
		
; ############################################################################
; # VSync
; # 
		.proc WaitVSync			; VBI abwarten
		
		lda RTCLOK+2
Loop	   	cmp RTCLOK+2  
        	beq Loop
		
		rts
		
		.end

; #############################################################################
; ### Speicherbereiche initialisieren

		.proc MemInI					
		
		lda ScrMemZ			; Speicherbereich des Bildbildschirm
		sta ScrMemZero			; in die ZeroPage kopieren
		lda ScrMemZ+1
		sta ScrMemZero+1		

		lda DListZ			; Speicherbereich der Displaylist
		sta DListZero			; in die ZeroPage kopieren
		lda DListZ+1
		sta DListZero+1		

  		jsr ScreenMem			; Bildschirm löschen (leeren)
  		jsr DListLoad.First		; Erste Displaylist einladen
		
		jsr WaitVSync			; VBI abwarten
		
		lda DlistZ			; Displaylist laden
	        sta SDLSTL
		lda DlistZ+1
		sta SDLSTL+1
		
		jsr WaitVSync			; Erneut VBI abwarten
		
		rts
		
		.end
		
; ############################################################################
; # Clear Screen
; # 
; # Sicherstellen, dass der Bildschirm sauber ist
; #
		.proc ScreenMem
		
		ldx #$00
		ldy #$00
		
		lda #$00			; Routine um den Bildschirm
@		sta (ScrMemZero),y		; zu löschen
		iny				; Da insgesamt 7,5k gelöscht
		bne @-				; werden müssen,
		inx 				; wird der Vorgang
		cpx #$1E			; in mehrere 256er Läufe
		beq @+
		inc ScrMemZero+1
		jmp @-
		
@		inc ScrMemZero+1
		ldy #$B0			; und einem Restlauf
@		dey				; aufgeteilt
		cpy #$00
		beq @+
		lda #$00
		sta (ScrMemZero),y
		jmp @-
		
@		lda ScrMemZ			; ZeroPage-Variable
		sta ScrMemZero			; wieder herstellen
		lda ScrMemZ+1
		sta ScrMemZero+1
		
		rts
				
		.end
		
; ############################################################################
; # Displaylist einrichten
; # 
; # Es gibt zwei Displaylisten, die je nach Scrollposition eingeblendet werden müssen
; #
		.proc DListLoad
		
First		ldy #$00			; Die Displaylist
		
Loop		lda DList1,y			; muss in den Bereich ab $2000
		cmp #$ff			; eingelesen werden
		beq @+				; $ff ist dabei das Signal
		sta (DlistZero),y		; das alles gelesen wurde
		iny
		jmp Loop
		
@		rts

Second		ldy #$00
		
Loop2		lda DList2,y			; Ein zweiter Loop für die
		cmp #$ff			; zweite Displaylist
		beq @+
		sta (DlistZero),y
		iny
		jmp Loop2
		
@		rts
				
		.end
		
; ############################################################################
; # VScroll - Routine um Grafikmodus 320 x 192 zu scollen 
; # 
		.proc VScroll
		lda move			; In Move wird festgehalten
		cmp #$02			; Ob man im ersten Durchlauf = 0 ist
		bcc @+				; Mehr als Durchlauf der 1. Häfte hat = 1
		jmp SecondDLI			; Oder gar in der 2. Hälfte sich befindet >2
		
@		lda VScrollPos			; VScrollPos wieder verringert
		cmp #$06			; bis zur 6, um nicht wichtige Einträge zu 
		beq Restore1			; überschreiben
		dec VScrollPos			; Bei 6 wird die 2. Displaylist aktiviert
		
		ldy #$03			; y wird auf die 1 Memory-Scanzeile der Displaylist
		jsr DListSetMem			; ausgerichtet und dieser dann hochgezählt
		ldy VScrollPos			; y nun auf den ersten Wander-Memscan setzen
		jsr DListSet1UPF		; und wandern lassen
		
		lda Move			
		cmp #$01
		beq @+
		ldy #199
		jmp FirstMove1			; Im ersten Durchgang wird der 3. Memscan nur 
@		tya				; verändert auf $2150
		clc
		adc #97				
		tay
		jsr DListSet1UPF		; In weiteren Durchgängen wird dieser wandern

@		jmp Count

SecondDLI	lda VScrollPos			; für die zweite Displaylist prüfen, ob das	
		cmp #$06			; Ende der Durchläufe erreicht ist		
		beq Restore2			; Dann wieder auf Displaylist 1 zurück ändern
		dec VScrollPos
		
		ldy #$03			; y wieder auf den 1 Memory-Scann der Displaylist
		jsr DListSetMem			; setzen und hochzählen
		ldy VScrollPos			
		jsr DListSet1UPF		; Hier wieder den 2. Scan wandern lassen
		
		lda Move			; Erster Durchlauf der 2. Displaylist = 5
		cmp #$06
		beq @+
		ldy #199
		jmp FirstMove2			; Im ersten Durchlauf nur die Adresse korrigieren
@		tya
		clc
		adc #93
		tay
		jsr DListSet1UPF		; Im weiteren Durchlauf den Memscan wandern lassen

@		jmp Count			; Zähler für "LastLine" wo neuer Inhalt reingeschrieben 
						; werden kann
; -- Unterprogramme
FirstMove1	lda #$01			; Move auf 1 setzen
		sta Move
		lda #$50			; Speicherbereich auf $2150 setzen
		sta (DlistZero),y
		sta LastLine
		iny
		lda #$21
		sta (DlistZero),y
		sta LastLine+1
		rts	

Restore1	jsr DListLoad.Second		; Zweite Displaylist aktivieren
		lda #103			; Und Variabeln neu setzen
		sta VScrollPos			; fürs wandern
		lda #5				; Move auf 5
		sta Move
		lda #$d8			; Speicher auf $2fd8 setzen
		sta LastLine
		lda #$2f
		sta LastLine+1
		rts		

FirstMove2	lda #$06			; Move auf 6 setzen
		sta Move
		lda #$00			; und Speicher auf $3000
		sta (DlistZero),y		; ändern
		sta LastLine
		iny
		lda #$30
		sta (DlistZero),y
		sta LastLine+1
		rts		

Restore2	jsr DListLoad.First		; Displaylist 1 wieder aktivieren
		lda #99				; Variabeln neu setzen
		sta VScrollPos
		lda #0				; Move wieder auf 0
		sta Move
		lda #$28			; Speicherbereich auf $3f28 setzen
		sta LastLine
		lda #$3f
		sta LastLine+1
		inc VScrollCnt
		rts		

DListSet1UPF	lda #$4F			; Routine, um die Memscan-Zeile
		sta (DlistZero),y		; wandern zu lassen
		iny
		iny		
		lda (DlistZero),y
		dey
		sta (DlistZero),y
		iny
		iny		
		lda (DlistZero),y
		dey
		sta (DlistZero),y
		iny		
		lda #$0f
		sta (DlistZero),y		
		rts
		
DListSetMem	clc				; Nur den Speicher hochzählen
		iny				; der im Memscan steht
		lda (DlistZero),y
		adc #$28
		sta (DlistZero),y
		iny
		lda (DlistZero),y
		adc #$00
@		sta (DlistZero),y	
		rts

Count		clc				; LastLine berechnen
		lda LastLine
		adc #$28
		sta LastLine
		lda LastLine+1
		adc #$00
		sta LastLine+1
		rts
		
Move		.byte $00
				
		.end
		
; ############################################################################
; ### Spielfeld generieren 
; ###
; ### Irgendetwas darstellen
; ###

		.proc Spielfeld

HoleRichtung	lda RANDOM
		cmp #$55
		bcc GeheLinks
		cmp #$aa
		bcs GeheRechts
		
GeheGeradeaus	lda #$00
		sta Richtung		
		rts
		
GeheLinks	lda Richtung
		cmp #$02
		beq @+
		lda Links
		cmp LinksMin
		bcc @+
		lda #$01
		sta Richtung
		rts
		
@		lda #$00
		sta Richtung
		rts
		
GeheRechts	lda Richtung
		cmp #$01
		beq @-
		lda Rechts
		cmp RechtsMax
		bcs @-
		lda #$02
		sta Richtung
		rts				

Start		jsr HoleRichtung
		
		lda Richtung
		cmp #$01
		beq LLinks
		bcc GGeradeaus
		bcs RRechts
		rts

GGeradeaus	ldy #$00
		lda #$ff
@		sta (LastLine),y
		iny
		cpy Links
		bcc @-
		dey
		lda LinksFein
		sta (LastLine),y
		iny

		lda #$00
@		sta (LastLine),y
		iny
		cpy Rechts
		bcc @-

		lda RechtsFein
		ldy Rechts
@		sta (LastLine),y
		lda #$ff
		iny
		cpy #$28
		bcc @-
		rts

LLinks		lda LinksFein
		cmp #$00
		beq @+
		clc
		asl
		sta LinksFein
		eor #$ff
		sta RechtsFein
		jmp GGeradeaus
@		lda #$ff
		sta LinksFein
		lda #$00	
		sta RechtsFein		
		dec Links
		dec Rechts
		jmp GGeradeaus
				
RRechts		lda RechtsFein
		cmp #$00
		beq @+
		clc
		lsr
		sta RechtsFein
		eor #$ff
		sta LinksFein
		jmp GGeradeaus
			
@		lda #$ff
		sta RechtsFein		
		lda #$00	
		sta LinksFein
		inc Links
		inc Rechts
		jmp GGeradeaus
		
LinksFein	.byte $ff
Links		.byte $14
RechtsFein	.byte $ff
Rechts		.byte $1E
Richtung	.byte $00		; 0 = Geradeaus   1 = Links   2 = Rechts
LinksMin	.byte $08
RechtsMax	.byte $20

		.end		
		
; #############################################################################
; ### Hauptprogramm

		.proc main
		
		jsr MemInI
		
		;lda #$0A
		;sta color2
		
Loop		jsr WaitVSync
		jsr VScroll
		jsr Spielfeld.Start

		
		jmp Loop		
		
		.end
		
; #############################################################################
		run main		
Gruß
Janko

Online
Benutzeravatar
Dr. Irata
Beiträge: 937
Registriert: 24.08.2021 14:40
Has thanked: 110 times
Been thanked: 268 times
Kontaktdaten:

Re: DisplayList für Neueinsteiger #1

Beitrag von Dr. Irata »

Guten Morgen Janko,
ich habe mir das Listing gleich mal rübergezogen und ausprobiert... beeindruckend!
Tatsächlich hatte ich mal ganz am Anfang mit Scrolling experimentiert unter Basic und das ging dort auch nur relativ zügig und schnell mit 2 verschiedenen Displays und dann umschalten... so hätte ich das jetzt nach meinem Projekt Phobos versucht - du hast das jetzt umgesetzt!! Das läuft echt gut. Respekt. Was ich noch besser finde ist, daß du auch noch einen Zufallsgenerator für eine einfache Landschaft eingebaut hast. Klasse!! Der Code scheint aufwendig, aber das Ergebnis ist ja entscheidend und der eigentliche Programmablauf um 8k zu scrollen läuft fast ohne CPU-Belastung.
Im Grunde müsste man das jetzt noch für verschiedene interessante Grafikmodi umsetzen und veröffentlichen, dann muss das nicht jeder selber neu "erfinden".
Klasse gemacht, Janko!!

Ich habe gestern ein wenig Zeit gehabt und neben der ganzen schlimmen Berichterstattung aus der Welt und vor allem aus der Ukraine mein Projekt weitergemacht.
Neue Items sind drin - die Schranken! Dabei wollte ich die Schranken so gestalten, daß sie ständig animiert sind und dann als weiteres Item relativ einfach in die Landschaft reingeprintet werden können über meine Routine "letzte Reihe". Die Schranke muss in vernünftiger Zeit ein- bzw. ausgeschaltet werden, dieses Timing hat mich etwas Mühe und Zeit gekostet. Am Ende habe ich es ans "blinken" gekoppelt und mit ein paar Anpassungen läuft das jetzt ganz gut.
Jetzt kommt noch eine weitere "Laufschranke" und noch weitere Landschaft und noch ein paar Sonderitems.

Für das Endlevel muss ich mir noch was schönes ausdenken...

Und danach gehe ich das nächste Projekt an... es wird wieder ein Shooter, der aber ganz anders aufgebaut sein soll...
Liebe Grüße
Peter

Online
Benutzeravatar
Kveldulfur
Beiträge: 624
Registriert: 17.08.2021 02:32
Has thanked: 237 times
Been thanked: 163 times
Kontaktdaten:

Re: DisplayList für Neueinsteiger #1

Beitrag von Kveldulfur »

Danke! Freut mich, dass es Dir gefällt.

Grüße
Janko

Antworten

Wer ist online?

Mitglieder in diesem Forum: Dr. Irata, Google [Bot] und 1 Gast