I've been working on learning how to wrap sprites around the screen. The effect being that when the sprite starts to leave one side of the screen it begins to appear on the opposite.
My example code works in the y-axis (I think x-axis is going to be tricky) and moves 1 pixel at a time either upwards or downwards. To change direction just press the D key. I'm sure it's not the best or smartess solution but, it works. Hope you like it.
Code: Select all
xmin equ 0
xmax equ 319
ymin equ 0
ymax equ 199
spriteH equ 18			;value in total scanlines i.e pixel height
spriteW equ 4			;value in bytes in the x axis on one scanline
org &4000
	
	ld a,1			;screen mode
	call &BC0E
	ld b,0			;screen background colour
	ld c,b
	call &BC32
	ld b,2			;screen border colour
	ld c,b
	call &BC38
		
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mainloop			;start of main loop
	ld a,66			;ESC key. 66=ESC key code
	call &BB1E		;key press check	
	jp nz,finish		;if ESC key pressed, exit to BASIC
	
	ld a,61			;D key 
	call &BB1E		;key press check
	call nz,changedir	;if pressed, perform vertical direction change
	call updateplayermovements
	
	call drawscreenobjects		
	call &BD19 		;wait for v-sync
	
	;call &bb18		;wait for any key press
	jr mainloop
finish:
	ret			;back to BASIC	
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
updateplayermovements
	
	call updatespritepos	;update new sprite x/y position
	
	ret
drawscreenobjects
	
	call drawplayer
	
	ret
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
changedir:
	
	ld a,(dir)		;get current dir flag
	xor 1			;flip the 1 to 0 or vice versa to change directional flag
	ld (dir),a		;save flag back to memory
	
	ret
updatespritepos:
	ld hl,(ypos)		;get current ypos
	
	ld a,(dir)		;load direction flag
		
	cp 0			;if it's 0 then we go in a downwards direction
	jr z,_sub 
			
	cp 1			;if it's 1 then we go in an upwards direction
	jr z,_add
	ret			;don't really need this return but, just in case something slips through
  _sub	
	ld a,l			;get current ypos	
	cp ymin			;have we reached bottom of screen?
	jr z,__resettotop	;if we have, reset pos to top	
	
	dec hl			;decrement ypos by one
	jr _save
  __resettotop
	ld hl,ymax		;set ypos to ymax amount
	jr _save	
  _add	
	ld a,l			;get current ypos
	cp ymax			;have we reached top of screen?
	jr z,__resettobottom	;if we have, reset pos to bottom
	inc hl			;increment ypos by one
	jr _save
  __resettobottom
	ld hl,ymin		;set ypos to ymin amount
	jr _save
  _save	
	ld (ypos),hl		;save new ypos		 
	ret
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
drawplayer:
	ld de,(xpos)		;load in current xpos in pixels
	ld hl,(ypos)		;load in current ypos in pixels
	
	call &bc1d		;convert x/y to screen address, which gets saved in HL. AF & DE get corrupt
	ld (scrmempos),hl 	;save copy of the initial start screen address 
				
				;The lines below are like a function call whereby we pass it 3 parameters
				;
	ld hl, sprite_bar	;param 1 - load in sprite data 
	ld de,(scrmempos)	;param 2 - load in screen start memory pos
	ld a, spriteH		;param 3 - height of sprite (in pixel lines)	
	call drawobject		;call the function to draw the sprite
	ret
drawobject:
	
	;Entry needs to be as follows;
	;
	; HL = Sprite data
	; DE = Screen start address
	; A  = Sprite height in pixels
	
_plotline
	ld bc,spriteW		;max horizontal byte count for scanline (loop)
	push af			;save the sprite height count
	and c			;reset the Zero flag because we need to test against it to
				;see if we have reached the maximum horizontal byte count of the scanline
	ldir			;blit the scanline data to the screen
	
	pop af			;read back the height counter i.e current value
	dec a			;reduce the height loop counter by one
	cp &0			;has the counter reached Zero?
	ret z			;if yes, the sprite has been fully plotted, return to calling function
	push af			;if not, save the current scanline counter value so we don't loose track.. 
				;..of which scanline we're at in the sprite plot
