; move a happy face with the joystick by Kirk Israel ; (with a can't'dodge'em line sweeping across the screen) processor 6502 include vcs.h org $F000 YPosFromBot = $80; VisiblePlayerLine = $81; PICS = $93; PICSNUM = $94; ;generic start up stuff... Start SEI CLD LDX #$FF TXS LDA #0 STA PICSNUM ClearMem STA 0,X DEX BNE ClearMem LDA #$00 ;start with a black background STA COLUBK LDA #$1C ;lets go for bright yellow, the traditional color for happyfaces STA COLUP0 ;Setting some variables... LDA #80 STA YPosFromBot ;Initial Y Position ;; Let's set up the sweeping line. as Missile 1 LDA #2 STA ENAM1 ;enable it LDA #33 STA COLUP1 ;color it LDA #$20 STA NUSIZ1 ;make it quadwidth (not so thin, that) LDA #$F0 ; -1 in the left nibble STA HMM1 ; of HMM1 sets it to moving ;VSYNC time MainLoop LDA #2 STA VSYNC STA WSYNC STA WSYNC STA WSYNC LDA #43 STA TIM64T LDA #0 STA VSYNC ;Main Computations; check down, up, left, right ;general idea is to do a BIT compare to see if ;a certain direction is pressed, and skip the value ;change if so ; ;Not the most effecient code, but gets the job done, ;including diagonal movement ; ; for up and down, we INC or DEC ; the Y Position LDA #010000 ;Down? BIT SWCHA BNE SkipMoveDown INC YPosFromBot SkipMoveDown LDA #100000 ;Up? BIT SWCHA BNE SkipMoveUp DEC YPosFromBot SkipMoveUp ; for left and right, we're gonna ; set the horizontal speed, and then do ; a single HMOVE. We'll use X to hold the ; horizontal speed, then store it in the ; appropriate register ;assum horiz speed will be zero LDX #0 LDA #%01000000 ;Left? BIT SWCHA BNE SkipMoveLeft LDX #$10 ;a 1 in the left nibble means go left ;; moving left, so we need the mirror image LDA #001000 ;a 1 in D3 of REFP0 says make it mirror STA REFP0 SkipMoveLeft LDA #%10000000 ;Right? BIT SWCHA BNE SkipMoveRight LDX #$F0 ;a -1 in the left nibble means go right... ;; moving right, cancel any mirrorimage LDA #000000 STA REFP0 SkipMoveRight STX HMP0 ;set the move for player 0, not the missile like last time... ; see if player and missile collide, and change the background color if so ;just a review...comparisons of numbers always seem a little backwards to me, ;since it's easier to load up the accumulator with the test value, and then ;compare that value to what's in the register we're interested. ;in this case, we want to see if D7 of CXM1P (meaning Player 0 hit ; missile 1) is on. So we put 10000000 into the Accumulator, ;then use BIT to compare it to the value in CXM1P LDA #%10000000 BIT CXM1P BEQ NoCollision ;skip if not hitting... LDA YPosFromBot ;must be a hit! load in the YPos... STA COLUBK ;and store as the bgcolor NoCollision STA CXCLR ;reset the collision detection for next time INC PICSNUM LDA PICSNUM AND #15 ;every 8th screen swap to next image of player CMP #8 BEQ PICSET4 JMP PICSET3 PICSET4 LDA PICS CMP #8 BEQ PICSET LDA #8 JMP PICSET2 PICSET LDA #0 PICSET2 STA PICS PICSET3 WaitForVblankEnd LDA INTIM BNE WaitForVblankEnd LDY #191 STA WSYNC STA HMOVE STA VBLANK ;main scanline loop... PreScanLoop ;set player graphic to all zeros for this line, and then see if ;we need to load it with graphic data LDA #0 STA GRP0 ScanLoop STA WSYNC ; here the idea is that VisiblePlayerLine ; is zero if the line isn't being drawn now, ; otherwise it's however many lines we have to go CheckActivatePlayer CPY YPosFromBot BNE SkipActivatePlayer LDA #8 STA VisiblePlayerLine SkipActivatePlayer ;set player graphic to all zeros for this line, and then see if ;we need to load it with graphic data LDA #0 STA GRP0 ; ;if the VisiblePlayerLine is non zero, ;we're drawing it now! ; LDX VisiblePlayerLine ;check the visible player line... BEQ FinishPlayer ;skip the drawing if its zero... IsPlayerOn TXA ;Transfers the byte in the X Register to the Accumulator ADC PICS ;add value of pics to Accumulator TAX ;Transfers the byte in the Accumulator to the X Register LDA BigHeadGraphic-1,X ;shift to change which pic were showing ; ORA #1 ;creates a shield STA GRP0 ;put that line as player graphic DEC VisiblePlayerLine ;and decrement the line count FinishPlayer DEY BNE ScanLoop LDA #2 STA WSYNC STA VBLANK LDX #24 OverScanWait STA WSYNC DEX BNE OverScanWait JMP MainLoop ; here's the actual graphic! If you squint you can see its ; upsidedown smiling self BigHeadGraphic .byte #010100 .byte #010100 .byte #011000 .byte #011000 .byte #%01111110 .byte #010000 .byte #011000 .byte #011000 .byte #010010 .byte #010100 .byte #011000 .byte #011000 .byte #%01111110 .byte #010000 .byte #011000 .byte #011000 .byte #010100 .byte #010100 .byte #011000 .byte #011000 .byte #%01111110 .byte #010000 .byte #011000 .byte #011000 .byte #010010 .byte #010100 .byte #011000 .byte #011000 .byte #%01111110 .byte #010000 .byte #011000 .byte #011000 org $FFFC .word Start .word Start
sprite display not as expected
Started by yllawwally, Feb 3 2010 3:32 PM
7 replies to this topic
#1
Posted Wed Feb 3, 2010 3:32 PM
I'm trying to learn 2600 programming. I took the face example from one of the tutorials here. I modified it to have alternate pics of the player every 8 screens. So that I could do a walking animation. However the top line seems to be a copy of the bottom line. I can't see what I'm doing wrong. I was hoping someone could help me find my error.
#2
Posted Wed Feb 3, 2010 9:03 PM
You're setting the "first" GRP0 line AFTER you turn the screen on, so whatever was in GRP0 from the last pass gets drawn at the top.
If you put the "LDA #0" and "STA GRP0" lines BEFORE the STA WSYNC/STA HMOVE/STA VBLANK group, that should clear it out.
Hope this helps.
--Will
If you put the "LDA #0" and "STA GRP0" lines BEFORE the STA WSYNC/STA HMOVE/STA VBLANK group, that should clear it out.
Hope this helps.
--Will
#3
Posted Fri Feb 5, 2010 10:38 AM
Sorry I mischaracterized the issue. Really the problem was the first line of the player was a copy of the previous last line. However that wasn't what was happening. I used ADC to add a counter for each step. I didn't realize that if the carry flag was set an additional 1 would be added. So I placed a CLC before adc, which has fixed it.
#4
Posted Thu Feb 11, 2010 3:29 PM
I seem to now have a problem using too many cycles. When the player and enemy are on the same lines, they get twice as tall. It seems that I should have cycles to spare. What am I doing wrong?
processor 6502 include vcs.h org $F000 ;Variables ------ YPosFromBot = $80; VisiblePlayerLine = $81; PICS = $82; ROLLING_COUNTER = $83; Graphics_Buffer = $84 YPosFromBotE1 = $85; VisibleEnemyLine = $86; VisibleEnemyLineCurrent = $87; EnemyLineBuffer = $88; VisiblePlayerLineCurrent = $90; ; Constants ------ playerheight ds #8; enemyheight ds #8; ;generic start up stuff... Start SEI CLD LDX #$FF TXS LDA #0 STA ROLLING_COUNTER STA PICS STA EnemyLineBuffer ClearMem STA 0,X DEX BNE ClearMem LDA #$00 ;start with a black background STA COLUBK LDA #$1C ;lets go for bright yellow, the traditional color for happyfaces STA COLUP0 ;Setting some variables... LDA #80 STA YPosFromBot ;Initial Y Position STA YPosFromBotE1 ;; Let's set up the sweeping line. as Missile 1 LDA #2 STA ENAM1 ;enable it LDA #33 STA COLUP1 ;color it LDA #$10 STA NUSIZ1 ;make it quadwidth (not so thin, that) LDA #000000 ; set to not move STA HMM1 ; of HMM1 sets it to moving ;VSYNC time MainLoop LDA #2 STA VSYNC STA WSYNC ; for up and down, we INC or DEC ; the Y Position LDA #010000 ;Down? BIT SWCHA BNE SkipMoveDown INC YPosFromBot INC YPosFromBotE1 INC YPosFromBotE1 SkipMoveDown LDA #100000 ;Up? BIT SWCHA BNE SkipMoveUp DEC YPosFromBot DEC YPosFromBotE1 DEC YPosFromBotE1 SkipMoveUp ; for left and right, we're gonna ; set the horizontal speed, and then do ; a single HMOVE. We'll use X to hold the ; horizontal speed, then store it in the ; appropriate register ;assum horiz speed will be zero LDX #0 LDA #%01000000 ;Left? BIT SWCHA BNE SkipMoveLeft LDX #$10 ;a 1 in the left nibble means go left ;; moving left, so we need the mirror image LDA #001000 ;a 1 in D3 of REFP0 says make it mirror STA REFP0 SkipMoveLeft LDA #%10000000 ;Right? BIT SWCHA BNE SkipMoveRight LDX #$F0 ;a -1 in the left nibble means go right... ;; moving right, cancel any mirrorimage LDA #000000 STA REFP0 SkipMoveRight STX HMP0 ;set the move for player 0, not the missile like last time... ; see if player and missile collide, and change the background color if so ;just a review...comparisons of numbers always seem a little backwards to me, ;since it's easier to load up the accumulator with the test value, and then ;compare that value to what's in the register we're interested. ;in this case, we want to see if D7 of CXM1P (meaning Player 0 hit ; missile 1) is on. So we put 10000000 into the Accumulator, ;then use BIT to compare it to the value in CXM1P LDA #%10000000 BIT CXM1P BEQ NoCollision ;skip if not hitting... LDA YPosFromBot ;must be a hit! load in the YPos... STA COLUBK ;and store as the bgcolor NoCollision STA CXCLR ;reset the collision detection for next time STA WSYNC ;////////////////////////////////////////////// ;setup pic animations ---------------------------------------------- INC ROLLING_COUNTER LDA ROLLING_COUNTER AND #15 ;every 8th screen swap to next image of player CMP #8 BEQ PICSET4 JMP PICSET3 PICSET4 LDA PICS CMP #8 BEQ PICSET LDA #8 JMP PICSET2 PICSET LDA #0 PICSET2 STA PICS PICSET3 LDA ROLLING_COUNTER AND #25 ;how often to move enemy, larger number is slower CMP #8 BEQ PICSET5 LDA #001111 ; +1 in the left nibble JMP PICSET6 PICSET5 LDA #011111 ; 0 in the left nibble PICSET6 STA HMP1 ; of HMP1 sets it to moving the enemy LDA #8 CLC ADC PICS ;add value of pics to Accumulator STA VisibleEnemyLineCurrent LDA #8 CLC ADC PICS ;add value of pics to Accumulator STA VisiblePlayerLineCurrent ;setup pic animations ---------------------------------------------- STA WSYNC ;////////////////////////////////////////////// LDA #43 STA TIM64T LDA #0 STA VSYNC ;------------------------- ;------------------------- WaitForVblankEnd LDA INTIM BNE WaitForVblankEnd LDY #191 STA WSYNC STA HMOVE STA VBLANK ;main scanline loop... PreScanLoop LDA #0 ScanLoop ;start of kernal +++++++++++++++++++++++ STA GRP0 ;put that line as player graphic 0 ;2 cycles AFTERPLAYERDRAW LDA EnemyLineBuffer ;2 cycles STA GRP1 ; put player 1 into grp1 2 cycles AfterEnemyDraw DEY ;count down number of scan lines 1 cycles LDA #8 ;2 cycles CheckActivatePlayer CPY YPosFromBot ;2 cycles BNE SkipActivatePlayer ;2 cycles STA VisiblePlayerLine ;2 cycles SkipActivatePlayer CheckActivateEnemy CPY YPosFromBotE1 ;2 cycles BNE SkipActivateEnemy ;2 cycles STA VisibleEnemyLine ;2 cycles SkipActivateEnemy LDA #0 ;2 cycles STA EnemyLineBuffer ;2 cycles LDA VisibleEnemyLine ;check the visible enemy line... 2 cycles BEQ FinishEnemy ;skip the drawing if its zero... 2 cycles IsEnemyOn LDX VisibleEnemyLineCurrent ;2 cycles LDA EnemyGraphics-1,x ;2 cycles STA EnemyLineBuffer DEC VisibleEnemyLine ;2 cycles DEC VisibleEnemyLineCurrent ;2 cycles FinishEnemy LDA VisiblePlayerLine ;check the visible player line... 2 cycles BEQ FinishPlayer ;skip the drawing if its zero... 2 cycles IsPlayerOn LDX VisiblePlayerLineCurrent ;2 cycles LDA MainPlayerGraphics-1,x ;shift to change which pic were showing 2 cycles ; ORA #1 ;creates a shield DEC VisiblePlayerLineCurrent ;2 cycles DEC VisiblePlayerLine ;2 cycles FinishPlayer CPY #0 ;2 cycles STA WSYNC ;2 cycles BNE ScanLoop ;2 cycles EndScanLoop ;end of kernal +++++++++++++++++ STA WSYNC STA VBLANK LDX #24 OverScanWait STA WSYNC DEX BNE OverScanWait JMP MainLoop MainPlayerGraphics .byte #010100 .byte #010100 .byte #011000 .byte #011000 .byte #%01111110 .byte #010000 .byte #111000 .byte #111000 .byte #010010 .byte #010100 .byte #011000 .byte #011000 .byte #%01111110 .byte #010000 .byte #111000 .byte #111000 EnemyGraphics .byte #%01111000 .byte #%10000100 .byte #001000 .byte #010000 .byte #010000 .byte #010000 .byte #111000 .byte #111000 .byte #%01111000 .byte #%01001000 .byte #010000 .byte #100000 .byte #100000 .byte #100000 .byte #%01110000 .byte #%01110000 org $FFFC .word Start .word Start
#5
Posted Thu Feb 11, 2010 5:29 PM
You are using too many cycles...and you seem to be confused regarding how many cycles are taken by the various instructions / addressing modes. There are NO instructions that only take a single cycle (DEY above should be 2 cycles). Most of the LDAs and STA's above are 3 cycles (not 2). The DEC's are 5 cycles (again, not 2). Branches are 2 cycles if not taken, but 3 cycles if they are.
Worst-case scenario...which is when the program takes the long path (i.e. no branches taken to skip ahead)...is 84 cycles.
Worst-case scenario...which is when the program takes the long path (i.e. no branches taken to skip ahead)...is 84 cycles.
Edited by Nukey Shay, Thu Feb 11, 2010 5:45 PM.
#6
Posted Thu Feb 11, 2010 6:24 PM
Correction...89 cycles worst-case in the scanline loop
#7
Posted Thu Feb 11, 2010 6:44 PM
Thank you very much. I was using number of bytes as the cycle time. Which is why I was totally confused.
#8
Posted Thu Mar 18, 2010 5:53 PM
I'm trying to convert this code to use skipdraw. However so far the graphics aren't correct. What am I doing wrong?
; move a happy face with the joystick by Kirk Israel
; (with a can't'dodge'em line sweeping across the screen)
processor 6502
include vcs.h
org $F000
;Variables ------
YPosFromBot = $80;
VisiblePlayerLine = $81;
PICS = $82;
ROLLING_COUNTER = $83;
Graphics_Buffer = $84
YPosFromBotE1 = $85;
VisibleEnemyLine = $86;
VisibleEnemyLineCurrent = $87;
EnemyLineBuffer = $88;
VisiblePlayerLineCurrent = $90;
BG_0 = $91;
BG_1 = $92;
BG_2 = $93;
; Constants ------
playerheight ds #8;
;generic start up stuff...
Start
SEI
CLD
LDX #$FF
TXS
LDA #0
STA ROLLING_COUNTER
STA PICS
STA EnemyLineBuffer
ClearMem
STA 0,X
DEX
BNE ClearMem
LDA #$00 ;start with a black background
STA COLUBK
LDA #$1C ;lets go for bright yellow, the traditional color for happyfaces
STA COLUP0
;Setting some variables...
LDA #80
STA YPosFromBot ;Initial Y Position
STA YPosFromBotE1
LDA #010001 ; 2 cycles
STA BG_0 ; 3 cycles
STA BG_1 ; 3 cycles
STA BG_2 ; 3 cycles
;; Let's set up the sweeping line. as Missile 1
LDA #2
; STA ENAM1 ;enable it
LDA #33
STA COLUP0 ;color it
STA COLUP1 ;color it
LDA #$10
; STA NUSIZ0 ;make it quadwidth (not so thin, that)
STA NUSIZ1 ;make it quadwidth (not so thin, that)
LDA #000000 ; set to not move
STA HMM1 ; of HMM1 sets it to moving
;VSYNC time
MainLoop ;+++++++++++++++++++++++++++The start of a new screen
LDA #0
STA GRP0
STA GRP1
STA PF0
STA PF1
STA PF2
LDA #2
STA VSYNC
STA WSYNC
; for up and down, we INC or DEC
; the Y Position
LDA #010000 ;Down?
BIT SWCHA
BNE SkipMoveDown
INC YPosFromBot
INC YPosFromBotE1
INC YPosFromBotE1
SkipMoveDown
LDA #100000 ;Up?
BIT SWCHA
BNE SkipMoveUp
DEC YPosFromBot
DEC YPosFromBotE1
DEC YPosFromBotE1
SkipMoveUp
; for left and right, we're gonna
; set the horizontal speed, and then do
; a single HMOVE. We'll use X to hold the
; horizontal speed, then store it in the
; appropriate register
;assum horiz speed will be zero
LDX #0
LDA #%01000000 ;Left?
BIT SWCHA
BNE SkipMoveLeft
LDX #$10 ;a 1 in the left nibble means go left
;; moving left, so we need the mirror image
LDA #001000 ;a 1 in D3 of REFP0 says make it mirror
STA REFP0
STA REFP1
SkipMoveLeft
LDA #%10000000 ;Right?
BIT SWCHA
BNE SkipMoveRight
LDX #$F0 ;a -1 in the left nibble means go right...
;; moving right, cancel any mirrorimage
LDA #000000
STA REFP0
STA REFP1
SkipMoveRight
STX HMP0 ;set the move for player 0, not the missile like last time...
STX HMP1 ;set the move for player 0, not the missile like last time...
; see if player and missile collide, and change the background color if so
;just a review...comparisons of numbers always seem a little backwards to me,
;since it's easier to load up the accumulator with the test value, and then
;compare that value to what's in the register we're interested.
;in this case, we want to see if D7 of CXM1P (meaning Player 0 hit
; missile 1) is on. So we put 10000000 into the Accumulator,
;then use BIT to compare it to the value in CXM1P
LDA #%10000000
BIT CXM1P
BEQ NoCollision ;skip if not hitting...
LDA YPosFromBot ;must be a hit! load in the YPos...
STA COLUBK ;and store as the bgcolor
NoCollision
STA CXCLR ;reset the collision detection for next time
STA WSYNC ;//////////////////////////////////////////////
;setup pic animations ----------------------------------------------
INC ROLLING_COUNTER
LDA ROLLING_COUNTER
AND #15 ;every 8th screen swap to next image of player
CMP #8
BEQ PICSET4
JMP PICSET3
PICSET4 LDA PICS
CMP #8
BEQ PICSET
LDA #8
JMP PICSET2
PICSET LDA #0
PICSET2 STA PICS
PICSET3
LDA ROLLING_COUNTER
AND #25 ;how often to move enemy, larger number is slower
CMP #8
BEQ PICSET5
LDA #001111 ; +1 in the left nibble
JMP PICSET6
PICSET5 LDA #011111 ; 0 in the left nibble
PICSET6 STA HMP1 ; of HMP1 sets it to moving the enemy
LDA #8
CLC
ADC PICS ;add value of pics to Accumulator
STA VisibleEnemyLineCurrent
LDA #8
CLC
ADC PICS ;add value of pics to Accumulator
STA VisiblePlayerLineCurrent
;setup pic animations ----------------------------------------------
STA WSYNC ;//////////////////////////////////////////////
LDA #43
STA TIM64T
LDA #0
STA VSYNC
;------------------------- setup backgrounds 20 pixels accross
LDA #255 ; 3 cycles
STA PF0 ; 3 cycles
STA PF1 ; 3 cycles
STA PF2 ; 3 cycles
;-------------------------
WaitForVblankEnd
LDA INTIM
BNE WaitForVblankEnd
LDY #4 ; was 191
STA WSYNC
STA HMOVE
STA VBLANK
;main scanline loop...
PreScanLoop
ScanLoop1 ;start of kernal +++++++++++++++++++++++ for skyline
LDA PFCOLOR-1,Y ; 4 cycles
STA COLUBK ;and store as the bgcolor ; 3 cycles
LDA PFData0-1,Y ; 4 cycles
STA PF0 ; 3 cycles
LDA PFData1-1,Y ; 4 cycles
STA RESM0 ; 3 cycles places left scan line leftmost
STA PF1 ; 3 cycles
LDA PFData2-1,Y ; 4 cycles
STA PF2 ; 3 cycles
LDA #0 ;2 cycles =30
STA GRP1 ; put player 1 into grp1 3 cycles
STA GRP0 ;put that line as player graphic 0 ;3 cycles =28
DEY ;count down number of scan lines 2 cycles =71
STA WSYNC ;3 cycles =74
BNE ScanLoop1 ;2 cycles =76
EndScanLoop1 ;end of kernal +++++++++++++++++++++++ for skyline
LDA #100;
STA COLUBK ;and store as the bgcolor
LDY #186 ; was 191 was 186
LDA #0
STA PF0 ; 3 cycles
STA PF1 ; 3 cycles
STA PF2 ; 3 cycles
LDA #%11100011 ;The last 3 bits control number and size of players
;the firs 3 bits control missle size
STA NUSIZ0
STA NUSIZ1
STA WSYNC ;3 cycles
ScanLoop ;start of kernal +++++++++++++++++++++++ for players
;--------------------------
; SPRITE DRAW
tya ; 2 Transfers the byte in the Y Register to the Accumulator.
sec ; 2 Sets the carry (C) flag (in the processor Status Register byte).
sbc SpriteEnd ; 3 Subtracts a byte in memory from the byte in the Accumulator, and "borrows" if necessary.
adc #8 ; 2 Adds byte in memory to the byte in the Accumulator, plus the carry flag if set.
bcs .Draw ; 2(3) Branches up to 127 bytes forward or 128 bytes backward from its own address if the carry flag is set.
nop ; 2 Wait
nop ; 2 Wait
sec ; 2 Sets the carry (C) flag
bcs .skipDraw ; 3 Branches up to 127 bytes forward or 128 bytes backward from its own address if the carry flag is set.
.Draw
lda MainPlayerGraphics,y ; 5 Loads the Accumulator with a byte from memory.
sta GRP0 ; 3 Stores the byte in the Accumulator into memory.
.skipDraw
;-->18 cycles used
;--------------------------
STA GRP0 ;set player graphics 3 cycles
STA GRP1 ;set player graphics 3 cycles
DEY ;count down number of scan lines 2 cycles =
STA WSYNC ;3 cycles =
BNE ScanLoop ;2 cycles =
EndScanLoop ;end of kernal +++++++++++++++++ for players
STA WSYNC
STA VBLANK
LDX #24
OverScanWait
STA WSYNC
DEX
BNE OverScanWait
JMP MainLoop
MainPlayerGraphics
.byte #010100
.byte #010100
.byte #011000
.byte #011000
.byte #%01111110
.byte #010000
.byte #111000
.byte #111000
SpriteEnd
.byte #100010
.byte #100100
.byte #101000
.byte #011000
.byte #%01111110
.byte #010000
.byte #111000
.byte #111000
EnemyGraphics
.byte #%01111000
.byte #%10000100
.byte #001000
.byte #010000
.byte #010000
.byte #010000
.byte #111000
.byte #111000
.byte #%01111000
.byte #%01001000
.byte #010000
.byte #100000
.byte #100000
.byte #100000
.byte #%01110000
.byte #%01110000
PFData0
.byte #001111
.byte #011111
.byte #%01111111
.byte #%11111111
PFData1
.byte #000000
.byte #001110
.byte #111111
.byte #%01111111
PFData2
.byte #000000
.byte #011000
.byte #%10111100
.byte #%11111111
PFCOLOR
.byte #$5F
.byte #$5D
.byte #$5B
.byte #$59
org $FFFC
.word Start
.word Start
1 user(s) are reading this topic
0 members, 1 guests, 0 anonymous users














