Improved Bomberman movement
This commit is contained in:
parent
d84a515a55
commit
02099c9461
|
@ -1 +1,5 @@
|
||||||
{:tilesize 32}
|
(local dim {})
|
||||||
|
(set dim.tilesize 32)
|
||||||
|
(set dim.halftile (/ dim.tilesize 2))
|
||||||
|
|
||||||
|
dim
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
|
|
||||||
(fn Bomb.explode [bomb rules]
|
(fn Bomb.explode [bomb rules]
|
||||||
(Bomb.set-state bomb :exploding 0.5)
|
(Bomb.set-state bomb :exploding 0.5)
|
||||||
(set bomb.solid nil)
|
(set bomb.bomb nil)
|
||||||
(set bomb.deadly true)
|
(set bomb.deadly true)
|
||||||
(rules.explode-bomb bomb))
|
(rules.explode-bomb bomb))
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@
|
||||||
:exploding (rules.clear-bomb bomb))))
|
:exploding (rules.clear-bomb bomb))))
|
||||||
|
|
||||||
(fn Bomb.new []
|
(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 []
|
(fn Bomb.new-explosion []
|
||||||
{:state :exploding :timer 0.5 :deadly true :draw #(Bomb.draw $...) :update #(Bomb.update $...)})
|
{:state :exploding :timer 0.5 :deadly true :draw #(Bomb.draw $...) :update #(Bomb.update $...)})
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
(local util (require :lib.util))
|
(local util (require :lib.util))
|
||||||
(local dim (require :game.dim))
|
(local dim (require :game.dim))
|
||||||
(local {: direct : move} (util.require :game.entity))
|
(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 map (require :game.tilemap))
|
||||||
|
|
||||||
(local bomberman (util.hot-table ...))
|
(local bomberman (util.hot-table ...))
|
||||||
|
@ -11,21 +11,63 @@
|
||||||
(love.graphics.setColor 0.2 0.2 0.2)
|
(love.graphics.setColor 0.2 0.2 0.2)
|
||||||
(love.graphics.circle :fill (. entity.pos 1) (. entity.pos 2) (/ dim.tilesize 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]
|
(-?> [x y]
|
||||||
(map.world-to-tile)
|
(map.world-to-tile)
|
||||||
(rules.tile-at)
|
(rules.tile-at)))
|
||||||
(. :solid)))
|
|
||||||
|
(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]
|
(fn bomberman.update [entity dt rules]
|
||||||
(set entity.vel (direct bomberman.keymap (* dim.tilesize 3)))
|
(set entity.vel (direct bomberman.keymap (* dim.tilesize 3)))
|
||||||
(local [x y] entity.pos)
|
(local [x y] entity.pos)
|
||||||
(local [dx dy] (vec* entity.vel dt))
|
(local [dx dy] (vec* entity.vel dt))
|
||||||
(let [xedge (edge x dx (/ dim.tilesize 2))
|
(let [[dx1 dy1] (bomberman.axis-movement (horizontal x y) x y dx rules)
|
||||||
xn (if (collides? xedge y rules) x (+ x dx))
|
[dy2 dx2] (bomberman.axis-movement (vertical x y) y x dy rules)]
|
||||||
yedge (edge y dy (/ dim.tilesize 2))
|
(set entity.pos [(+ x dx1 dx2) (+ y dy1 dy2)]))
|
||||||
yn (if (collides? x yedge rules) y (+ y dy))]
|
|
||||||
(set entity.pos [xn yn]))
|
|
||||||
(when (love.keyboard.isDown bomberman.keymap.bomb)
|
(when (love.keyboard.isDown bomberman.keymap.bomb)
|
||||||
(rules.place-bomb (map.world-to-tile entity.pos))))
|
(rules.place-bomb (map.world-to-tile entity.pos))))
|
||||||
|
|
||||||
|
|
|
@ -34,8 +34,13 @@
|
||||||
|
|
||||||
(fn edge [c dc neg-offset ?pos-offset]
|
(fn edge [c dc neg-offset ?pos-offset]
|
||||||
(local pos-offset (if (= ?pos-offset nil) neg-offset ?pos-offset))
|
(local pos-offset (if (= ?pos-offset nil) neg-offset ?pos-offset))
|
||||||
(if (= dc 0) c
|
(if (= dc 0) (values c c)
|
||||||
(< dc 0) (+ c dc (- neg-offset))
|
(< dc 0) (values (- c neg-offset) (+ c dc (- neg-offset)))
|
||||||
(+ c dc pos-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}
|
||||||
|
|
|
@ -67,11 +67,6 @@
|
||||||
(-> vec
|
(-> vec
|
||||||
((vec-op #(math.floor (/ $1 dim.tilesize))))))
|
((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-tilemap : itile-at : tile-at : set-itile-at : tile-at-overlay : draw-tilemaps
|
||||||
: new-entitymap : set-entity-at : remove-entity : update-entitymap
|
: new-entitymap : set-entity-at : remove-entity : update-entitymap
|
||||||
: world-to-tile}
|
: world-to-tile}
|
||||||
|
|
|
@ -29,9 +29,9 @@
|
||||||
[{:name :empty
|
[{:name :empty
|
||||||
:empty true}
|
:empty true}
|
||||||
{:name :strongwall
|
{:name :strongwall
|
||||||
:solid true}
|
:wall true}
|
||||||
{:name :weakwall
|
{:name :weakwall
|
||||||
:solid true
|
:wall true
|
||||||
:breakable true}
|
:breakable true}
|
||||||
{:name :dot
|
{:name :dot
|
||||||
:edible true}
|
:edible true}
|
||||||
|
|
Loading…
Reference in a new issue