diff --git a/game/dim.fnl b/game/dim.fnl index d238f61..79c3199 100644 --- a/game/dim.fnl +++ b/game/dim.fnl @@ -1 +1,5 @@ -{:tilesize 32} +(local dim {}) +(set dim.tilesize 32) +(set dim.halftile (/ dim.tilesize 2)) + +dim diff --git a/game/entities/bomb.fnl b/game/entities/bomb.fnl index 9bdaec0..52b666a 100644 --- a/game/entities/bomb.fnl +++ b/game/entities/bomb.fnl @@ -28,7 +28,7 @@ (fn Bomb.explode [bomb rules] (Bomb.set-state bomb :exploding 0.5) - (set bomb.solid nil) + (set bomb.bomb nil) (set bomb.deadly true) (rules.explode-bomb bomb)) @@ -40,7 +40,7 @@ :exploding (rules.clear-bomb bomb)))) (fn Bomb.new [] - {:state :ticking :timer 3 :solid true :draw #(Bomb.draw $...) :update #(Bomb.update $...)}) + {:state :ticking :timer 3 :bomb true :draw #(Bomb.draw $...) :update #(Bomb.update $...)}) (fn Bomb.new-explosion [] {:state :exploding :timer 0.5 :deadly true :draw #(Bomb.draw $...) :update #(Bomb.update $...)}) diff --git a/game/entities/bomberman.fnl b/game/entities/bomberman.fnl index b0ca496..f05c1a0 100644 --- a/game/entities/bomberman.fnl +++ b/game/entities/bomberman.fnl @@ -1,7 +1,7 @@ (local util (require :lib.util)) (local dim (require :game.dim)) (local {: direct : move} (util.require :game.entity)) -(local {: edge : vec*} (util.require :game.helpers)) +(local {: edge : edge-crosses : vec*} (util.require :game.helpers)) (local map (require :game.tilemap)) (local bomberman (util.hot-table ...)) @@ -11,21 +11,63 @@ (love.graphics.setColor 0.2 0.2 0.2) (love.graphics.circle :fill (. entity.pos 1) (. entity.pos 2) (/ dim.tilesize 2))) -(fn collides? [x y rules] +(fn tile-at [x y rules] (-?> [x y] (map.world-to-tile) - (rules.tile-at) - (. :solid))) + (rules.tile-at))) + +(fn wall-collides? [x y rules] + (-?> (tile-at x y rules) + (. :wall))) + +(fn bomb-collides? [x y rules] + (-?> (tile-at x y rules) + (. :bomb))) + +(fn bomberman.collides? [[x y] rules] + (let [tile (tile-at x y rules)] + (and tile (or tile.bomb tile.wall)))) + +(fn bomberman.tile-edge [c dc] + (let [tc (math.floor (/ c dim.tilesize)) + cfloor (* tc dim.tilesize)] + (if (= dc 0) c + (> dc 0) (- cfloor dim.halftile) + (+ cfloor dim.tilesize dim.halftile)))) + +; Collision model for Bomberman works like this (in order): +; * if the moving edge is NOT crossing over a tile boundary, allow the movement +; * if there is no solid tile in in front of Bomberman, allow the movement +; * if there are two solid tiles in front of Bomberman, push Bomberman back onto +; the tile boundary +; * if there is one solid and one empty tile in front of Bomberman, push Bomberman +; back onto the tile boundary, and push Bomberman towards the empty tile in the +; other axis +; repeat for both x and y axis +; TODO: do we add the two vectors? is it acceptable that diagonal movement is faster? +(fn horizontal [x y] (fn [dx dy] [(+ x dx) (+ y dy)])) +(fn vertical [x y] (fn [dy dx] [(+ x dx) (+ y dy)])) +(fn bomberman.axis-movement [off c copp dc rules] + (let [d (fn [cnew] (- cnew c)) + (edge-prev edge-next) (edge c dc dim.halftile) + crosses (edge-crosses edge-prev edge-next dim.tilesize) + neg-collides (bomberman.collides? (off (d edge-next) (- dim.halftile)) rules) + pos-collides (bomberman.collides? (off (d edge-next) (- dim.halftile 0.01)) rules) + dc-edge (d (bomberman.tile-edge edge-next dc)) + dcopp (math.abs dc)] + (if (not crosses) [dc 0] + (and (not neg-collides) (not pos-collides)) [dc 0] + (and neg-collides pos-collides) [dc-edge 0] + neg-collides [dc-edge (math.min dcopp (- (bomberman.tile-edge (+ copp dim.tilesize (- dim.halftile 0.01)) 1) copp))] + pos-collides [dc-edge (math.max (- dcopp) (- (bomberman.tile-edge (- copp dim.tilesize dim.halftile) -1) copp))]))) (fn bomberman.update [entity dt rules] (set entity.vel (direct bomberman.keymap (* dim.tilesize 3))) (local [x y] entity.pos) (local [dx dy] (vec* entity.vel dt)) - (let [xedge (edge x dx (/ dim.tilesize 2)) - xn (if (collides? xedge y rules) x (+ x dx)) - yedge (edge y dy (/ dim.tilesize 2)) - yn (if (collides? x yedge rules) y (+ y dy))] - (set entity.pos [xn yn])) + (let [[dx1 dy1] (bomberman.axis-movement (horizontal x y) x y dx rules) + [dy2 dx2] (bomberman.axis-movement (vertical x y) y x dy rules)] + (set entity.pos [(+ x dx1 dx2) (+ y dy1 dy2)])) (when (love.keyboard.isDown bomberman.keymap.bomb) (rules.place-bomb (map.world-to-tile entity.pos)))) diff --git a/game/helpers.fnl b/game/helpers.fnl index 3453f85..7e902c3 100644 --- a/game/helpers.fnl +++ b/game/helpers.fnl @@ -34,8 +34,13 @@ (fn edge [c dc neg-offset ?pos-offset] (local pos-offset (if (= ?pos-offset nil) neg-offset ?pos-offset)) - (if (= dc 0) c - (< dc 0) (+ c dc (- neg-offset)) - (+ c dc pos-offset))) + (if (= dc 0) (values c c) + (< dc 0) (values (- c neg-offset) (+ c dc (- neg-offset))) + (values (+ c pos-offset) (+ c dc pos-offset)))) -{: dir-from-key : vec* : vec+ : vec-op : all-coordinates : edge} +(fn edge-crosses [c1 c2 width] + (if (= c1 c2) false + (or (= (% c1 width) 0) (= (% c2 width) 0)) true + (not= (math.floor (/ c1 width)) (math.floor (/ c2 width))))) + +{: dir-from-key : vec* : vec+ : vec-op : all-coordinates : edge : edge-crosses} diff --git a/game/tilemap.fnl b/game/tilemap.fnl index a14effd..894ee4d 100644 --- a/game/tilemap.fnl +++ b/game/tilemap.fnl @@ -67,11 +67,6 @@ (-> vec ((vec-op #(math.floor (/ $1 dim.tilesize)))))) -(fn colliding-tile-xy [vec dir] - (-> vec - (world-to-tile) - (vec+ dir))) - {: new-tilemap : itile-at : tile-at : set-itile-at : tile-at-overlay : draw-tilemaps : new-entitymap : set-entity-at : remove-entity : update-entitymap : world-to-tile} diff --git a/game/tiles.fnl b/game/tiles.fnl index 3893ddc..8772aa9 100644 --- a/game/tiles.fnl +++ b/game/tiles.fnl @@ -29,9 +29,9 @@ [{:name :empty :empty true} {:name :strongwall - :solid true} + :wall true} {:name :weakwall - :solid true + :wall true :breakable true} {:name :dot :edible true}