~benaiah/ludum-dare-nov-2018

ad6ee9cfd29a1c5ef96029162c368b0c69eb94c9 — Benaiah Mischenko 2 years ago 8d87383 master
improved platforming, music, and camera

- can distinguish keypresses from held keys (walljumping isn't
  annoying now)

- looping background music

- gamera-based camera follows the player
5 files changed, 127 insertions(+), 43 deletions(-)

M .gitmodules
A bg_music_session.ogg
M game.fnl
M main.fnl
A modules/gamera
M .gitmodules => .gitmodules +3 -0
@@ 10,3 10,6 @@
[submodule "modules/bump-lua"]
	path = modules/bump-lua
	url = git@github.com:kikito/bump.lua.git
[submodule "modules/gamera"]
	path = modules/gamera
	url = git@github.com:kikito/gamera.git

A bg_music_session.ogg => bg_music_session.ogg +0 -0
M game.fnl => game.fnl +120 -43
@@ 2,6 2,7 @@
(local bump (require "modules.bump-lua.bump"))
(local ces (require "modules.ces-fnl.ces"))
(local inspect (require "modules.fennel.fennelview"))
(local gamera (require "modules.gamera.gamera"))
(local exports {})

;; tail recursive push! which takes a specific index, allowing it to


@@ 57,15 58,25 @@
      (push! acc key (unpack data)))
    acc))

;; distinguish keypresses from key holds
(var collect-keypresses {})
(fn exports.keypressed [key]
  (tset collect-keypresses key true))

(var keypress-table {})
(fn was-key-pressed [key]
  (. keypress-table key))

(local collision-filter (fn [] "slide"))

(fn make-player-map [p]
  (lume.merge {:position [100 100]
               :momentum [0 0]
               :gravity [1100]
               :controls [{:speed 1100 :jump 700 :max-speed 700}]
               :controls [0 {:speed 1100 :jump 700 :max-speed 700}]
               :collision [-25 -25 50 50 collision-filter]
               :platform-checks [0 0 0]}
               :platform-checks [0 0 0]
               :track-with-camera [true]}
              (or p {})))

(fn make-world []


@@ 73,15 84,16 @@
                {:position [:x :y]
                 :momentum [:x :y]
                 :gravity [:amount]
                 :controls [:options]
                 :controls [:jump-timer :options]
                 :collision [:ox :oy :w :h :filter]
                 :draw-rect [:ox :oy :w :h :color]
                 :draw-circle [:on]
                 :draw-player [:on]
                 :platform-checks [:standing :left-wall :right-wall]
                 :track-with-camera [:on]
                 }))
  world)

(local updates-initial {:position {} :momentum {} :platform-checks {}})
(local updates-initial {:position {} :momentum {} :platform-checks {} :controls {}})
(var updates updates-initial)

(local momentum-system


@@ 117,8 129,8 @@
                [_ standing left-wall right-wall] platform-checks
                [_ x y] position
                (_ standing-ay) (: bump-world :check id (+ x ox) (+ y oy 1) filter)
                (left-wall-ax) (: bump-world :check id (+ x ox -1) (+ y oy) filter)
                (right-wall-ax) (: bump-world :check id (+ x ox 1) (+ y oy) filter)
                (left-wall-ax) (: bump-world :check id (+ x ox -2) (+ y oy) filter)
                (right-wall-ax) (: bump-world :check id (+ x ox 2) (+ y oy) filter)

                standing-fudge-timer 0.2
                wall-slide-fudge-timer 0.2]


