(local pxl8 (require :pxl8)) (local debug-ui (require :mod.debug_ui)) (var world nil) (var cam-x 512) (var cam-y 64) (var cam-z 512) (var cam-yaw 0) (var cam-pitch 0) (var bob-time 0) (var show-debug-ui false) (var affine false) (var fps 0) (var fps-accumulator 0) (var fps-frame-count 0) (local move-speed 200) (local turn-speed 2.0) (local bob-speed 8.0) (local bob-amount 4.0) (fn init [] (set world (pxl8.world_new)) (let [result (pxl8.world_generate world { :type pxl8.PROCGEN_CAVE :width 16 :height 16 :seed 42 :density 0.45 :iterations 4})] (if (< result 0) (pxl8.error (.. "Failed to generate cave - result: " result)) (pxl8.info "Generated procedural cave")))) (fn update [dt] (let [clamped-dt (math.min dt 0.1)] (when (> dt 0.05) (pxl8.debug (.. "Large dt: " (string.format "%.3f" dt) "s"))) (set fps-accumulator (+ fps-accumulator clamped-dt)) (set fps-frame-count (+ fps-frame-count 1)) (when (>= fps-accumulator 0.25) (set fps (/ fps-frame-count fps-accumulator)) (set fps-accumulator 0) (set fps-frame-count 0)) (when (pxl8.key_pressed "F8") (set show-debug-ui (not show-debug-ui)) (pxl8.ui_window_set_open "Debug Menu (F8)" show-debug-ui)) (when (pxl8.world_is_loaded world) (let [forward-x (- (math.sin cam-yaw)) forward-z (- (math.cos cam-yaw)) right-x (math.cos cam-yaw) right-z (- (math.sin cam-yaw)) cell-size 64 grid-min 0 grid-max (* 16 cell-size)] (var moving false) (var new-x cam-x) (var new-z cam-z) (when (pxl8.key_down "w") (set new-x (+ new-x (* forward-x move-speed clamped-dt))) (set new-z (+ new-z (* forward-z move-speed clamped-dt))) (set moving true)) (when (pxl8.key_down "s") (set new-x (- new-x (* forward-x move-speed clamped-dt))) (set new-z (- new-z (* forward-z move-speed clamped-dt))) (set moving true)) (when (pxl8.key_down "q") (set new-x (- new-x (* right-x move-speed clamped-dt))) (set new-z (- new-z (* right-z move-speed clamped-dt))) (set moving true)) (when (pxl8.key_down "e") (set new-x (+ new-x (* right-x move-speed clamped-dt))) (set new-z (+ new-z (* right-z move-speed clamped-dt))) (set moving true)) (when (and (>= new-x grid-min) (<= new-x grid-max) (>= new-z grid-min) (<= new-z grid-max)) (set cam-x new-x) (set cam-z new-z)) (when (or (pxl8.key_down "left") (pxl8.key_down "a")) (set cam-yaw (+ cam-yaw (* turn-speed clamped-dt)))) (when (or (pxl8.key_down "right") (pxl8.key_down "d")) (set cam-yaw (- cam-yaw (* turn-speed clamped-dt)))) (when (pxl8.key_down "up") (set cam-pitch (+ cam-pitch (* turn-speed clamped-dt))) (when (> cam-pitch 1.5) (set cam-pitch 1.5))) (when (pxl8.key_down "down") (set cam-pitch (- cam-pitch (* turn-speed clamped-dt))) (when (< cam-pitch -1.5) (set cam-pitch -1.5))) (if moving (set bob-time (+ bob-time (* clamped-dt bob-speed))) (let [target-phase (* (math.floor (/ bob-time math.pi)) math.pi)] (set bob-time (+ (* bob-time 0.8) (* target-phase 0.2))))))))) (fn frame [] (pxl8.clr 0) (when (pxl8.world_is_loaded world) (let [bob-offset (* (math.sin bob-time) bob-amount) eye-y (+ cam-y bob-offset) forward-x (- (math.sin cam-yaw)) forward-z (- (math.cos cam-yaw)) target-x (+ cam-x forward-x) target-y (+ eye-y (math.sin cam-pitch)) target-z (+ cam-z forward-z)] (pxl8.text (.. "Pos: " (string.format "%.0f" cam-x) "," (string.format "%.0f" cam-y) "," (string.format "%.0f" cam-z)) 10 25 12) (pxl8.clear_zbuffer) (pxl8.set_backface_culling true) (pxl8.set_wireframe false) (let [aspect (/ (pxl8.get_width) (pxl8.get_height)) fov 1.047] (pxl8.set_projection (pxl8.mat4_perspective fov aspect 1.0 4096.0))) (pxl8.set_view (pxl8.mat4_lookat [cam-x eye-y cam-z] [target-x target-y target-z] [0 1 0])) (pxl8.set_model (pxl8.mat4_identity)) (pxl8.set_affine_textures affine) (pxl8.world_render world [cam-x eye-y cam-z]))) (let [new-state (debug-ui.render {:show-debug-ui show-debug-ui :fps fps :wireframe false :auto-rotate false :orthographic false :use-texture true :affine affine})] (when (not= new-state.show-debug-ui nil) (set show-debug-ui new-state.show-debug-ui)) (when (not= new-state.affine nil) (set affine new-state.affine)))) {:init init :update update :frame frame}