From ca870dab91daee38b8d55ac6d2f2b4fd6959c6ac Mon Sep 17 00:00:00 2001 From: equa Date: Sun, 18 Apr 2021 20:22:20 -0500 Subject: entities et al --- lib/cells.fnl | 25 +++++++++++++++++- lib/entity.fnl | 12 +++++++++ lib/game.fnl | 81 ++++++++++++++++++++++++++++++++++++++++------------------ lib/main.fnl | 10 ++++---- lib/player.fnl | 39 ++++++++++++++++++++++++++++ lib/vec.fnl | 27 ++++++++++++++++++++ 6 files changed, 163 insertions(+), 31 deletions(-) create mode 100644 lib/entity.fnl create mode 100644 lib/player.fnl create mode 100644 lib/vec.fnl (limited to 'lib') diff --git a/lib/cells.fnl b/lib/cells.fnl index dde8372..3a43010 100644 --- a/lib/cells.fnl +++ b/lib/cells.fnl @@ -63,4 +63,27 @@ [0.2 0.2 0.3]) }) -{: life : brain} +(local boom + {cell.init + (fn [self] + (setmetatable {:life 1} self)) + cell.birth + (fn [self get] + (if (and (> self.life 0.08) + (> (neighbors> get (* (if (> self.life 0.9) 0.3 0.1) (math.random 7))) 0)) + (do + (setmetatable {:life (* self.life 0.8)} (getmetatable self))) + nil)) + cell.update + (fn [self get] + (if (> self.life 0.3) + (setmetatable {:life (* self.life (+ 0.5 (* (math.random 5) 0.1)))} (getmetatable self)) + nil)) + cell.aliveness + #$.life + cell.color + #[(+ 0.4 (* 0.6 $.life)) + (math.max 0 (- 0.8 (* 0.9 (- 1 $.life)))) + (+ 0.1 )]}) + +{: life : brain : boom} diff --git a/lib/entity.fnl b/lib/entity.fnl new file mode 100644 index 0000000..2032e65 --- /dev/null +++ b/lib/entity.fnl @@ -0,0 +1,12 @@ +(local proto (require :lib.proto)) + +{:init (proto.table-method :entity.init) + :position (proto.table-value :entity.position) + :velocity (proto.table-value :entity.velocity) + ;; [self game {: up : down : left : right}] + :steer (proto.meta-method :entity.velocity) + ;; [self game] + ;; screen origin at center of entity, 1 = 1 pixel (for now) + :draw (proto.meta-method :entity.draw) + ;; [self game pos] + :collide (proto.meta-method-opt :entity.collide)} diff --git a/lib/game.fnl b/lib/game.fnl index 01f882d..b75a254 100644 --- a/lib/game.fnl +++ b/lib/game.fnl @@ -1,19 +1,14 @@ (local state (require :lib.state)) (local cell (require :lib.cell)) (local cells (require :lib.cells)) +(local vec (require :lib.vec)) +(local entity (require :lib.entity)) +(local player (require :lib.player)) (local fv (require :fennel.view)) (fn lerp* [a b c d x] (+ c (* (/ (- x a) (- b a)) (- d c)))) -(fn vec-sub [a b] - {:x (- a.x b.x) - :y (- a.y b.y)}) - -(fn vec-lerp* [a b c d x] - {:x (lerp* a.x b.x c.x d.x x.x) - :y (lerp* a.y b.y c.y d.y x.y)}) - (fn new-grid [w h f] (var t {}) (for [x 0 (- w 1)] @@ -23,8 +18,8 @@ t) (fn update [self] - (set self.ship.x (+ self.ship.x 0.02)) - (set self.ship.y (+ self.ship.y 0.005)) + ;; (set ship-pos.x (+ self.ship.x 0.02)) + ;; (set ship-pos.y (+ self.ship.y 0.005)) (set self.radius (lerp* 0 1 self.radius self.target-radius 0.3)) (when (= self.tick 0) (for [x 0 (- self.width 1)] @@ -48,15 +43,37 @@ (cell.birth (. neighbors (math.random (length neighbors))) get)) (tset self.grid-alt x y nil)))))) (set (self.grid self.grid-alt) (values self.grid-alt self.grid))) - ;; TODO - (set self.tick (% (+ self.tick 1) self.rate))) + (set self.tick (% (+ self.tick 1) self.rate)) + ;; player steering + (when self.entities.player + (entity.steer self.entities.player + self + :player + {:up (love.keyboard.isDown :up) + :right (love.keyboard.isDown :right) + :left (love.keyboard.isDown :left)})) + ;; entities + (each [id e (pairs self.entities)] + (tset e entity.position (vec.wrap + (vec.add (entity.position e) (entity.velocity e)) + {:x self.width :y self.height})) + (let [x (math.floor (. e entity.position :x)) + y (math.floor (. e entity.position :y)) + t (. self.grid x y)] + (when t + (entity.collide e self id x y))) + ) + ) (fn id [x] x) (fn draw [self] (local (width height) (love.graphics.getDimensions)) ;; (love.graphics.scale width height) - (let [camera-size (math.min width height) + (let [ship-pos (if self.entities.player + (entity.position self.entities.player) + self.ship-pos) + camera-size (math.min width height) radius-x (* self.radius (/ width camera-size)) radius-y (* self.radius (/ height camera-size)) clipped-x (math.min radius-x self.max-radius) @@ -64,18 +81,20 @@ display-a {:x (* width (- 1 (/ clipped-x radius-x)) 0.5) :y (* height (- 1 (/ clipped-y radius-y)) 0.5)} display-b {:x (- width display-a.x) :y (- height display-a.y)} - display-size (vec-sub display-b display-a) - camera-a {:x (- self.ship.x clipped-x) - :y (- self.ship.y clipped-y)} - camera-b {:x (+ self.ship.x clipped-x) - :y (+ self.ship.y clipped-y)} - cell-box (vec-lerp* {:x 0 :y 0} + display-size (vec.sub display-b display-a) + camera-a {:x (- ship-pos.x clipped-x) + :y (- ship-pos.y clipped-y)} + camera-b {:x (+ ship-pos.x clipped-x) + :y (+ ship-pos.y clipped-y)} + cell-box (vec.lerp {:x 0 :y 0} {:x (* 2 clipped-x) :y (* 2 clipped-y)} ;; TODO: this is wrong {:x 0 :y 0} display-size {:x 1 :y 1})] + ;; TODO: this is ugly and weird + (set self.ship-pos ship-pos) (love.graphics.setScissor (- display-a.x 1) (- display-a.y 1) (- display-b.x display-a.x -2) (- display-b.y display-a.y -2)) @@ -91,12 +110,12 @@ (love.graphics.clear) (for [x (math.floor camera-a.x) (math.floor camera-b.x)] (for [y (math.floor camera-a.y) (math.floor camera-b.y)] - (let [vec {:x (% x self.width) :y (% y self.height)} - render-a (vec-lerp* camera-a camera-b display-a display-b + (let [pos {:x (% x self.width) :y (% y self.height)} + render-a (vec.lerp camera-a camera-b display-a display-b {: x : y}) - render-b (vec-lerp* camera-a camera-b display-a display-b + render-b (vec.lerp camera-a camera-b display-a display-b {:x (+ x 1) :y (+ y 1)}) - the (. self.grid vec.x vec.y) + the (. self.grid pos.x pos.y) color (and the (cell.color the))] (when color (love.graphics.setColor (unpack color)) @@ -106,6 +125,15 @@ (id cell-box.x) (id cell-box.y)))))) ;; draw other stuff + (each [id v (pairs self.entities)] + (love.graphics.push) + (let [pos (entity.position v) + render-pos (vec.lerp camera-a camera-b display-a display-b pos)] + (love.graphics.translate render-pos.x render-pos.y) + (love.graphics.scale cell-box.x + cell-box.y)) + (entity.draw v self id) + (love.graphics.pop)) )) ;; (love.graphics.setLineWidth 0.1) ;; (love.graphics.line 0 0 0.3 0.3) @@ -142,10 +170,13 @@ :min-radius 16 :tick 0 :rate 6 + :entities {:player (entity.init player {:x 32 :y 32})} :grid (new-grid width height #(if (= (math.random 6) 1) - (if (< $1 52) + (if (> $1 34) (cell.init cells.life) - (cell.init cells.brain)) + (< $1 00) + (cell.init cells.brain) + nil) nil)) :grid-alt (new-grid width height #nil) } diff --git a/lib/main.fnl b/lib/main.fnl index 03383ad..8e4908a 100644 --- a/lib/main.fnl +++ b/lib/main.fnl @@ -10,7 +10,8 @@ ;; i'm not sure if it'd be worth it (it'd require those dependency loops maybe) ;; TODO: ^ (local hotswap-modules - [:lib.cells + [:lib.player + :lib.cells :lib.game :lib.main]) @@ -19,11 +20,11 @@ (fn love.load [] (when profi? - (profi:start)) - (set love.frame 0) + (profi:start) + (set love.frame 0)) (love.keyboard.setKeyRepeat true) (global the-state (state.init game)) - (global messages {}) + (global messages (or messages {})) (print "a")) (fn love.draw [] @@ -46,7 +47,6 @@ (table.remove messages i) (set v.ticks (- v.ticks 1)))))) -;; TODO: we need a better way to display errors at runtime for updates too (fn love.update [] (when profi? (profi:startHooks) diff --git a/lib/player.fnl b/lib/player.fnl new file mode 100644 index 0000000..0633727 --- /dev/null +++ b/lib/player.fnl @@ -0,0 +1,39 @@ +(local entity (require :lib.entity)) +(local vec (require :lib.vec)) +(local cell (require :lib.cell)) +(local cells (require :lib.cells)) + +(fn init [self pos] + (setmetatable {entity.position pos + entity.velocity {:x 0 :y 0} + :target-spin 0 + :direction 0} + self)) + +(fn steer [self game id controls] + ;; TODO: smooth turning + (when controls.left + (set self.target-spin (- self.target-spin 0.15))) + ;; (set self.direction (% (- self.direction 0.1) (* math.pi 2))) + (when controls.right + (set self.target-spin (+ self.target-spin 0.15))) + (set self.direction (% (+ self.direction (* self.target-spin 0.1)) (* math.pi 2))) + (set self.target-spin (* self.target-spin 0.9)) + (when controls.up + (local v (entity.velocity self)) + (set v.x (+ v.x (* (math.cos self.direction) 0.02))) + (set v.y (+ v.y (* (math.sin self.direction) 0.02))) + (when (> (vec.mag v) 0.8) + (tset self entity.velocity (vec.mul v (/ 0.8 (vec.mag v))))))) + +(fn draw [self game id] + (love.graphics.setColor 1 1 1) + (love.graphics.rotate self.direction) + (love.graphics.polygon :fill -0.6 -0.4 0.6 0 -0.6 0.4)) + +(fn collide [self game id x y] + (print "ow!") + (tset game.entities id nil) + (tset game.grid x y (cell.init cells.boom))) + +{entity.init init entity.steer steer entity.draw draw entity.collide collide} diff --git a/lib/vec.fnl b/lib/vec.fnl new file mode 100644 index 0000000..cce9627 --- /dev/null +++ b/lib/vec.fnl @@ -0,0 +1,27 @@ +(fn ilerp* [a b c d x] + (+ c (* (/ (- x a) (- b a)) (- d c)))) + +(fn add [a b] + {:x (+ a.x b.x) + :y (+ a.y b.y)}) + +(fn sub [a b] + {:x (- a.x b.x) + :y (- a.y b.y)}) + +(fn mul [v n] + {:x (* v.x n) + :y (* v.y n)}) + +(fn mag [v] + (math.sqrt (+ (* v.x v.x) (* v.y v.y)))) + +(fn wrap [a b] + {:x (% a.x b.x) + :y (% a.y b.y)}) + +(fn lerp [a b c d x] + {:x (ilerp* a.x b.x c.x d.x x.x) + :y (ilerp* a.y b.y c.y d.y x.y)}) + +{: lerp : add : sub : mul : mag : wrap} -- cgit 1.3.0-6-gf8a5