@@ 135,7 147,10 @@
        :controls
        [:controls :momentum :platform-checks]
        (fn controls [dt controls momentum platform-checks]
          (let [[id control-options] controls
          (let [[id jump-timer control-options] controls
                ;; we need to delay jumps at least long enough for the
                ;; fudged platform checks to disappear
                jump-timer-length 0.25
                [_ dx dy] momentum
                [_ standing at-left-wall at-right-wall] platform-checks
                is-standing (~= standing 0)


@@ 163,28 178,33 @@
                clamped-right-impulse (lume.clamp right-impulse 0 (- max-speed dx))
                new-dx (+ dx (* dt (+ friction-impulse clamped-left-impulse clamped-right-impulse)))
                wall-slide-speed 200
                [jump-dy jump-dx]
                (if (and (love.keyboard.isDown :w) is-standing)
                    [(* -1 control-options.jump)]
                can-jump (= 0 jump-timer)
                [jumped new-dy override-dx]
                (if (and can-jump is-standing (was-key-pressed :w))
                    [true (* -1 control-options.jump)]

                    (and is-at-left-wall (> dy 0) (love.keyboard.isDown :a))
                    (if (love.keyboard.isDown :w)
                        [(* -.75 control-options.jump) (* 0.65 control-options.jump)]
                        [(math.min dy wall-slide-speed)])
                    (and can-jump is-at-left-wall (> dy 0) (love.keyboard.isDown :a) (was-key-pressed :w))
                    [true (* -.75 control-options.jump) (* 0.65 control-options.jump)]

                    (and is-at-right-wall (love.keyboard.isDown :d) )
                    (if (love.keyboard.isDown :w)
                        [(* -0.75 control-options.jump) (* -0.65 control-options.jump)]
                        [(math.min dy wall-slide-speed)])
                    (and can-jump is-at-right-wall (love.keyboard.isDown :d) (was-key-pressed :w))
                    [true (* -0.75 control-options.jump) (* -0.65 control-options.jump)]
                    
                    (and is-at-left-wall (> dy 0) (love.keyboard.isDown :a))
                    [false (math.min dy wall-slide-speed)]
                    
                    (and is-at-right-wall (> dy 0) (love.keyboard.isDown :d))
                    [false (math.min dy wall-slide-speed)]

                    (and (not is-standing)
                         (not (love.keyboard.isDown :w))
                         (< dy 0))
                    [(lume.lerp dy 0 (/ dt 0.07))]
                    [false (lume.lerp dy 0 (/ dt 0.07))]

                    :else [dy])]
            (when (~= dy jump-dy) (tset updates.platform-checks id [0 0 0]))
            (tset updates.momentum id [(or jump-dx new-dx) jump-dy])))))
                    :else [false dy])]
            (if jumped
              (tset updates.controls id [jump-timer-length])
              (tset updates.controls id [(math.max 0 (- jump-timer dt))]))
            (tset updates.momentum id [(or override-dx new-dx) new-dy])))))

;; using object maps, create entities in both the CES world and the
;; bump world.


@@ 215,13 235,25 @@
             (tset updates.position id [resolvedx resolvedy])
             )))))))

(global music music)
(fn load-music []
  (or music
      (let [mus (love.audio.newSource "bg_music_session.ogg" :static)]
        (global music mus)
        mus)))

(fn exports.load []
  (let [world (make-world)
  (love.window.setMode 1024 768)
  (let [bg-music (load-music)
        world (make-world)
        bump-world (bump.newWorld)
        player-maps [(make-player-map {:draw-circle [:on]})
                     {:position [0 250]
        player-maps [(make-player-map {:draw-player [:on]})
                     {:position [0 200]
                      :collision [0 0 1000 10 collision-filter]
                      :draw-rect [0 0 1000 10 [255 255 255]]}
                     {:position [1000 200]
                      :collision [0 0 10 100 collision-filter]
                      :draw-rect [0 0 10 100 [255 255 255]]}
                     {:position [400 600]
                      :collision [0 0 1000 10 collision-filter]
                      :draw-rect [0 0 1000 10 [255 255 255]]}


@@ 232,13 264,18 @@
                      :collision [0 0 10 600 collision-filter]
                      :draw-rect [0 0 10 600 [255 255 255]]}
                     ]
        player-ids (create-entities-and-collisions world bump-world player-maps)]
    {:world world :bump-world bump-world}))
        player-ids (create-entities-and-collisions world bump-world player-maps)
        cam (gamera.new 0 0 2000 2000)]
    (: bg-music :setLooping true)
    (: bg-music :play)
    {:world world :bump-world bump-world :camera cam}))

(fn exports.init [state]
  (lume.merge state {}))

