(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 (var (planex planey) (values 0 0.80)) ; Camera plane { :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)))) (var camerax (/ (* 2 i) (- screen-width 1))) (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.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))))))