I have some untested code that prepares objects for drawing (find eligible candidates, sort by distance). If it works correctly, then all you need is to implement the rendering code which should be straight-forward.
Code:
Also, I am assuming you already have a sine table of the first 64 elements
Code:
ld hl,obj_array
call seive_sort
call render
;<<code>>
ret
seive:
;save our obj_array pointer
;start index at -1
ld (obj_array_ptr),hl
ld a,-1
ld (obj_index),a
push af
pop af
;now we loop through the array
seive_loop:
;our obj_array (array of objects) needs to be scanned and sorted
;the first thing is to update our index
ld hl,obj_index
inc (hl)
ld hl,(obj_array_ptr)
;Get the first byte of the object's code
;If it is 0xFF, then the object array is finished and we move on to sorting
ld a,(hl)
inc a
jp z,sort
inc hl
;Now we get the coordinates of the object relative to the map
ld e,(hl)
inc hl
ld d,(hl)
inc hl
ld (obj_array_ptr),hl
;Now we need to get the coordinates relative to the player
ld hl,(player_coords) ;y,x
ld a,e
sub l
ld e,a
ld a,d
sub h
ld d,a
;Now we rotate based on the player's view angle
call rotate_de
;If the adjusted y-coordinate is negative, this is behind the player
ld a,e
or a
jp m,seive_loop
;Now we check the the x-coordinates. This is a bit complicated:
; If the x-coordinate is 0, it is directly ahead of the player, so draw it
; --Side Note--
; The player view angle can be drawn using the graphs of y=4x, y=-4x.
; This is almost exactly 10 binary degrees, but much easier to compute
; To check if an object is in view, if x is negative, we draw a line of slope
; -4x from the point to locate the x intercept. If this is greater than zero, it fits
; For positive x, we find the x intercept of the line of slope 4x passing through the point
; If this is negative, we are good to go!
; Doing the math, we need 4x+y<=0 for negative x, 4x-y<=0 for positive x
ld a,d ;x-coord, we need it multiplied by 4, so mul by 2 gives us the sign, too!
add a,a
jr nz,$+7
ld d,48
jp accept
push af ;save this for later
jr nc,$+4
neg
add a,a
jr c,seive_loop-1
sub e
neg
jp m,seive_loop-1
;so now we know object is in range
;What we want to do know is figure out the x-coordinate to display the object
;Basically, if we take a horizontal slice of the view range that intercepts the object
;we need how far the object is from the edge divided by total width of the view range
;then we multiply by the screen width (96)
;
;We did the "push af" before to capture whether or not it was in the left of the view range
;or not. this just means we need to do 1-dist_from_edge/total_dist
;Total distance is 2*y/4 = y/2, so we need to perform 96*x/(y/2) = 96*(2x/y)
;This algorithm is hackadasical (<--- made up word), but it relies on the fact that
;2x<y<128 which is always true
;a=4x, e=y
ld d,o \ sub e \ jr nc,$+3 \ add a,e \ rl d
add a,a \ sub e \ jr nc,$+3 \ add a,e \ rl d
add a,a \ sub e \ jr nc,$+3 \ add a,e \ rl d
add a,a \ sub e \ jr nc,$+3 \ add a,e \ rl d
add a,a \ sub e \ jr nc,$+3 \ add a,e \ rl d
add a,a \ sub e
ld a,d
cpl
ld d,a
ccf
rla
add a,d
ld d,a
pop af
jr nc,$+6
ld a,96
sub d
ld d,a
;now we need to write our un-adjusted y, adjusted x, and obj_index to the sort buffer
accept:
ld hl,sort_buf
inc (hl)
ld hl,(sort_buf_write)
ld (hl),e
inc hl
ld (hl),d
inc hl
ld a,(obj_index)
ld (hl),a
jp seive_loop
sort:
;;Use merge-sort
;;data is .db y,x,index
;;sort descending by y
;;Up to 56 objects
;;
;;Outputs: A as the number of objects to draw
;; HL points to the first object
ld bc,$0101
sort_loop:
ld hl,sort_buf
ld a,(hl)
inc hl
cp b
ret nc
sort_loop1:
push bc
sub b
jr nc,$+8
add a,b
ld b,a
xor a
jr c,$+7
sub c
jr nc,$+5
add a,c
ld c,a
xor a
push af
ld a,b
add a,l
ld e,a
ld a,h
adc a,0
ld d,a
call merge_sorted
pop af
pop bc
or a
jr nz,sort_loop1
sla b
ld c,b
jp sort_loop
merge_sorted:
;;Inputs:
;; HL points to one sorted list
;; DE points to another sorted list
;; B is the size of the first list, non zero
;; C is the size of the second list
;;Outputs:
;; The list is merged and sorted, and written back
;; HL points to the next set of sublists
ld a,c
or a
ret z
ld ix,sort_buf+1+3*56
push bc
push hl
merge_and_sort_loop:
ld a,(de)
cp (hl)
jr c,copy_list2
ld a,(hl)
ld (ix),a
inc hl
inc ix
ld a,(hl)
ld (ix),a
inc hl
inc ix
ld a,(hl)
ld (ix),a
inc hl
inc ix
djnz merge_and_sort_loop
;copy the rest of the second list
;actually we will just cheat and write back our current data
;No use in copying the second list just to copy back
push ix
pop hl
ld de,sort_buf+1+3*56
ld a,c
or a
sbc hl,de
ld b,h
ld c,l
pop hl
ex de,hl
ldir
ld c,a
ex de,hl
add hl,bc
pop bc
ret
copy_list2:
ld a,(de)
ld (ix),a
inc de
inc ix
ld a,(de)
ld (ix),a
inc de
inc ix
ld a,(de)
ld (ix),a
inc de
inc ix
dec c
jr nz,merge_and_sort_loop
;now we copy the rest of the first list
push ix
pop de
ld a,b
add a,a
add a,b
ld c,a
ld b,0
ldir
pop de
pop bc
ld a,b
add a,c
ld c,a
ld b,0
add a,a
add a,c
ld c,a
ld hl,sort_buf+1+3*56
ldir
ex de,hl
ret
render:
;;Inputs: A is the number of objects to draw, HL points to the first object
;;Destroys: Assume all
;;Notes:
;; Objects are stored as (y,x,index)
;; Y needs to be adjusted for drawing
;; X is already adjusted
;; "index" refers to the object's index into the list of objects
;; This needs to be used to retrieve the rest of the object information
ret
rotate_de:
;d = x
;e = y
;-(player_angle) is the amount by which to rotate
;
ld a,(player_angle)
neg
; x = x*cos - y*sin
; y = x*sin + y*cos
;get cos(a), sin(a)
;note cos(a) = sin(a-64)
ld c,a
add a,a
xor c
ld a,c
jp p,$+5
neg
and %00111111
ld hl,sine_table
add a,l
ld l,a
jr nc,$+3
inc h
ld a,(hl)
bit 7,c
jr z,$+4
neg
ld b,a
ld a,c
add a,64
ld c,a
add a,a
xor c
ld a,c
jp p,$+5
neg
and %00111111
ld hl,sine_table
add a,l
ld l,a
jr nc,$+3
inc h
ld a,(hl)
bit 7,c
jr z,$+4
neg
ld b,a
;c is sine
;b is cosine
;d = x
;e = y
push de
;x*cos - y*sin
;d*b - e*c
;x*sin + y*cos
;d*c + e*b
ld a,b
ld e,d
call A_Times_E_signed
pop de
push de
push hl
ld a,c
call A_Times_E_signed
pop de
or a
sbc hl,de
ex (sp),hl
push hl
ld a,h
ld e,c
call A_Times_E_signed
pop de
ld a,b
ld b,h
ld c,l
call A_Times_E_signed
add hl,bc
pop de
ld a,e
add a,a
ld a,d
adc a,0
ld d,a
ld a,l
add a,a
ld a,h
adc a,0
ld e,a
ret
A_Times_E_signed:
;;Inputs: A,E
;;Outputs: HL
;;250+6b+34a
;;worst: 332cc
ld a,e
add a,a
sbc a,a
ld d,a
ld a,l
ld hl,0
rlca \ jr nc,$+5 \ ld l,e \ ld h,d
add hl,hl \ rlca \ jr nc,$+3 \ add hl,de
add hl,hl \ rlca \ jr nc,$+3 \ add hl,de
add hl,hl \ rlca \ jr nc,$+3 \ add hl,de
add hl,hl \ rlca \ jr nc,$+3 \ add hl,de
add hl,hl \ rlca \ jr nc,$+3 \ add hl,de
add hl,hl \ rlca \ jr nc,$+3 \ add hl,de
add hl,hl \ rlca \ jr nc,$+3 \ add hl,de
add a,a
ret nc
ld d,e
ld e,0
or a
sbc hl,de
ret
Also, I am assuming you already have a sine table of the first 64 elements