Warum geht das nicht

geschrieben am 22.05.2015 19:38:51
( Link )
Hallo zusammen,

ich habe ein kleines Problem mit einem Custom Sprite. Der Sprite soll mal, abhängig von der Münzzahl unterschiedlich schnell, konstant nach rechts unten gehen und wenn der Spieler den Sprungknopf drückt, nach rechts oben. Wenn der Sprite was berührt, soll er sterben und Mario gleich mit töten (Das klingt voll dumm, wenn man das so aufschreibt XD)

Code
dcb "INIT"
RTL

SPEEDDOWN: dcb $E8,$D8,$C0,$80
SPEEDUP: dcb $18,$28,$3F,$7F

dcb "MAIN"
JSR Maincode
JSR Graphics
RTL

Maincode:
LDA $14C8,x ; \
CMP #$08 ; |
BNE Freeze ; | Freeze den Sprite wenn nötig
LDA $9D ; |
BNE Freeze ; /

LDA $1588,x ; \
AND #$0F ; | Teste, ob der Sprite gegen ein Hindernis "läuft"
BNE Kill ; /

LDY $0DBF ; \
LDA SPEEDUP,y ; | Setze den X-Speed abhängig von den Münzen
STA $B6,x ; /

LDA $15 ; \
AND #$80 ; | Prüfe, ob der Spieler eine Sprungtaste drückt
BEQ Down ; |
BRA Up ; /

Up: ; \
LDA SPEEDUP,y ; | Setze den Y-Speed abhängig von den Münzen
STA $AA,x ; |
BRA End ; /

Down: ; \
LDA SPEEDDOWN,y ; | Setze den Y-Speed abhängig von den Münzen
STA $AA,x ; |
BRA End ; /

End: ; \
JSL $01802A ; | Ende der Hauptroutine
RTS ; /

Freeze: ; \ Offensichtlich
RTS ; /

Kill: ; \
JSL $00F606 ; | Mario töten
RTS ; /


Das ist der Code, dahinter kommt dann halt noch die Grafikroutine aber mit der ist nix falsch, die Grafiken laden ohne Probleme. Wäre nett wenn ihr mir helfen könntet

Gruß, HF01
Ich könnte hier Text hinschreiben. Mache ich aber nicht.
geschrieben am 22.05.2015 20:49:17
( Link )
Wäre ja nett, wenn du uns noch mitteilen könntest, was daran denn falsch läuft.

Na ja. Das einzige offensichtliche Problem ist, dass du die SPEED-Daten wahrscheinlich von ganz woanders liest. Du musst dem Programm noch mitteilen, aus welcher Bank es die Daten überhaupt lesen soll (sprich das "high Byte" der Adresse, also zum Beispiel das $12 in $123456). Momentan sagst du nur "lade aus $3456" (angenommen, die SPEEDDOWN- bzw. SPEEDUP-Tabelle liegt da), aber die Bank muss sich das Programm selbst ermitteln. Dann nimmt es das Data Bank Register, und das kann werweißwas sein. Gängige Praxis ist es, das DBR auf denselben Wert zu setzen wie das Program Bank Register (die Bank, in der der Code gerade läuft). Das macht man mit PHK : PLB, und das wirst du auch in jedem Sprite so finden.

Code
dcb "MAIN"
PHB ; Data Bank sichern
PHK ; \ Program Bank = Data Bank
PLB ;/
JSR [...]
PLB ; Data Bank wiederherstellen
RTL


Und dabei merke ich gerade, dass du immer noch TRASM benutzt. Yikes. Gibt's einen Grund, warum du Sprites nicht für xkas/Asar schreibst?

Außerdem fällt mir auf, dass deine Tabellen zu klein sind. Ich nehme an, du möchtest auch mal mehr als drei Münzen haben? Deine Tabellen decken nur die Fälle 0, 1, 2 und 3 ab. Wenn du für jede Münze unterschiedliche Geschwindigkeiten haben willst, könntest du entweder alle 100 Bytes ausschreiben, oder eine Funktion finden, die von der Anzahl der Münzen auf die Geschwindigkeit schließen lässt. Wenn du die Gechwindigkeitsänderung nur in Schritten von, sagen wir mal, 32, Münzen haben willst, kannst du folgendes tun:
Code
LDA $0DBF
LSR
LSR
LSR
LSR
LSR
TAY

