SPO600 Lab2 (Pt.2)-- challenges 1 and 2
In Part 1, I have modified the code of 6502 processor so that an logo can bounce within the screen.
Challenges
Now, we have a few challenges. We would like to modified the code so that it can meet the following requirement:
1. Permit integer value other than -1 and +1 for the X and Y increments (logo velocity).
2. Permit fractional value for the X and Y increments (eg. +1.5 or -0.75)
3. Perturb the ball's position or velocity (To be done next blog)
4. Change the graphic image or colour each time it bounces (To be done next blog)
Challenge 1.
Problems analysis and solutions
Assumption: the velocity cannot be larger than the screen size, i.e. the ball will not bounce more than once within one frame.
Problem of Challenge 1:
Since the current algorithm is just checking whether the logo is on the edge to decide whether we should reverse the velocity to perform a bounce. However, it only works when the velocity is 1. If the velocity is 2 and the displacement of the ball from the edge is 1, bounce will not be performed and could cause error.
solution for challenge 1:
Instead of only checking the current position of the logo, we can calculate the expected location after movement to see if it excess the boundary. If so, recalculate the location and reverse the velocity.
code:
; draw-image-subroutine.6502
;
; This is a routine that can place an arbitrary
; rectangular image on to the screen at given
; coordinates.
;
; Chris Tyler 2024-09-17
; Licensed under GPLv2+
;
; The subroutine is below starting at the
; label "DRAW:"
; Zero-page variables
define XPOS $20
define YPOS $21
define X_V $22
define Y_V $23
define XNEXT $24
define YNEXT $25
START:
; Set up the width and height elements of the data structure
LDA #$05
STA $12 ; IMAGE WIDTH
STA $13 ; IMAGE HEIGHT
; randomize initial position within 0 to 3
LDA $fe
AND #$03
STA XPOS
LDA $fe
AND #$03
STA YPOS
; randomize initial velocity within 1 to 3
LDA $fe
AND #$03
ORA #$01
STA X_V
LDA $fe
AND #$03
ORA #$01
STA Y_V
; Main loop for diagonal animation
MAINLOOP:
; Set pointer to the image
; Use G_O or G_X as desired
; The syntax #<LABEL returns the low byte of LABEL
; The syntax #>LABEL returns the high byte of LABEL
LDA #<G_X
STA $10
LDA #>G_X
STA $11
; Place the image on the screen
LDA #$10 ; Address in zeropage of the data structure
LDX XPOS ; X position
LDY YPOS ; Y position
JSR DRAW ; Call the subroutine
; Delay to show the image
LDY #$00
LDX #$50
DELAY:
DEY
BNE DELAY
DEX
BNE DELAY
; Set pointer to the blank graphic
LDA #<G_BLANK
STA $10
LDA #>G_BLANK
STA $11
; Draw the blank graphic to clear the old image
LDA #$10 ; LOCATION OF DATA STRUCTURE
LDX XPOS
LDY YPOS
JSR DRAW
JMP MOVE
TEMP: JMP MAINLOOP
; Increment the predicted position
MOVE: LDA X_V
CLC
ADC XPOS
STA XNEXT
LDA Y_V
CLC
ADC YPOS
STA YNEXT
X_LEFTCHECK: ;check if X reach left edge
LDA XNEXT
BMI X_BOUNCE_L
;check if X excess right edge
LDA XNEXT
CMP #$1b
BCS X_BOUNCE_R
JMP Y_TOPCHECK
X_BOUNCE_R: ;bounce on right edge
LDA #$00
SEC
SBC X_V
STA X_V
LDA XNEXT
SEC
SBC #$1b
STA XNEXT
LDA #$1b
SEC
SBC XNEXT
STA XNEXT
JMP Y_TOPCHECK
X_BOUNCE_L: ;bounce on left edge
LDA #$00
SEC
SBC X_V
STA X_V
LDA #$00
SEC
SBC XNEXT
STA XNEXT
;check if Y reach TOP edge
Y_TOPCHECK: LDA YNEXT
BMI Y_BOUNCE_T
;check if Y reach Bottom edge
Y_BOTCHECK: LDA YNEXT
CMP #$1b
BCS Y_BOUNCE_B
JMP END_CHECK
Y_BOUNCE_T:
LDA #$00
SEC
SBC Y_V
STA Y_V
LDA #$00
SEC
SBC YNEXT
STA YNEXT
JMP END_CHECK
Y_BOUNCE_B:
LDA #$00
SEC
SBC Y_V
STA Y_V
LDA YNEXT
SEC
SBC #$1b
STA YNEXT
LDA #$1b
SEC
SBC YNEXT
STA YNEXT
END_CHECK:
LDA XNEXT
STA XPOS
LDA YNEXT
STA YPOS
JMP TEMP ; Repeat infinitely
; ==========================================
;
; DRAW :: Subroutine to draw an image on
; the bitmapped display
;
; Entry conditions:
; A - location in zero page of:
; a pointer to the image (2 bytes)
; followed by the image width (1 byte)
; followed by the image height (1 byte)
; X - horizontal location to put the image
; Y - vertical location to put the image
;
; Exit conditions:
; All registers are undefined
;
; Zero-page memory locations
define IMGPTR $A0
define IMGPTRH $A1
define IMGWIDTH $A2
define IMGHEIGHT $A3
define SCRPTR $A4
define SCRPTRH $A5
define SCRX $A6
define SCRY $A7
DRAW:
; SAVE THE X AND Y REG VALUES
STY SCRY
STX SCRX
; GET THE DATA STRUCTURE
TAY
LDA $0000,Y
STA IMGPTR
LDA $0001,Y
STA IMGPTRH
LDA $0002,Y
STA IMGWIDTH
LDA $0003,Y
STA IMGHEIGHT
; CALCULATE THE START OF THE IMAGE ON
; SCREEN AND PLACE IN SCRPTRH
;
; THIS IS $0200 (START OF SCREEN) +
; SCRX + SCRY * 32
;
; WE'LL DO THE MULTIPLICATION FIRST
; START BY PLACING SCRY INTO SCRPTR
LDA #$00
STA SCRPTRH
LDA SCRY
STA SCRPTR
; NOW DO 5 LEFT SHIFTS TO MULTIPLY BY 32
LDY #$05 ; NUMBER OF SHIFTS
MULT:
ASL SCRPTR ; PERFORM 16-BIT LEFT SHIFT
ROL SCRPTRH
DEY
BNE MULT
; NOW ADD THE X VALUE
LDA SCRX
CLC
ADC SCRPTR
STA SCRPTR
LDA #$00
ADC SCRPTRH
STA SCRPTRH
; NOW ADD THE SCREEN BASE ADDRESS OF $0200
; SINCE THE LOW BYTE IS $00 WE CAN IGNORE IT
LDA #$02
CLC
ADC SCRPTRH
STA SCRPTRH
; NOTE WE COULD HAVE DONE TWO: INC SCRPTRH
; NOW WE HAVE A POINTER TO THE IMAGE IN MEM
; COPY A ROW OF IMAGE DATA
COPYROW:
LDY #$00
ROWLOOP:
LDA (IMGPTR),Y
STA (SCRPTR),Y
INY
CPY IMGWIDTH
BNE ROWLOOP
; NOW WE NEED TO ADVANCE TO THE NEXT ROW
; ADD IMGWIDTH TO THE IMGPTR
LDA IMGWIDTH
CLC
ADC IMGPTR
STA IMGPTR
LDA #$00
ADC IMGPTRH
STA IMGPTRH
; ADD 32 TO THE SCRPTR
LDA #32
CLC
ADC SCRPTR
STA SCRPTR
LDA #$00
ADC SCRPTRH
STA SCRPTRH
; DECREMENT THE LINE COUNT AND SEE IF WE'RE
; DONE
DEC IMGHEIGHT
BNE COPYROW
RTS
; ==========================================
; 5x5 pixel images
; Image of a blue "O" on black background
G_O:
DCB $00,$0e,$0e,$0e,$00
DCB $0e,$00,$00,$00,$0e
DCB $0e,$00,$00,$00,$0e
DCB $0e,$00,$00,$00,$0e
DCB $00,$0e,$0e,$0e,$00
; Image of a yellow "X" on a black background
G_X:
DCB $07,$00,$00,$00,$07
DCB $00,$07,$00,$07,$00
DCB $00,$00,$07,$00,$00
DCB $00,$07,$00,$07,$00
DCB $07,$00,$00,$00,$07
; Image of a black square
G_BLANK:
DCB $00,$00,$00,$00,$00
DCB $00,$00,$00,$00,$00
DCB $00,$00,$00,$00,$00
DCB $00,$00,$00,$00,$00
DCB $00,$00,$00,$00,$00
red highlighted part: randomized initial velocity and position
yellow highlighted part: calculated the predicted position
green highlighted code: check if the predicted position out of boundary. if so, recalculate the position and reverse the velocity
blue highlighted part: save the predicted position to position
output:
Challenge 2.
Permit fractional value for the X and Y increments (eg. +1.5 or -0.75)
Problems analysis and solutions
This is quite simple given that in challenge 1, we fix the program so that it have functionality to check if the predict position is out of boundary. To solve this problem, we use 2 bytes of memory to store velocity and position in each direction. 2 byte value's addition and subtraction may take some time, but generally it should be easy.
code:
; draw-image-subroutine.6502
;
; This is a routine that can place an arbitrary
; rectangular image on to the screen at given
; coordinates.
;
; Chris Tyler 2024-09-17
; Licensed under GPLv2+
;
; The subroutine is below starting at the
; label "DRAW:"
; Zero-page variables
define XPOSL $20
define XPOSH $21
define YPOSL $22
define YPOSH $23
define XNEXTL $24
define XNEXTH $25
define YNEXTL $26
define YNEXTH $27
define X_VL $28
define X_VH $29
define Y_VL $30
define Y_VH $31
START:
; Set up the width and height elements of the data structure
LDA #$05
STA $12 ; IMAGE WIDTH
STA $13 ; IMAGE HEIGHT
; initial position
LDA #$00
STA XPOSL
LDA #$01
STA XPOSH
LDA #$00
STA YPOSL
LDA #$03
STA YPOSH
; initial velocity x = 1.5, y =-0.75
LDA #$01
STA X_VH
LDA #$80
STA X_VL
LDA #$40
STA Y_VL
LDA #$ff
STA Y_VH
; Main loop for diagonal animation
MAINLOOP:
; Set pointer to the image
; Use G_O or G_X as desired
; The syntax #<LABEL returns the low byte of LABEL
; The syntax #>LABEL returns the high byte of LABEL
LDA #<G_X
STA $10
LDA #>G_X
STA $11
; Place the image on the screen
LDA #$10 ; Address in zeropage of the data structure
LDX XPOSH ; X position
LDY YPOSH ; Y position
JSR DRAW ; Call the subroutine
; Delay to show the image
LDY #$00
LDX #$50
DELAY:
DEY
BNE DELAY
DEX
BNE DELAY
; Set pointer to the blank graphic
LDA #<G_BLANK
STA $10
LDA #>G_BLANK
STA $11
; Draw the blank graphic to clear the old image
LDA #$10 ; LOCATION OF DATA STRUCTURE
LDX XPOSH
LDY YPOSH
JSR DRAW
JMP MOVE
TEMP: JMP MAINLOOP
; Increment the predicted position
MOVE: LDA X_VL
CLC
ADC XPOSL
STA XNEXTL
LDA X_VH
ADC XPOSH
STA XNEXTH
LDA Y_VL
CLC
ADC YPOSL
STA YNEXTL
LDA Y_VH
ADC YPOSH
STA YNEXTH
X_LEFTCHECK: ;check if X reach left edge
LDA XNEXTH
BMI X_BOUNCE_L
;check if X excess right edge
LDA XNEXTH
CMP #$1b
BCS X_BOUNCE_R
JMP Y_TOPCHECK
X_BOUNCE_R: ;bounce on right edge
LDA #$00
SEC
SBC X_VL
STA X_VL
LDA #$00
SBC X_VH
STA X_VH
LDA XNEXTH
SEC
SBC #$1b
STA XNEXTH
LDA $00
SEC
SBC XNEXTL
STA XNEXTL
LDA #$1b
SBC XNEXTH
STA XNEXTH
JMP Y_TOPCHECK
X_BOUNCE_L: ;bounce on left edge
LDA #$00
SEC
SBC X_VL
STA X_VL
LDA #$00
SBC X_VH
STA X_VH
LDA #$00
SEC
SBC XNEXTL
STA XNEXTL
LDA #$00
SBC XNEXTH
STA XNEXTH
;check if Y reach TOP edge
Y_TOPCHECK: LDA YNEXTH
BMI Y_BOUNCE_T
;check if Y reach Bottom edge
Y_BOTCHECK: LDA YNEXTH
CMP #$1b
BCS Y_BOUNCE_B
JMP END_CHECK
Y_BOUNCE_T:
LDA #$00 ;reverse velocity
SEC
SBC Y_VL
STA Y_VL
LDA #$00
SBC Y_VH
STA Y_VH
;reverse position
LDA #$00
SEC
SBC YNEXTL
STA YNEXTL
LDA #$00
SBC YNEXTH
STA YNEXTH
JMP END_CHECK
Y_BOUNCE_B:
LDA #$00
SEC
SBC Y_VL
STA Y_VL
LDA #$00
SBC Y_VH
STA Y_VH
LDA YNEXTH
SEC
SBC #$1b
STA YNEXTH
LDA $00
SEC
SBC YNEXTL
STA YNEXTL
LDA #$1b
SBC YNEXTH
STA YNEXTH
END_CHECK:
LDA XNEXTH
STA XPOSH
LDA XNEXTL
STA XPOSL
LDA YNEXTH
STA YPOSH
LDA YNEXTL
STA YPOSL
JMP TEMP ; Repeat infinitely
; ==========================================
;
; DRAW :: Subroutine to draw an image on
; the bitmapped display
;
; Entry conditions:
; A - location in zero page of:
; a pointer to the image (2 bytes)
; followed by the image width (1 byte)
; followed by the image height (1 byte)
; X - horizontal location to put the image
; Y - vertical location to put the image
;
; Exit conditions:
; All registers are undefined
;
; Zero-page memory locations
define IMGPTR $A0
define IMGPTRH $A1
define IMGWIDTH $A2
define IMGHEIGHT $A3
define SCRPTR $A4
define SCRPTRH $A5
define SCRX $A6
define SCRY $A7
DRAW:
; SAVE THE X AND Y REG VALUES
STY SCRY
STX SCRX
; GET THE DATA STRUCTURE
TAY
LDA $0000,Y
STA IMGPTR
LDA $0001,Y
STA IMGPTRH
LDA $0002,Y
STA IMGWIDTH
LDA $0003,Y
STA IMGHEIGHT
; CALCULATE THE START OF THE IMAGE ON
; SCREEN AND PLACE IN SCRPTRH
;
; THIS IS $0200 (START OF SCREEN) +
; SCRX + SCRY * 32
;
; WE'LL DO THE MULTIPLICATION FIRST
; START BY PLACING SCRY INTO SCRPTR
LDA #$00
STA SCRPTRH
LDA SCRY
STA SCRPTR
; NOW DO 5 LEFT SHIFTS TO MULTIPLY BY 32
LDY #$05 ; NUMBER OF SHIFTS
MULT:
ASL SCRPTR ; PERFORM 16-BIT LEFT SHIFT
ROL SCRPTRH
DEY
BNE MULT
; NOW ADD THE X VALUE
LDA SCRX
CLC
ADC SCRPTR
STA SCRPTR
LDA #$00
ADC SCRPTRH
STA SCRPTRH
; NOW ADD THE SCREEN BASE ADDRESS OF $0200
; SINCE THE LOW BYTE IS $00 WE CAN IGNORE IT
LDA #$02
CLC
ADC SCRPTRH
STA SCRPTRH
; NOTE WE COULD HAVE DONE TWO: INC SCRPTRH
; NOW WE HAVE A POINTER TO THE IMAGE IN MEM
; COPY A ROW OF IMAGE DATA
COPYROW:
LDY #$00
ROWLOOP:
LDA (IMGPTR),Y
STA (SCRPTR),Y
INY
CPY IMGWIDTH
BNE ROWLOOP
; NOW WE NEED TO ADVANCE TO THE NEXT ROW
; ADD IMGWIDTH TO THE IMGPTR
LDA IMGWIDTH
CLC
ADC IMGPTR
STA IMGPTR
LDA #$00
ADC IMGPTRH
STA IMGPTRH
; ADD 32 TO THE SCRPTR
LDA #32
CLC
ADC SCRPTR
STA SCRPTR
LDA #$00
ADC SCRPTRH
STA SCRPTRH
; DECREMENT THE LINE COUNT AND SEE IF WE'RE
; DONE
DEC IMGHEIGHT
BNE COPYROW
RTS
; ==========================================
; 5x5 pixel images
; Image of a blue "O" on black background
G_O:
DCB $00,$0e,$0e,$0e,$00
DCB $0e,$00,$00,$00,$0e
DCB $0e,$00,$00,$00,$0e
DCB $0e,$00,$00,$00,$0e
DCB $00,$0e,$0e,$0e,$00
; Image of a yellow "X" on a black background
G_X:
DCB $07,$00,$00,$00,$07
DCB $00,$07,$00,$07,$00
DCB $00,$00,$07,$00,$00
DCB $00,$07,$00,$07,$00
DCB $07,$00,$00,$00,$07
; Image of a black square
G_BLANK:
DCB $00,$00,$00,$00,$00
DCB $00,$00,$00,$00,$00
DCB $00,$00,$00,$00,$00
DCB $00,$00,$00,$00,$00
DCB $00,$00,$00,$00,$00
yellow highlighted part: initial value with high-bytes and low-bytes
blue highlighted part: 2-bytes addition and subtraction are performed in the move and bounce functions
red highlighted part: store both the high and low bytes of the predicted and adjusted positions.
Ouptut:
Challenges 3 and 4 will be completed in next blog
Comments
Post a Comment