fennel-ray-casting/raycaster.fnl

210 lines
8.1 KiB
Text
Raw Normal View History

2024-10-10 18:17:16 +00:00
(local state (require :state))
(local mapper (require :mapper))
(local overlay (require :overlay))
(local pi math.pi)
; ### Screen Size ###
(var (screen-width screen-height) (love.window.getMode))
; ### Map Information ###
(var map (mapper.generate 15 15))
; (var map [[1 1 1 1 1 1 1 1 1 1 1 ]
; [2 0 0 0 0 0 0 0 0 0 4 ]
; [2 0 0 0 0 0 0 0 0 0 4 ]
; [2 0 0 0 0 0 0 0 0 0 4 ]
; [2 0 0 0 0 0 0 0 0 0 4 ]
; [2 0 0 0 0 0 0 0 0 0 4 ]
; [2 0 0 0 0 0 0 0 3 0 4 ]
; [2 0 0 0 0 0 0 3 3 0 4 ]
; [2 0 0 0 0 0 0 0 0 0 4 ]
; [1 1 1 1 1 1 1 1 1 1 1 ]])
; ### Texture Information ###
(var walls [])
(var wall-textures (love.filesystem.getDirectoryItems "textures/walls"))
(var (tex-height tex-width) (values 64 64))
(each [_ v (ipairs wall-textures)]
(local wall {})
(tset wall :t (love.graphics.newImage (.. "textures/walls/" v)))
(tset wall :w (love.graphics.getWidth (. wall :t)))
(tset wall :h (love.graphics.getHeight (. wall :t)))
(table.insert walls wall))
; ### "Player" variables ###
(var (posx posy) (values 4.0 4.0)) ; Initial map position
(var (dirx diry) (values -1.0 0.0)) ; Initial direction vector
2024-10-11 19:24:16 +00:00
(var (planex planey) (values 0 0.66)) ; Camera plane
2024-10-10 18:17:16 +00:00
{
:draw (fn love.draw []
(for [i 0 screen-width]
; Calculate ray position and direction
; Originals, giving a fish-eye lens effect:
; (var camerax (/ (* 2 i) (- screen-width 1)))
; (var (ray-dir-x ray-dir-y) (values (+ dirx (* planex camerax)) (+ diry (* planey camerax))))
2024-10-11 19:24:16 +00:00
(var camerax (- (/ (* 2 i) (- screen-width 1)) 1.0))
2024-10-10 18:17:16 +00:00
(var (ray-dir-x ray-dir-y) (values (+ dirx (* planex camerax)) (+ diry (* planey camerax))))
; Which map square we're in
(var (mapx mapy) (values (math.floor posx) (math.floor posy)))
; Length of ray from current position to next x or y side
(var (side-dist-x side-dist-y) (values 0 0))
; Length of ray from one x or y side to the next x or y side
; (var (delta-dist-x delta-dist-y) (values
; (math.sqrt (+ 1 (/ (* ray-dir-y ray-dir-y) (* ray-dir-x ray-dir-x))))
; (math.sqrt (+ 1 (/ (* ray-dir-x ray-dir-x) (* ray-dir-y ray-dir-y))))))
2024-10-11 19:24:16 +00:00
; (var (delta-dist-x delta-dist-y) (values
; (math.sqrt (+ 1 (* (/ ray-dir-y ray-dir-x) (/ ray-dir-y ray-dir-x))))
; (math.sqrt (+ 1 (* (/ ray-dir-x ray-dir-y) (/ ray-dir-x ray-dir-y))))))
2024-10-10 18:17:16 +00:00
(var (delta-dist-x delta-dist-y) (values (math.abs (/ 1 ray-dir-x)) (math.abs (/ 1 ray-dir-y))))
(var perp-wall-dist 0)
; Direction to step in, x or y
(var (stepx stepy) (values 0 0))
; Side the ray hits, x (0) or y (1)
(var side 0)
; Calculate step and initial side-dist-*
(if (< ray-dir-x 0)
(do
(set stepx -1)
(set side-dist-x (* (- posx mapx) delta-dist-x)))
(do
(set stepx 1)
(set side-dist-x (* (- (+ mapx 1.0) posx) delta-dist-x))))
(if (< ray-dir-y 0)
(do
(set stepy -1)
(set side-dist-y (* (- posy mapy) delta-dist-y)))
(do
(set stepy 1)
(set side-dist-y (* (- (+ mapy 1.0) posy) delta-dist-y))))
; Perform DDA (Digital Differential Analysis)
(var hit false)
(while (not hit)
(if (< side-dist-x side-dist-y)
(do
(set side-dist-x (+ side-dist-x delta-dist-x))
(set mapx (+ mapx stepx))
(set side 0))
(do
(set side-dist-y (+ side-dist-y delta-dist-y))
(set mapy (+ mapy stepy))
(set side 1)))
(if (> (. map mapx mapy) 0) (set hit true)))
; Calculate distance of perpendicular ray, to avoid fisheye effect
(if (= side 0)
(set perp-wall-dist (- side-dist-x delta-dist-x))
(set perp-wall-dist (- side-dist-y delta-dist-y)))
; Calculate height of line to draw on screen
(var line-height (/ screen-height perp-wall-dist))
; Calculate lowest and highest pixel to fill in current stripe
(var draw-start (+ (/ (- line-height) 2) (/ screen-height 2)))
(if (< draw-start 0) (set draw-start 0))
(var draw-end (+ (/ line-height 2) (/ screen-height 2)))
(if (>= draw-end screen-height) (set draw-end (- screen-height 1)))
; Draw wall slice
; (var color [1 1 1 1])
; (case (. map mapx mapy)
; 1 (set color [1 1 1 1])
; 2 (set color [1 0 0 1])
; 3 (set color [0 1 0 1])
; 4 (set color [0 0 1 1])
; )
; (when (= side 1)
; (tset color 1 (/ (. color 1) 2))
; (tset color 2 (/ (. color 2) 2))
; (tset color 3 (/ (. color 3) 2)))
; (love.graphics.setColor color)
; (love.graphics.line i draw-start i draw-end)
; (love.graphics.setColor 1 1 1)
; Draw textured wall
;; Choose texture
(var tex-num (. walls (. map mapx mapy)))
;; Calculate exactly where the wall was hit
(var wallx 0)
(if (= side 0)
(set wallx (+ posy (* perp-wall-dist ray-dir-y)))
(set wallx (+ posx (* perp-wall-dist ray-dir-x))))
(set wallx (- wallx (math.floor wallx)))
;; Find the x-coordinate on the texture
(var tex-x (math.floor (* wallx (. tex-num :w))))
(if (and (= side 0) (> ray-dir-x 0)) (set tex-x (- (. tex-num :w) tex-x 1)))
(if (and (= side 1) (< ray-dir-y 0)) (set tex-x (- (. tex-num :w) tex-x 1)))
;; Draw the texture
(love.graphics.draw (. tex-num :t)
(love.graphics.newQuad tex-x 0 1 (. tex-num :h) (. tex-num :w) (. tex-num :h))
i draw-start 0 1 (/ line-height (. tex-num :h)))
)
(overlay.overlay)
)
:update (fn update [dt]
(var mvspeed (* dt 3.0))
(var rtspeed (* dt 1.0))
(when (love.keyboard.isDown "up")
(when (= 0 (. map (math.floor (+ (* mvspeed dirx) posx)) (math.floor posy)))
(set posx (+ (* mvspeed dirx) posx)))
(when (= 0 (. map (math.floor posx) (math.floor (+ (* mvspeed diry) posy))))
(set posy (+ (* mvspeed diry) posy)))
)
(when (love.keyboard.isDown "down")
(when (= 0 (. map (math.floor (+ (* mvspeed dirx) posx)) (math.floor posy)))
(set posx (- posx (* mvspeed dirx))))
(when (= 0 (. map (math.floor posx) (math.floor (+ (* mvspeed diry) posy))))
(set posy (- posy (* mvspeed diry))))
)
(when (love.keyboard.isDown "right")
(var old-dirx dirx)
(set dirx (- (* dirx (math.cos (- rtspeed))) (* diry (math.sin (- rtspeed)))))
(set diry (+ (* old-dirx (math.sin (- rtspeed))) (* diry (math.cos (- rtspeed)))))
(var old-planex planex)
(set planex (- (* planex (math.cos (- rtspeed))) (* planey (math.sin (- rtspeed)))))
(set planey (+ (* old-planex (math.sin (- rtspeed))) (* planey (math.cos (- rtspeed)))))
)
(when (love.keyboard.isDown "left")
(var old-dirx dirx)
(set dirx (- (* dirx (math.cos rtspeed)) (* diry (math.sin rtspeed))))
(set diry (+ (* old-dirx (math.sin rtspeed)) (* diry (math.cos rtspeed))))
(var old-planex planex)
(set planex (- (* planex (math.cos rtspeed)) (* planey (math.sin rtspeed))))
(set planey (+ (* old-planex (math.sin rtspeed)) (* planey (math.cos rtspeed))))
)
)
:keypressed (fn keypressed [k]
(when (= k "x") (love.event.quit))
)
}
; (fn move-player [x]
; (let [new-x (+ posx (* (math.cos dirx)) x) new-y (+ posy (* (math.sin diry)) x)]
; (when (= (. map (math.floor new-y) (math.floor new-x)) 0)
; (set posx new-x) (set posy new-y))))
; (fn rotate-player [d]
; (local rotation-speed 1)
; (var old-dirx dirx)
; (set dirx (- (* dirx (math.cos (* d rotation-speed))) (* diry (math.sin (* d rotation-speed)))))
; (set diry (+ (* old-dirx (math.sin (* d rotation-speed))) (* diry (math.cos (* d rotation-speed)))))
; (var old-planex planex)
; (set planex (- (* planex (math.cos (* d rotation-speed))) (* planey (math.sin (* d rotation-speed)))))
; (set planey (+ (* old-planex (math.sin (* d rotation-speed))) (* planey (math.cos (* d rotation-speed))))))