Das teilt deine Münzen durch zweiunddreißig (=fünf Mal durch zwei), bevor sie ins Y-Register geladen werden. (Man kann auch LSR #5 schreiben, aber das wird zu demselben Code "assembelt" [?] und ist in ausgeschriebener Form vielleicht besser zu verstehen.)

Ein paar Optimierungs-Tipps:

Code
RTS
Freeze:
RTS

Das erste RTS kannst du weghauen.

Code
BRA End
End:

Das Ganze ebenfalls.

Code
BEQ Down    ; |
BRA Up ; /

BEQ-BRA-Konstrukte wie dieses hier kann man umformen. BNE Up : Down: (oder BEQ Down : Up:) tut dasselbe.

Kurz gesagt, den Knopfdruck-Teil würde ich so schreiben:
Code
LDA $15       ; \
AND #$80 ; | Prüfe, ob der Spieler eine Sprungtaste drückt
BEQ Down
Up: ; \
LDA SPEEDUP,y ; | Setze den Y-Speed abhängig von den Münzen
STA $AA,x ; |
BRA End ; /
Down: ; \
LDA SPEEDDOWN,y ; | Setze den Y-Speed abhängig von den Münzen
STA $AA,x ; |
\
End:


(Mann, bin ich schlecht im Formulieren heute. )
geschrieben am 22.05.2015 21:16:30
( Link )
Warum ich Sprites für TRASM schreibe? Ich kenne den Unterschied nicht XD
Was muss man da anders machen?

Was falsch läuft? Einfach alles XD
Der Speed wird (von meiner Perspektive aus) komplett random gesetzt und auf den Input reagiert der Sprite erst gar nicht^^

Und nein, ich plane nicht mehr als 3 Münzen einzubauen. Es soll in den Leveln wenig Münzen geben, die auch nur für den Grund dienen und außerdem habe ich Blöcke in der ROM, die die Münzen auf 0-3 setzen.
Ich könnte hier Text hinschreiben. Mache ich aber nicht.
geschrieben am 22.05.2015 22:22:45
( Link )
So... jetzt habe ich mal versucht, das ganze Ding in xkas-Format umzuwandeln.
Allerdings spuckts mir jetzt schon bei
Code
print "INIT ",pc

nen Fehler aus (Label [INIT] not found oder so). Andere xkas-Codes werden aber sauber assembliert. Warum?
Ich könnte hier Text hinschreiben. Mache ich aber nicht.
geschrieben am 23.05.2015 10:29:53
( Link )
Zitat von xHF01x:
Der Speed wird (von meiner Perspektive aus) komplett random gesetzt

Ja, dann liegt's am fehlenden PHB PHK PLB und so weiter. Siehe oben.

Zitat von xHF01x:
nen Fehler aus (Label [INIT] not found oder so). Andere xkas-Codes werden aber sauber assembliert. Warum?

Dran gedacht, im CFG-Editor den Haken bei "use xkas for assembly" zu setzen?
geschrieben am 23.05.2015 12:17:21
( Link )
Ja, an den Haken habe ich gedacht...

Die Fehlermeldung
Code
error: tmpasm.asm: line 3: invalid opcode or command [print "INIT ",pc]
error: tmpasm.asm: line 3: label [INIT] not found [print "INIT ",pc]
error: tmpasm.asm: line 3: label [pc] not found [print "INIT ",pc]
MAIN 008001


Die .cfg
Code
01
36
00 00 70 A7 39 64
00 00
wave.asm
1


Und hier noch der Code:
Code
print "INIT ", pc
RTL

print "MAIN ", pc
PHB
PHK
PLB
JSR MAINCODE
JSR GRAPHICS
PLB
RTL

SPEEDDOWN: db $E8,$D8,$C0,$80
SPEEDUP: db $18,$28,$3F,$7F

MAINCODE:
LDA $14C8,x ; \
CMP #$08 ; |
BNE FREEZE ; | Freeze den Sprite wenn nötig
LDA $009D ; |
BNE FREEZE ; /

LDA $1588,x ; \
AND #$0F ; | Teste, ob der Sprite gegen ein Hindernis "läuft"
BNE KILL ; /

LDY $0DBF ; \
LDA SPEEDUP,y ; | Setze den X-Speed abhängig von den Münzen
STA $00B6,x ; /

LDA $15 ; \
AND #$80 ; | Prüfe, ob der Spieler eine Sprungtaste drückt
BEQ DOWN ; /

LDA SPEEDUP,y ; \
STA $00AA,x ; | Setze den Y-Speed abhängig von den Münzen
BRA END ; /

DOWN: ; \
LDA SPEEDDOWN,y ; | Setze den Y-Speed abhängig von den Münzen
STA $00AA,x ; /

END: ; \ Ende der Hauptroutine
JSL $01802A ; /

FREEZE: ; \ Offensichtlich
RTS ; /

KILL: ; \
JSL $00F606 ; | Mario töten
RTS ; /

GRAPHICS:
JSR GET_DRAW_INFO
LDA $00
STA $0300,y
LDA $01
STA $0301,y
LDA #$2A
STA $0302,y
LDA #%00101100
ORA $64
STA $0303,y
INY
INY
INY
INY
LDY #$02
LDA #$00
JSL $01B7B3
RTS

SPR_T1: db $0C,$1C
SPR_T2: db $01,$02

GET_DRAW_INFO: STZ $186C,x ; reset sprite offscreen flag, vertical
STZ $15A0,x ; reset sprite offscreen flag, horizontal
LDA $E4,x ; \
CMP $1A ; | set horizontal offscreen if necessary
LDA $14E0,x ; |
SBC $1B ; |
BEQ ON_SCREEN_X ; |
INC $15A0,x ; /

ON_SCREEN_X: LDA $14E0,x ; \
XBA ; |
LDA $E4,x ; |
REP #$20 ; |
SEC ; |
SBC $1A ; | mark sprite INVALID if far enough off screen
CLC ; |
ADC.w #$0040 ; |
CMP.w #$0180 ; |
SEP #$20 ; |
ROL A ; |
AND #$01 ; |
STA $15C4,x ; /
BNE INVALID ;

LDY #$00 ; \ set up loop:
LDA $1662,x ; |
AND #$20 ; | if not smushed (1662 & 0x20), go through loop twice
BEQ ON_SCREEN_LOOP ; | else, go through loop once
INY ; /
ON_SCREEN_LOOP: LDA $D8,x ; \
CLC ; | set vertical offscreen if necessary
ADC SPR_T1,y ; |
PHP ; |
CMP $1C ; | (vert screen boundry)
ROL $00 ; |
PLP ; |
LDA $14D4,x ; |
ADC #$00 ; |
LSR $00 ; |
SBC $1D ; |
BEQ ON_SCREEN_Y ; |
LDA $186C,x ; | (vert offscreen)
ORA SPR_T2,y ; |
STA $186C,x ; |
ON_SCREEN_Y: DEY ; |
BPL ON_SCREEN_LOOP ; /

LDY $15EA,x ; get offset to sprite OAM
LDA $E4,x ; \
SEC ; |
SBC $1A ; | $00 = sprite x position relative to screen boarder
STA $00 ; /
LDA $D8,x ; \
SEC ; |
SBC $1C ; | $01 = sprite y position relative to screen boarder
STA $01 ; /
RTS ; return

INVALID: PLA ; \ return from *main gfx routine* subroutine...
PLA ; | ...(not just this subroutine)
RTS ; /


Ich verstehs nicht... Irgendne Idee?
Ich könnte hier Text hinschreiben. Mache ich aber nicht.
geschrieben am 23.05.2015 15:20:33
( Link )
Ok, ich habe den gesamten Code 1:1 abgeschrieben und plötzlich geht's
Kein Plan was das war. Vermutlich ein spukendes Steuerzeichen

Edit: Zu früh gefreut. Immerhin nimmt xkas den Sprite jetzt an. Aber das Spiel stürzt jetzt ab, wenn man den Sprite lädt
Ich könnte hier Text hinschreiben. Mache ich aber nicht.
geschrieben am 24.05.2015 12:05:31
( Link )
Kann ich auf den ersten Blick auch nicht sehen, woran das liegt. Da hilft nur, immer mehr vom Code auszukommentieren und jedes Mal zu probieren, ob das Spiel immer noch abstürzt oder nicht - wenn nicht, dann weißt du, der Fehler liegt in dem gerade auskommentierten Teil.
geschrieben am 24.05.2015 12:25:51
( Link )
Jo, das habe ich dann auch schon gemacht. Habs dann wieder in Trasm probiert und jetzt geht's.
Kann es sein, dass man Variablen / Tabellennamen nur X Zeichen lang machen darf oder so?
Weil jetzt wo meine Tabellen nur noch T1 und T2 heißen geht's.

Code
dcb "INIT"
RTL

T1 db $18,$28,$3F,$7F
T2 db $E8,$D8,$C0,$80

dcb "MAIN"
PHB
PHK
PLB
JSR Maincode
JSR Graphics
PLB
RTL

Maincode:
LDA $14C8,x ; \
CMP #$08 ; |
BNE Freeze ; | Freeze den Sprite wenn nötig
LDA $9D ; |
BNE Freeze ; /

LDA $1588,x ; \
AND #$0F ; | Teste, ob der Sprite gegen eine Wand läuft
BNE Kill ; /

LDY $0DBF ; \
LDA T1,y ; | Münzen laden und X-Speed setzen
STA $B6,x ; /
LDA $15 ; \
AND #$80 ; | Wenn der Spieler A oder B drückt, gehe nach oben
BNE Oben ; /
LDA T1,y ; \ Sonst unten
STA $AA,x ; / Y-Speed setzen
JSL $01802A
RTS

Oben:
LDA T2,y ; \
STA $AA,x ; / Y-Speed setzen
JSL $01802A
RTS

Freeze:
RTS

Kill:
JSL $00F606 ; Mario töten
RTS ; Und zurück in die Hauptroutine


Graphics:
JSR GET_DRAW_INFO
LDA $00
STA $0300,y
LDA $01
STA $0301,y
LDA #$2A
STA $0302,y
LDA #%00101100
ORA $64
STA $0303,y
INY
INY
INY
INY
LDY #$02
LDA #$00
JSL $01B7B3
RTS

SPR_T1 dcb $0C,$1C
SPR_T2 dcb $01,$02

GET_DRAW_INFO STZ $186C,x ; reset sprite offscreen flag, vertical
STZ $15A0,x ; reset sprite offscreen flag, horizontal
LDA $E4,x ; \
CMP $1A ; | set horizontal offscreen if necessary
LDA $14E0,x ; |
SBC $1B ; |
BEQ ON_SCREEN_X ; |
INC $15A0,x ; /

ON_SCREEN_X LDA $14E0,x ; \
XBA ; |
LDA $E4,x ; |
REP #$20 ; |
SEC ; |
SBC $1A ; | mark sprite invalid if far enough off screen
CLC ; |
ADC.W #$0040 ; |
CMP.W #$0180 ; |
SEP #$20 ; |
ROL A ; |
AND #$01 ; |
STA $15C4,x ; /
BNE INVALID ;

LDY #$00 ; \ set up loop:
LDA $1662,x ; |
AND #$20 ; | if not smushed (1662 & 0x20), go through loop twice
BEQ ON_SCREEN_LOOP ; | else, go through loop once
INY ; /
ON_SCREEN_LOOP LDA $D8,x ; \
CLC ; | set vertical offscreen if necessary
ADC SPR_T1,y ; |
PHP ; |
CMP $1C ; | (vert screen boundry)
ROL $00 ; |
PLP ; |
LDA $14D4,x ; |
ADC #$00 ; |
LSR $00 ; |
SBC $1D ; |
BEQ ON_SCREEN_Y ; |
LDA $186C,x ; | (vert offscreen)
ORA SPR_T2,y ; |
STA $186C,x ; |
ON_SCREEN_Y DEY ; |
BPL ON_SCREEN_LOOP ; /

LDY $15EA,x ; get offset to sprite OAM
LDA $E4,x ; \
SEC ; |
SBC $1A ; | $00 = sprite x position relative to screen boarder
STA $00 ; /
LDA $D8,x ; \
SEC ; |
SBC $1C ; | $01 = sprite y position relative to screen boarder
STA $01 ; /
RTS ; return

INVALID PLA ; \ return from *main gfx routine* subroutine...
PLA ; | ...(not just this subroutine)
RTS ; /


Edit: Hab jetzt noch mal nen bissel rumgetestet und mir ist aufgefallen, dass es nicht mehr funktioniert, wenn ich das JSL $01802A in nen eigenen Block setze und dann dahin BRA-e.

Naja, auf jeden Fall läufts jetzt und der Thread kann *zu*

~HF01
Ich könnte hier Text hinschreiben. Mache ich aber nicht.