__updatescradd:			;this block is to move to the next (sprite) scanline
	ex de,hl		;we need to swap the two values around because we need DE's value in HL
	ld hl,(scrmempos)	;get last scanline start address
___bottomcheck:
	ld a,h			;lets check if the new scanline has reached the bottom of the screen
		
	cp &ff			;if the new value is &FF then we have reached the bottom screen boundary
				
	jp nz,_ok		;we use the Z flag to decide what we need to do based on the evaluation above
				;if we haven't hit the bottom then skip rest of the code and check if we hit top
				;of screen
	ld a,l			;if the first check has been met then we have to check the low byte as well
	cp &80			;we compare this to &80 as that is the beginning of the last scanline low byte
	
	jp c,_ok		;we check against the C flag as we want to perform a greater than check..
				;..because the value can potentially be between &80 and &CF i.e
				;left hand side of the screen to the right hand side of the screen
				;again, if this condition is not met then resume as normal
	;the block below does the sprite "wrap" by subtracting &3F80 (amount to take in back to the top)
	;from current scanline address
	ld a,h			;load H value into A
	sub a,&3f		;subtract &3F 	
	ld h,a			;save new H value back
	ld a,l			;load L into A
	sub a,&80		;subtract &80
	ld l,a			;save new L value back
	jr _ok
___topcheck:
	ld a,h			;lets check if the new scanline will exceed the bottom of the screen	
	cp &c0			;if the new value is &00 then we have crossed the bottom screen boundary
				
	jp nz,_ok		;we use the Z flag to decide what we need to do based on the evaluation above
				;if we haven't hit the bottom then skip rest of the code and resume as normal
	ld a,l			;if the first check has been met then we have to check the low byte as well	
	cp &4f			;we compare this to &80 as that is the beginning of the last scanline low byte
	
	jp nc,_ok		;we check against the C flag as we want to perform a less than check..
				;..because the value can potentially be between &00 and &4F i.e
				;left hand side of the screen to the right hand side of the screen
				;again, if this condition is not met then resume as normal
	;the block below does the sprite "wrap" by subtracting &3F80 (amount to take in back to the top)
	;from current scanline address
	ld a,h			;load H value into A
	add a,&3f		;subtract &3F 	
	ld h,a			;save new H value back
	ld a,l			;load L into A
	add a,&80		;subtract &80
	ld l,a	
_ok:	
	call &bc26 		;get next scanline start address based on current HL value. AF gets corrupt
	pop af			;restore the scanline counter value
	ld (scrmempos),hl	;save new scanline address for use in the blit 
	ex de,hl		;(re)swap the values around
	jr _plotline		;plot scanline
	ret
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;various object declarations/definitions
xpos:		defw 150 		;sprite start x-pos
ypos:		defw spriteH 		;sprite start y-pos
dir:		defb 1			;player direction flag 0=downwards 1=upwards
scrmempos:	defw 1			;used to store screen memory start location.
					;this is important as the whole sprite print logic works
					;relative to this
nolist
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;various sprite data
sprite_Bar:
defb &00,&00,&00,&00; line 0
defb &00,&FF,&FF,&00; line 1
defb &00,&FF,&FF,&00; line 1
defb &33,&FF,&ff,&cc; line 3
defb &33,&FF,&FF,&cc; line 4
defb &00,&FF,&FF,&00; line 2
defb &00,&FF,&FF,&00; line 2
defb &00,&FF,&FF,&00; line 2
defb &00,&FF,&FF,&00; line 2
defb &00,&FF,&FF,&00; line 2
defb &00,&FF,&FF,&00; line 2
defb &00,&FF,&FF,&00; line 2
defb &00,&FF,&FF,&00; line 2
defb &33,&FF,&ff,&cc; line 3
defb &33,&FF,&FF,&cc; line 4
defb &00,&FF,&FF,&00; line 5
defb &00,&FF,&FF,&00; line 6
defb &00,&00,&00,&00; line 7