301 lines
12 KiB
Fennel
301 lines
12 KiB
Fennel
(local state (require :state))
|
|
(local mapper (require :mapper))
|
|
(local overlay (require :overlay))
|
|
(local pi math.pi)
|
|
(var count-down true)
|
|
; ### Screen Size ###
|
|
(var (screen-width screen-height) (love.window.getMode))
|
|
(love.mouse.setGrabbed true)
|
|
(love.mouse.setRelativeMode true)
|
|
|
|
; ### Map Information ###
|
|
(var (map spawn) (mapper.generate))
|
|
|
|
; ### Texture Information ###
|
|
(var walls [])
|
|
(var wall-textures (love.filesystem.getDirectoryItems "assets/textures/walls"))
|
|
(var (tex-height tex-width) (values 64 64))
|
|
|
|
(var skybox [])
|
|
(var skybox-textures (love.filesystem.getDirectoryItems "assets/textures/skybox"))
|
|
|
|
(each [_ v (ipairs wall-textures)]
|
|
(local wall {})
|
|
(tset wall :t (love.graphics.newImage (.. "assets/textures/walls/" v)))
|
|
(tset wall :w (love.graphics.getWidth (. wall :t)))
|
|
(tset wall :h (love.graphics.getHeight (. wall :t)))
|
|
(table.insert walls wall))
|
|
|
|
(each [_ v (ipairs skybox-textures)]
|
|
(local skyb {})
|
|
(tset skyb :t (love.graphics.newImage (.. "assets/textures/skybox/" v)))
|
|
(tset skyb :w (love.graphics.getWidth (. skyb :t)))
|
|
(tset skyb :h (love.graphics.getHeight (. skyb :t)))
|
|
(table.insert skybox skyb))
|
|
|
|
; ### "Player" variables ###
|
|
(var (posx posy) (values (+ (. spawn :x) 0.5) (+ (. spawn :y) 0.5)))
|
|
(var (dirx diry) (values -1.0 0.0)) ; Initial direction vector
|
|
(var (planex planey) (values 0 0.66)) ; Camera plane
|
|
|
|
; ### Offset experimentation ###
|
|
(var (offst-x offst-y) (values 0 0))
|
|
|
|
{
|
|
:draw (fn love.draw []
|
|
(state.setDirX dirx)
|
|
(state.setDirY diry)
|
|
; Mouse-Look
|
|
(love.graphics.translate offst-x offst-y)
|
|
|
|
; "Skybox"
|
|
; Draw a big thing before everything else
|
|
; (love.graphics.draw (. skybox 1 :t) -20 -20)
|
|
|
|
; CEILING/FLOOR CASTING
|
|
(var cf-f-tex-num (. walls 2))
|
|
(var cf-c-tex-num (. walls 2))
|
|
; (var floor-texel (love.graphics.newQuad 0 0 1 1 (. cf-f-tex-num :w) (. cf-f-tex-num :h)))
|
|
(for [i (/ screen-height 2) screen-height]
|
|
; Set ray-dir for left-most (i = 0) and right-most (i = screen-width) rays
|
|
(var (cf-ray-dir-x0 cf-ray-dir-y0) (values (- dirx planex) (- diry planey)))
|
|
(var (cf-ray-dir-x1 cf-ray-dir-y1) (values (+ dirx planex) (+ diry planey)))
|
|
|
|
; Current y position compared to horizon
|
|
(var cf-p (math.floor (/ (- i screen-height) 2)))
|
|
|
|
; Vertical position of the camera
|
|
(var cf-pos-z (* 0.5 screen-height))
|
|
|
|
; Horizontal distance from camera to floor for current row
|
|
(var cf-row-distance (/ cf-pos-z cf-p))
|
|
|
|
; Calculate step vectors
|
|
(var cf-floor-step-x (/ (* cf-row-distance (- cf-ray-dir-x1 cf-ray-dir-x0)) screen-width))
|
|
(var cf-floor-step-y (/ (* cf-row-distance (- cf-ray-dir-y1 cf-ray-dir-y0)) screen-width))
|
|
|
|
; Coordinates of left-most column, updated stepping to the right
|
|
(var (cf-floor-x cf-floor-y) (values (+ posx (* cf-row-distance cf-ray-dir-x0))
|
|
(+ posy (* cf-row-distance cf-ray-dir-y0))))
|
|
|
|
; Draw floor and ceiling
|
|
(for [j 0 screen-width]
|
|
; Get cell
|
|
(var (cf-cell-x cf-cell-y) (values (math.floor cf-floor-x) (math.floor cf-floor-y)))
|
|
|
|
; Get texture coordinate from fractional part
|
|
; CPP Code: wtf is the & doing there?
|
|
; (var (cf-tx cf-ty) (values (math.floor (% (* tex-width (- cf-floor-x cf-cell-x)) tex-width))
|
|
; (math.floor (% (* tex-height (- cf-floor-y cf-cell-y)) tex-height))))
|
|
(var (cf-tx cf-ty) (values (math.floor (* tex-width (- cf-floor-x cf-cell-x)))
|
|
(math.floor (* tex-height (- cf-floor-y cf-cell-y)))))
|
|
|
|
;; Draw the texture
|
|
; (var tex-num cf-f-tex-num)
|
|
; (love.graphics.draw (. tex-num :t)
|
|
; (love.graphics.newQuad cf-tx 0 1 (. tex-num :h) (. tex-num :w) (. tex-num :h))
|
|
; i cf-ty 0 1 (/ line-height (. tex-num :h)))
|
|
; (love.graphics.draw (. cf-f-tex-num :t)
|
|
; floor-texel
|
|
; j i 0 1 1)
|
|
|
|
; Step
|
|
(set cf-floor-x (+ cf-floor-x cf-floor-step-x))
|
|
(set cf-floor-y (+ cf-floor-y cf-floor-step-y))
|
|
)
|
|
)
|
|
; WALL CASTING
|
|
(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))))
|
|
(var camerax (- (/ (* 2 i) (- screen-width 1)) 1.0))
|
|
(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))))))
|
|
; (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))))))
|
|
(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 textured wall
|
|
;; Choose texture
|
|
; (var tex-num (. walls (. map mapx mapy)))
|
|
(var tex-num (. walls (math.floor (/ (. map mapx mapy) 10))))
|
|
;; 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, accounting for "fog"
|
|
(var fog-dist (- 1 (/ perp-wall-dist 10)))
|
|
(var light-dist (- 0.8 (/ perp-wall-dist 5)))
|
|
(love.graphics.setColor light-dist light-dist light-dist fog-dist)
|
|
; (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)))
|
|
; (when (= (. map mapx mapy) 3)
|
|
(for [q 0 (% (. map mapx mapy) 10)]
|
|
(set fog-dist (- fog-dist 0.1))
|
|
(set light-dist (- light-dist 0.1))
|
|
(love.graphics.setColor light-dist light-dist light-dist fog-dist)
|
|
(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 (* line-height q)) 0 1 (/ line-height (. tex-num :h)))
|
|
)
|
|
; )
|
|
)
|
|
(overlay.overlay offst-x offst-y)
|
|
)
|
|
|
|
:update (fn update [dt]
|
|
(var mvspeed (* dt 3.0))
|
|
(var rtspeed (* dt 1.0))
|
|
|
|
(when (love.keyboard.isDown "e")
|
|
(when (= 0 (. map (math.floor (+ (* mvspeed dirx) posx)) (math.floor posy)))
|
|
(set posx (+ (* mvspeed dirx) posx))
|
|
(state.modDis mvspeed))
|
|
(when (= 0 (. map (math.floor posx) (math.floor (+ (* mvspeed diry) posy))))
|
|
(set posy (+ (* mvspeed diry) posy))
|
|
(state.modDis mvspeed))
|
|
)
|
|
|
|
(when (love.keyboard.isDown "d")
|
|
(when (= 0 (. map (math.floor (- posx (* mvspeed dirx))) (math.floor posy)))
|
|
(set posx (- posx (* mvspeed dirx)))
|
|
(state.modDis mvspeed))
|
|
(when (= 0 (. map (math.floor posx) (math.floor (- posy (* mvspeed diry)))))
|
|
(set posy (- posy (* mvspeed diry)))
|
|
(state.modDis mvspeed))
|
|
)
|
|
|
|
(when (love.keyboard.isDown "f")
|
|
(when (= 0 (. map (math.floor (+ (* mvspeed planex) posx)) (math.floor posy)))
|
|
(set posx (+ (* mvspeed planex) posx))
|
|
(state.modDis mvspeed))
|
|
(when (= 0 (. map (math.floor posx) (math.floor (+ (* mvspeed planey) posy))))
|
|
(set posy (+ (* mvspeed planey) posy))
|
|
(state.modDis mvspeed))
|
|
)
|
|
|
|
(when (love.keyboard.isDown "s")
|
|
(when (= 0 (. map (math.floor (- posx (* mvspeed planex))) (math.floor posy)))
|
|
(set posx (- posx (* mvspeed planex)))
|
|
(state.modDis mvspeed))
|
|
(when (= 0 (. map (math.floor posx) (math.floor (- posy (* mvspeed planey)))))
|
|
(set posy (- posy (* mvspeed planey)))
|
|
(state.modDis mvspeed))
|
|
)
|
|
|
|
(when (love.keyboard.isDown "r")
|
|
(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 "w")
|
|
(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))))
|
|
)
|
|
|
|
(if (= 0 (% (+ 1 (math.floor (state.getDis))) 10))
|
|
(when count-down
|
|
(set count-down false)
|
|
(state.modO -1))
|
|
(set count-down true))
|
|
)
|
|
|
|
:mousemoved (fn mousemoved [x y dx dy]
|
|
(var rtspeed (* dx -0.001))
|
|
(var yawspeed (* dy -0.5))
|
|
|
|
(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))))
|
|
|
|
(set offst-y (+ offst-y yawspeed))
|
|
)
|
|
|
|
:keypressed (fn keypressed [k]
|
|
(when (= k "o") (state.modO -1))
|
|
(when (= k "x") (love.event.quit))
|
|
)
|
|
}
|