From 66fcd6a3cf7d26be1440586470af09d2064ea040 Mon Sep 17 00:00:00 2001 From: Jeremy Penner Date: Tue, 13 Apr 2021 19:56:23 -0400 Subject: [PATCH] Pacman movement! Basically. --- game/entities/pacman.fnl | 68 +++++++++++++++++++++++++++++++++++----- game/helpers.fnl | 10 ++++-- 2 files changed, 68 insertions(+), 10 deletions(-) diff --git a/game/entities/pacman.fnl b/game/entities/pacman.fnl index 71c2f84..b411ee6 100644 --- a/game/entities/pacman.fnl +++ b/game/entities/pacman.fnl @@ -2,7 +2,7 @@ (local dim (require :game.dim)) (local {: defmethod} (util.require :lib.multimethod)) (local {: direct : draw : update} (util.require :game.entity)) -(local {: vec*} (util.require :game.helpers)) +(local {: vec* : vec+ : edge : edge-crosses} (util.require :game.helpers)) (local map (require :game.tilemap)) (local pacman (util.hot-table ...)) @@ -37,13 +37,67 @@ ; their edges filed off!) ; I think Bomberman actually does this too -(defmethod update :pacman (fn [entity dt rules] +(fn tile-at [x y rules] + (-?> [x y] + (map.world-to-tile) + (rules.tile-at))) + +(fn collides? [[x y] rules] + (let [tile (tile-at x y rules)] + (and tile (or tile.bomb tile.wall)))) + +(fn horizontal [c copp] [c copp]) +(fn vertical [c copp] [copp c]) +(fn perp-move? [dprev doppnext] (and (not= dprev 0) (not= doppnext 0))) +(fn try-perp-turn [entity d make-xy rules] + (let [[c copp] (make-xy (table.unpack entity.pos)) + posperp (vec+ entity.pos (make-xy (if (> d 0) dim.tilesize (- dim.tilesize)) 0)) + [xcenter ycenter] (vec+ (vec* (map.world-to-tile posperp) dim.tilesize) dim.halftile) + [ccenter coppcenter] (make-xy xcenter ycenter) + turn-allowed? (and (> copp (- coppcenter (/ dim.tilesize 4))) + (< copp (+ coppcenter (/ dim.tilesize 4))))] + (when (and turn-allowed? (not (collides? posperp rules))) + (set entity.vel (make-xy d 0)) + (set entity.opp-target coppcenter)))) + +(fn rev-move? [dprev dprevopp dnext] + ; currently moving on this axis or not moving at all + (and (or (not= dprev 0) (and (= dprev 0) (= dprevopp 0))) + ; attempting to move in a new direction + (not= dnext 0) (not= dprev dnext))) + +(fn update-direction [entity rules] (let [[dx dy] entity.vel - [dxkey dykey] (direct pacman.keymap (* dim.tilesize 4)) - turn-attempted (and (or (not= dxkey 0) (not= dykey 0)) - (or (not= dxkey dx) (not= dykey dy)))] - (when turn-attempted - (set entity.vel [dxkey dykey]))))) + [dxkey dykey] (direct pacman.keymap (* dim.tilesize 4))] + ; two possible movement cases: + ; 1. Pacman wants to change direction perpendicular to how he is currently moving + ; 2. Pacman wants to change direction on the axis he is currently moving on + ; Case 1 takes priority over case 2 + (if (perp-move? dy dxkey) (try-perp-turn entity dxkey horizontal rules) + (perp-move? dx dykey) (try-perp-turn entity dykey vertical rules) + (rev-move? dx dy dxkey) (set entity.vel [dxkey 0]) + (rev-move? dy dx dykey) (set entity.vel [0 dykey])))) + +(fn move [entity dt rules] + (let [[dx dy] (vec* entity.vel dt) + make-xy (if (= dy 0) horizontal vertical) + [c copp] (make-xy (table.unpack entity.pos)) + [dc _] (make-xy dx dy) + (edge-prev edge-next) (edge c dc dim.halftile) + (crosses? edge-snap) (edge-crosses edge-prev edge-next dim.tilesize) + _ (print edge-prev edge-next edge-snap) + cnext (if (and crosses? (collides? (make-xy edge-next copp) rules)) + (+ c (- edge-snap edge-prev)) + (+ c dc)) + dcopp (if (= entity.opp-target nil) 0 + (-> (- entity.opp-target copp) + (math.min (* dt dim.tilesize 4)) + (math.max (* dt dim.tilesize -4))))] + (set entity.pos (make-xy cnext (+ copp dcopp))))) + +(defmethod update :pacman (fn [entity dt rules] + (update-direction entity rules) + (move entity dt rules))) (fn pacman.new [pos] {: pos :vel [0 0] :entity :pacman}) diff --git a/game/helpers.fnl b/game/helpers.fnl index 7e902c3..622d1ce 100644 --- a/game/helpers.fnl +++ b/game/helpers.fnl @@ -39,8 +39,12 @@ (values (+ c pos-offset) (+ c dc pos-offset)))) (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))))) + (let [t1 (math.floor (/ c1 width)) + t2 (math.floor (/ c2 width))] + (if (= c1 c2) false + (= (% c1 width) 0) (values true c1) + (= (% c2 width) 0) (values true c2) + (not= t1 t2) (values true (* (math.max t1 t2) width)) + false))) {: dir-from-key : vec* : vec+ : vec-op : all-coordinates : edge : edge-crosses}