(fn exports.update [dt state]
  (set keypress-table collect-keypresses)
  (set collect-keypresses {})
  (local world state.world)
  (run-system world gravity-system dt)
  (ces.world.run-updates world updates)


@@ 257,26 294,66 @@
  (ces.world.run-updates world updates)
  (set updates updates-initial)

  (lume.merge state {:world world}))
  (lume.merge state {:world world :last-dt dt}))

(fn draw-player [_ _ position momentum platform-checks]
  (let [[id x y] position
        [_ dx dy] momentum
        [_ standing at-left-wall at-right-wall] platform-checks
        is-standing (> standing 0)
        is-at-left-wall (> at-left-wall 0)
        is-at-right-wall (> at-right-wall 0)
        wall-sliding-left (and is-at-left-wall (< dy 0))
        wall-sliding-right (and is-at-right-wall (< dy 0))
        x-shoulder-offsets [-16 16]
        y-shoulder-offsets [-15 -15]
        x-hand-offsets [(if is-at-left-wall -25 -25) (if is-at-right-wall 25 25)]
        y-hand-offsets [(if is-at-left-wall -30 10) (if is-at-right-wall -20 10)]
        x-momentum-offset (* -0.015 dx)
        y-momentum-offset (* -0.01 dy)]
    (love.graphics.ellipse :fill x (- y 5) 20 20)
                (love.graphics.setLineWidth 3)
                (love.graphics.line (+ x (. x-shoulder-offsets 1))
                                    (+ y (. y-shoulder-offsets 1))
                                    (+ x (. x-hand-offsets 1) x-momentum-offset)
                                    (+ y (. y-hand-offsets 1) y-momentum-offset))
                (love.graphics.line (+ x (. x-shoulder-offsets 2))
                                    (+ y (. y-shoulder-offsets 2))
                                    (+ x (. x-hand-offsets 2) x-momentum-offset)
                                    (+ y (. y-hand-offsets 2) y-momentum-offset))))

(fn exports.draw [state]
  (love.graphics.setBackgroundColor [0.05 0.05 0.05])
  (let [world state.world]
  (let [world state.world
        camera state.camera]
    (when world

      (love.graphics.setColor [0.95 0.95 0.95])
      (ces.world.call-on-common-components
       world [:draw-circle :position]
       (fn draw-ellipses [opts draw-circle position]
         (let [[id x y] position]
           (love.graphics.ellipse :fill x y 25 25))))

      (ces.world.call-on-common-components
       world [:draw-rect :position]
       (fn draw-rects [opts draw-rect position]
         (let [[id ox oy w h color] draw-rect
               [_ x y] position]
           (love.graphics.rectangle :fill (+ x ox) (+ y oy) w h)))))))
       world [:track-with-camera :position :platform-checks]
       (fn [_ track-with-camera position platform-checks]
         (let [[id on] track-with-camera
               [_ x y] position
               [_ standing] platform-checks
               (cx cy) (: camera :getPosition)]
           (when on
             (let [newcx (lume.lerp cx x (/ state.last-dt 0.25))
                   newcy (if true
                             (lume.lerp cy (- y 125) (/ state.last-dt 0.25))
                             cy)]
               (: camera :setPosition newcx newcy))))))

      (: camera :draw
         (fn [l t w h]
           (love.graphics.setColor [0.95 0.95 0.95])
           (ces.world.call-on-common-components
            world [:draw-player :position :momentum :platform-checks]
            draw-player)

           (ces.world.call-on-common-components
            world [:draw-rect :position]
            (fn draw-rects [opts draw-rect position]
              (let [[id ox oy w h color] draw-rect
                    [_ x y] position]
                (love.graphics.rectangle :fill (+ x ox) (+ y oy) w h)))))))))

(fn exports.repl-env [state] {:ces ces})


M main.fnl => main.fnl +3 -0
@@ 40,3 40,6 @@

(fn love.draw [] 
  (when game-state (game.draw game-state)))

(fn love.keypressed [key]
  (game.keypressed key))

A modules/gamera => modules/gamera +1 -0
@@ 0,0 1,1 @@
Subproject commit de363d0f4a2fb1ab9b03ecf976b6e4c32b1bfa7a