;; This example demonstrates how to draw a compiled sprite on the screen. ;; ;; The compiled sprite code has been generated by a program. ;; ;; Each function draws 1 sprite. The function contains the instructions needed to draw that sprite. ;; ;; Compiled sprites are fast because you avoid unnecessary masking, reading from memory etc. ;; All the data is within each instruction. ;; ;; Compiled sprites are hard, perhaps impossible to clip. ;; org &8000 ;; turn off listing; remove for pasmo assembler nolist scr_set_mode equ &bc0e txt_output equ &bb5a mc_wait_flyback equ &bd19 km_test_key equ &bb1e scr_set_ink equ &bc32 ;; these are not needed by the draw routines, only to erase the sprite after. ;; all sprites in this example are the same size sprite_height equ 16 ;; sprite height in lines sprite_width_pixels equ 14 ;; sprite width in mode 0 pixels sprite_width_bytes equ sprite_width_pixels/2 ;; sprite width in bytes ;;----------------------------------------------------------------------------------------------------- start: ;; set mode to 0 ld a,0 call scr_set_mode ;; put something on the screen so we can see the sprite masking working ld d,'A' ld b,24 l2: ld c,20 l1: ld a,d call txt_output dec c jr nz,l1 inc d dec b jr nz,l2 ;; make table of screen addresses for the start of each scanline call make_scr_table ;; draw sprite call draw_sprite_cur_coords ;;--------------------------------------------------- main_loop: ;; wait for VSYNC call mc_wait_flyback ;; get current coords and store them in prev coords ;; we compare new coords to previous coords to determine ;; if we should erase and then redraw the sprite. ;; this avoids continuous flicker if the sprite is not moving ;; however, the sprite can still disapear when moving around ;; the screen because there is a time when the sprite has been ;; deleted, the monitor has drawn it when it has been deleted ;; and we then draw the new version too late. ld hl,(sprite_coords) ld (prev_coords),hl ;; check keys call do_keys ;; wait for next interrupt ;; this ensures our code takes longer than the vsync time ;; so we can always wait just for the start of the vsync halt ;; draw the sprite if it has moved call redraw_sprite jp main_loop ;;----------------------------------------------------------------------------------------------------- redraw_sprite: ;; coords changed? ld hl,(prev_coords) ld bc,(sprite_coords) or a sbc hl,bc ld a,h or l jr nz,rs1 ;; no change in x or y, so no update ret ;;----------------------------------------------------------------------------------------------------- rs1: ;; restore background (where sprite used to be) ld hl,(prev_coords) ld de,sprite_background ld b,sprite_height ld c,sprite_width_bytes call sprite_background_restore draw_sprite_cur_coords: ;; store background pixels where sprite is now located ld hl,(sprite_coords) ld de,sprite_background ld b,sprite_height ld c,sprite_width_bytes call sprite_background_store ld hl,(sprite_coords) call get_scr_addr ;; uncomment each line to draw each sprite call sprite_0 ;;call sprite_1 ;;call sprite_2 ret ;;----------------------------------------------------------------------------------------------------- ;; initialise a table make_scr_table: ld hl,&c000 ld b,200 ld ix,scr_table mst1: ld (ix+0),l ld (ix+1),h call scr_next_line inc ix inc ix djnz mst1 ret ;;----------------------------------------------------------------------------------------------------- scr_table: defs 200*2 ;;----------------------------------------------------------------------------------------------------- ;; input conditions: ;; H = x byte coordinate (0-((scr_width_chars*2)-1)) ;; L = y coordinate (0-((scr_height_chars*char_height_lines)-1)) ;; output conditions: ;; HL = screen address get_scr_addr: push bc push de ld d,0 ld e,h ;; DE = x coordinate ld h,0 ;; HL = y coordinate add hl,hl ;; x2 for offset into table (2 bytes per y line) ld bc,scr_table add hl,bc ld a,(hl) inc hl ld h,(hl) ld l,a ;; HL = screen address for start of line ;; now add on X add hl,de pop de pop bc ret ;;----------------------------------------------------------------------------------------------------- ;; input conditions: ;; HL = screen address ;; output conditions: ;; HL = screen address (next scanline down) ;; scr_next_line: ;; go down next scan line ld a,h add a,8 ld h,a ret nc ;; add on amount to go to next char line ld a,l add a,&50 ld l,a ld a,h adc a,&c0 ld h,a ret ;;----------------------------------------------------------------------------------------------------- ;; check keyboard ;; ;; cursor keys do_keys: ld a,0*8+0 call km_test_key jr nz,move_up ld a,0*8+1 call km_test_key jr nz,move_right ld a,0*8+2 call km_test_key jr nz,move_down ld a,1*8+0 call km_test_key jr nz,move_left ret ;;----------------------------------------------------------------------------------------------------- move_up: ;; do not move up if we are already on line 0 ld a,(y_coord) or a ret z dec a ld (y_coord),a ret ;;----------------------------------------------------------------------------------------------------- move_down: ;; avoid going off bottom by checking for bottom-most y position ld a,(y_coord) sub 200-sprite_height ret nc ;; greater than or equal to this pos then don't increment ld a,(y_coord) inc a ld (y_coord),a ret ;;----------------------------------------------------------------------------------------------------- move_left: ;; avoiding going off left side ld a,(x_coord) or a ret z dec a ld (x_coord),a ret ;;----------------------------------------------------------------------------------------------------- right_side equ (40*2)-sprite_width_bytes move_right: ld a,(x_coord) sub right_side ret nc ld a,(x_coord) inc a ld (x_coord),a ret ;;----------------------------------------------------------------------------------------------------- ;; H = x byte coord ;; L = y line ;; DE = address to store screen data ;; B = height ;; C = width ;; store a rectangle from the screen into a buffer sprite_background_store: call get_scr_addr sprite_back_height: push bc push hl sprite_back_width: ld a,(hl) ;; read from screen ld (de),a ;; store to buffer inc hl inc de dec c jr nz,sprite_back_width pop hl call scr_next_line pop bc djnz sprite_back_height ret ;; H = x byte coord ;; L = y line ;; DE = address to store screen data ;; B = height ;; C = width ;; ;; restore a rectangle to the screen sprite_background_restore: call get_scr_addr sprite_reback_height: push bc push hl sprite_reback_width: ld a,(de) ;; read from buffer ld (hl),a ;; write to screen inc hl inc de dec c jr nz,sprite_reback_width pop hl call scr_next_line pop bc djnz sprite_reback_height ret ;;-------------------------------------------------------------------------------------------------------------------------------- ;; drawing function for sprite 0 ;; ;; the sprite pixel data is "compiled" into the function. ;; ;; ld (hl),&cc for example is writing 2 pixels direct to the screen, the pixel data is &cc. ;; ;; ld a,(hl) ;; and &aa ;; or &44 ;; ld (hl),a ;; ;; is masking the screen and writing some pixels ;; ;; inc hl is for skipping a byte containing 2 transparent pixels ;; ;; this code is only for this specific sprite, each sprite has it's own code ;; note the code is not optimised. ;; ;; entry to each function: ;; HL = screen address sprite_0: push hl ;; remember address of line inc hl ld a,(hl) and &aa ld (hl),a inc hl ld (hl),&cc inc hl ld (hl),&cc inc hl ld (hl),&cc pop hl ;; restore address of line call scr_next_line ;; go to next line down push hl inc hl ld (hl),&cc inc hl ld (hl),&cc inc hl ld (hl),&cc inc hl ld (hl),&cc pop hl call scr_next_line push hl ld a,(hl) and &aa or &44 ld (hl),a inc hl ld (hl),&cc inc hl ld a,(hl) and &55 or &88 ld (hl),a inc hl inc hl inc hl ld a,(hl) and &aa ld (hl),a inc hl ld (hl),&cc pop hl call scr_next_line push hl ld a,(hl) and &aa or &44 ld (hl),a inc hl ld (hl),&cc inc hl ld a,(hl) and &55 or &88 ld (hl),a inc hl inc hl inc hl ld a,(hl) and &aa ld (hl),a inc hl ld (hl),&cc pop hl call scr_next_line push hl ld a,(hl) and &aa or &44 ld (hl),a inc hl ld (hl),&cc inc hl ld a,(hl) and &55 or &88 ld (hl),a pop hl call scr_next_line push hl ld a,(hl) and &aa or &44 ld (hl),a inc hl ld (hl),&cc inc hl ld a,(hl) and &55 or &88 ld (hl),a pop hl call scr_next_line push hl ld a,(hl) and &aa or &44 ld (hl),a inc hl ld (hl),&cc inc hl ld a,(hl) and &55 or &88 ld (hl),a pop hl call scr_next_line push hl ld a,(hl) and &aa or &44 ld (hl),a inc hl ld (hl),&cc inc hl ld a,(hl) and &55 or &88 ld (hl),a pop hl call scr_next_line push hl ld a,(hl) and &aa or &44 ld (hl),a inc hl ld (hl),&cc inc hl ld a,(hl) and &55 or &88 ld (hl),a pop hl call scr_next_line push hl ld a,(hl) and &aa or &44 ld (hl),a inc hl ld (hl),&cc inc hl ld a,(hl) and &55 or &88 ld (hl),a pop hl call scr_next_line push hl ld a,(hl) and &aa or &44 ld (hl),a inc hl ld (hl),&cc inc hl ld a,(hl) and &55 or &88 ld (hl),a pop hl call scr_next_line push hl ld a,(hl) and &aa or &44 ld (hl),a inc hl ld (hl),&cc inc hl ld a,(hl) and &55 or &88 ld (hl),a pop hl call scr_next_line push hl ld a,(hl) and &aa or &44 ld (hl),a inc hl ld (hl),&cc inc hl ld a,(hl) and &55 or &88 ld (hl),a inc hl inc hl inc hl ld a,(hl) and &aa ld (hl),a inc hl ld (hl),&cc pop hl call scr_next_line push hl ld a,(hl) and &aa or &44 ld (hl),a inc hl ld (hl),&cc inc hl ld a,(hl) and &55 or &88 ld (hl),a inc hl inc hl inc hl ld a,(hl) and &aa ld (hl),a inc hl ld (hl),&cc pop hl call scr_next_line push hl inc hl ld (hl),&cc inc hl ld (hl),&cc inc hl ld (hl),&cc inc hl ld (hl),&cc inc hl ld a,(hl) and &55 or &88 ld (hl),a pop hl call scr_next_line inc hl ld (hl),&cc inc hl ld (hl),&cc inc hl ld (hl),&cc inc hl ld a,(hl) and &55 or &88 ld (hl),a ret ;;-------------------------------------------------------------------------------------------------------------------------------- ;; drawing function for sprite 1 sprite_1: push hl inc hl ld a,(hl) and &aa ld (hl),a inc hl ld (hl),&c0 inc hl ld (hl),&c0 inc hl ld (hl),&c0 inc hl ld a,(hl) and &55 or &80 ld (hl),a pop hl call scr_next_line push hl inc hl ld (hl),&c0 inc hl ld (hl),&c0 inc hl ld (hl),&c0 inc hl ld (hl),&c0 pop hl call scr_next_line push hl ld a,(hl) and &aa or &40 ld (hl),a inc hl ld (hl),&c0 inc hl ld a,(hl) and &55 or &80 ld (hl),a inc hl inc hl inc hl ld a,(hl) and &aa ld (hl),a inc hl ld (hl),&c0 pop hl call scr_next_line push hl ld a,(hl) and &aa or &40 ld (hl),a inc hl ld (hl),&c0 inc hl ld a,(hl) and &55 or &80 ld (hl),a inc hl inc hl inc hl ld a,(hl) and &aa ld (hl),a inc hl ld (hl),&c0 pop hl call scr_next_line push hl ld a,(hl) and &aa or &40 ld (hl),a inc hl ld (hl),&c0 inc hl ld a,(hl) and &55 or &80 ld (hl),a inc hl inc hl inc hl ld a,(hl) and &aa ld (hl),a inc hl ld (hl),&c0 pop hl call scr_next_line push hl ld a,(hl) and &aa or &40 ld (hl),a inc hl ld (hl),&c0 inc hl ld a,(hl) and &55 or &80 ld (hl),a inc hl inc hl inc hl ld a,(hl) and &aa ld (hl),a inc hl ld (hl),&c0 pop hl call scr_next_line push hl ld a,(hl) and &aa or &40 ld (hl),a inc hl ld (hl),&c0 inc hl ld a,(hl) and &55 or &80 ld (hl),a inc hl inc hl inc hl ld a,(hl) and &aa ld (hl),a inc hl ld (hl),&c0 pop hl call scr_next_line push hl ld a,(hl) and &aa or &40 ld (hl),a inc hl ld (hl),&c0 inc hl ld a,(hl) and &55 or &80 ld (hl),a inc hl inc hl inc hl ld a,(hl) and &aa ld (hl),a inc hl ld (hl),&c0 pop hl call scr_next_line push hl ld a,(hl) and &aa or &40 ld (hl),a inc hl ld (hl),&c0 inc hl ld (hl),&c0 inc hl ld (hl),&c0 inc hl ld (hl),&c0 inc hl ld (hl),&c0 pop hl call scr_next_line push hl ld a,(hl) and &aa or &40 ld (hl),a inc hl ld (hl),&c0 inc hl ld (hl),&c0 inc hl ld (hl),&c0 inc hl ld (hl),&c0 pop hl call scr_next_line push hl ld a,(hl) and &aa or &40 ld (hl),a inc hl ld (hl),&c0 inc hl ld a,(hl) and &55 or &80 ld (hl),a pop hl call scr_next_line push hl ld a,(hl) and &aa or &40 ld (hl),a inc hl ld (hl),&c0 inc hl ld a,(hl) and &55 or &80 ld (hl),a pop hl call scr_next_line push hl ld a,(hl) and &aa or &40 ld (hl),a inc hl ld (hl),&c0 inc hl ld a,(hl) and &55 or &80 ld (hl),a pop hl call scr_next_line push hl ld a,(hl) and &aa or &40 ld (hl),a inc hl ld (hl),&c0 inc hl ld a,(hl) and &55 or &80 ld (hl),a pop hl call scr_next_line push hl ld a,(hl) and &aa or &40 ld (hl),a inc hl ld (hl),&c0 inc hl ld a,(hl) and &55 or &80 ld (hl),a pop hl call scr_next_line ld a,(hl) and &aa or &40 ld (hl),a inc hl ld (hl),&c0 inc hl ld a,(hl) and &55 or &80 ld (hl),a ret ;;-------------------------------------------------------------------------------------------------------------------------------- ;; drawing function for sprite 2 sprite_2: push hl inc hl ld a,(hl) and &aa ld (hl),a inc hl ld (hl),&0c inc hl ld (hl),&0c inc hl ld (hl),&0c pop hl call scr_next_line push hl inc hl ld (hl),&0c inc hl ld (hl),&0c inc hl ld (hl),&0c inc hl ld (hl),&0c pop hl call scr_next_line push hl ld a,(hl) and &aa or &04 ld (hl),a inc hl ld (hl),&0c inc hl ld a,(hl) and &55 or &08 ld (hl),a inc hl inc hl inc hl ld a,(hl) and &aa ld (hl),a inc hl ld (hl),&0c pop hl call scr_next_line push hl ld a,(hl) and &aa or &04 ld (hl),a inc hl ld (hl),&0c inc hl ld a,(hl) and &55 or &08 ld (hl),a inc hl inc hl inc hl ld a,(hl) and &aa ld (hl),a inc hl ld (hl),&0c pop hl call scr_next_line push hl ld a,(hl) and &aa or &04 ld (hl),a inc hl ld (hl),&0c inc hl ld a,(hl) and &55 or &08 ld (hl),a pop hl call scr_next_line push hl ld a,(hl) and &aa or &04 ld (hl),a inc hl ld (hl),&0c inc hl ld a,(hl) and &55 or &08 ld (hl),a pop hl call scr_next_line push hl ld a,(hl) and &aa or &04 ld (hl),a inc hl ld (hl),&0c inc hl ld a,(hl) and &55 or &08 ld (hl),a pop hl call scr_next_line push hl ld a,(hl) and &aa or &04 ld (hl),a inc hl ld (hl),&0c inc hl ld a,(hl) and &55 or &08 ld (hl),a pop hl call scr_next_line push hl ld a,(hl) and &aa or &04 ld (hl),a inc hl ld (hl),&0c inc hl ld a,(hl) and &55 or &08 ld (hl),a pop hl call scr_next_line push hl ld a,(hl) and &aa or &04 ld (hl),a inc hl ld (hl),&0c inc hl ld a,(hl) and &55 or &08 ld (hl),a pop hl call scr_next_line push hl ld a,(hl) and &aa or &04 ld (hl),a inc hl ld (hl),&0c inc hl ld a,(hl) and &55 or &08 ld (hl),a pop hl call scr_next_line push hl ld a,(hl) and &aa or &04 ld (hl),a inc hl ld (hl),&0c inc hl ld a,(hl) and &55 or &08 ld (hl),a pop hl call scr_next_line push hl ld a,(hl) and &aa or &04 ld (hl),a inc hl ld (hl),&0c inc hl ld a,(hl) and &55 or &08 ld (hl),a inc hl inc hl inc hl ld a,(hl) and &aa ld (hl),a inc hl ld (hl),&0c pop hl call scr_next_line push hl ld a,(hl) and &aa or &04 ld (hl),a inc hl ld (hl),&0c inc hl ld a,(hl) and &55 or &08 ld (hl),a inc hl inc hl inc hl ld a,(hl) and &aa ld (hl),a inc hl ld (hl),&0c pop hl call scr_next_line push hl inc hl ld (hl),&0c inc hl ld (hl),&0c inc hl ld (hl),&0c inc hl ld (hl),&0c inc hl ld a,(hl) and &55 or &08 ld (hl),a pop hl call scr_next_line inc hl ld (hl),&0c inc hl ld (hl),&0c inc hl ld (hl),&0c inc hl ld a,(hl) and &55 or &08 ld (hl),a ret ;;-------------------------------------------------------------------------------------------------------------------------------- ;; a buffer to store screen behind sprite sprite_background: defs sprite_height*sprite_width_bytes prev_coords: prev_y_coord: defb 0 prev_x_coord: defb 0 sprite_coords: y_coord: defb 0 x_coord: defb 0 ;; make this executable for pasmo, uncomment for pasmo assembler end start