(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 2 1 1 1 1 2 1 1 1 ] [1 0 0 0 0 0 0 0 0 0 1 ] [1 0 0 0 0 0 0 0 0 0 2 ] [2 0 0 0 0 0 0 0 0 0 2 ] [1 0 0 0 0 0 0 0 0 0 1 ] [1 0 0 0 0 0 0 0 0 0 1 ] [1 0 0 0 0 0 0 0 3 0 1 ] [1 0 0 0 0 0 0 3 3 0 1 ] [1 1 1 1 1 1 0 0 0 0 1 ] [1 0 0 0 0 0 0 1 1 1 1 ] [1 0 1 1 1 1 1 1 1 1 1 ] [1 0 1 1 1 1 0 0 0 0 1 ] [1 0 1 1 1 1 1 1 1 0 1 ] [1 0 0 0 0 0 0 0 0 0 1 ] [1 1 1 1 1 1 1 1 1 1 1 ]]) ; ### 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 4.0 4.0)) ; Initial map position (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 [] ; 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 7)) ; (var cf-c-tex-num (. walls 6)) ; (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 ; ; (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))) ; ; (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))) ;; 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 7))) (love.graphics.setColor 1 1 1 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 1 3] (set fog-dist (- fog-dist 0.1)) (love.graphics.setColor 1 1 1 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))) (when (= 0 (. map (math.floor posx) (math.floor (+ (* mvspeed diry) posy)))) (set posy (+ (* mvspeed diry) posy))) ) (when (love.keyboard.isDown "d") (when (= 0 (. map (math.floor (- posx (* mvspeed dirx))) (math.floor posy))) (set posx (- posx (* mvspeed dirx)))) (when (= 0 (. map (math.floor posx) (math.floor (- posy (* mvspeed diry))))) (set posy (- posy (* mvspeed diry)))) ) (when (love.keyboard.isDown "f") (when (= 0 (. map (math.floor (+ (* mvspeed planex) posx)) (math.floor posy))) (set posx (+ (* mvspeed planex) posx))) (when (= 0 (. map (math.floor posx) (math.floor (+ (* mvspeed planey) posy)))) (set posy (+ (* mvspeed planey) posy))) ) (when (love.keyboard.isDown "s") (when (= 0 (. map (math.floor (- posx (* mvspeed planex))) (math.floor posy))) (set posx (- posx (* mvspeed planex)))) (when (= 0 (. map (math.floor posx) (math.floor (- posy (* mvspeed planey))))) (set posy (- posy (* mvspeed planey)))) ) ; (when (love.keyboard.isDown "s") ; (var strafe-x (- (* dirx (math.cos (- (/ math.pi 2)))) (* diry (math.sin (- (/ math.pi 2)))))) ; (var strafe-y (+ (* dirx (math.sin (- (/ math.pi 2)))) (* diry (math.cos (- (/ math.pi 2)))))) ; (when (= 0 (. map (math.floor (- posx (* mvspeed strafe-x))) (math.floor posy))) ; (set posx (- posx (* mvspeed strafe-x)))) ; (when (= 0 (. map (math.floor posx) (math.floor (- posy (* mvspeed strafe-y))))) ; (set posy (- posy (* mvspeed strafe-y)))) ; ) ; (when (love.keyboard.isDown "f") ; (var strafe-x (- (* dirx (math.cos (+ (/ math.pi 2)))) (* diry (math.sin (+ (/ math.pi 2)))))) ; (var strafe-y (+ (* dirx (math.sin (+ (/ math.pi 2)))) (* diry (math.cos (+ (/ math.pi 2)))))) ; (when (= 0 (. map (math.floor (- posx (* mvspeed strafe-x))) (math.floor posy))) ; (set posx (- posx (* mvspeed strafe-x)))) ; (when (= 0 (. map (math.floor posx) (math.floor (- posy (* mvspeed strafe-y))))) ; (set posy (- posy (* mvspeed strafe-y)))) ; ) (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)))) ) ) :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 "x") (love.event.quit)) ) }