diff options
| author | Jakob L. Kreuze <jakob@memeware.net> | 2018-10-21 19:14:02 -0400 |
|---|---|---|
| committer | Jakob L. Kreuze <jakob@memeware.net> | 2018-10-21 19:14:02 -0400 |
| commit | 49de0938a3609be7bcf9bed6766bc27f2d389c2a (patch) | |
| tree | 37c99278dfe5acf818aae8fcf5680a2e4e020562 | |
| parent | fdf869cdddf66b1c1cb27380e157d580a5e3fb82 (diff) | |
Refactoring + initial surface sliming
| -rw-r--r-- | art/slime.png | bin | 0 -> 502 bytes | |||
| -rw-r--r-- | art/swanky.png | bin | 5186 -> 5173 bytes | |||
| -rw-r--r-- | art/tiles.png | bin | 927 -> 974 bytes | |||
| -rw-r--r-- | game.fnl | 269 | ||||
| -rw-r--r-- | map.fnl | 48 | ||||
| -rw-r--r-- | sandbox.fnl | 256 | ||||
| -rw-r--r-- | wrap.fnl | 8 |
7 files changed, 308 insertions, 273 deletions
diff --git a/art/slime.png b/art/slime.png Binary files differnew file mode 100644 index 0000000..8d977cf --- /dev/null +++ b/art/slime.png diff --git a/art/swanky.png b/art/swanky.png Binary files differindex 2342e45..3fd8c29 100644 --- a/art/swanky.png +++ b/art/swanky.png diff --git a/art/tiles.png b/art/tiles.png Binary files differindex a9d36c5..97a5720 100644 --- a/art/tiles.png +++ b/art/tiles.png diff --git a/game.fnl b/game.fnl new file mode 100644 index 0000000..60c025c --- /dev/null +++ b/game.fnl @@ -0,0 +1,269 @@ +;;;; Copyright (C) 2018 Jakob L. Kreuze, All Rights Reserved. +;;;; +;;;; This file is part of swanky. +;;;; +;;;; swanky is free software: you can redistribute it and/or modify it under the +;;;; terms of the GNU General Public License as published by the Free Software +;;;; Foundation, either version 3 of the License, or (at your option) any later +;;;; version. +;;;; +;;;; swanky is distributed in the hope that it will be useful, but WITHOUT ANY +;;;; WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +;;;; FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +;;;; details. +;;;; +;;;; You should have received a copy of the GNU General Public License along +;;;; with swanky. If not, see <http://www.gnu.org/licenses/>. + +(local bump (require :lib.bump)) +(local lume (require :lib.lume)) + +(local map (require :map)) + +(local player-sheet + {:img (love.graphics.newImage "art/swanky.png") + :orientation-offset 128 + :width 24 :height 22 + :padding-x 8 :padding-y 10}) + +(local player-animations + {:idle {:offset 0 :sustain false :frames 2} + :jump {:offset 2 :sustain true :frames 4}}) + +;; Returns a new player object, placed at the world coordinates, (`x', `y'). +(fn make-player [x y] + {:width (. player-sheet :width) + :height (. player-sheet :height) + + :goal-x-vel 128 + :goal-y-vel 128 + + :x-pos x + :y-pos y + + :x-vel 0 + :y-vel 0 + + :orientation :right + :animation :idle + :frame 0 + + :grounded false + + :action {:jump false + :right false + :left false}}) + +(fn player-turn-right [player] + (tset player :orientation :right) + (tset player :action :right true) + (tset player :action :left false) + (tset player :x-vel (/ (. player :x-vel) 2))) + +(fn player-turn-left [player] + (tset player :orientation :left) + (tset player :action :left true) + (tset player :action :right false) + (tset player :x-vel (/ (. player :x-vel) 2))) + +;; Returns a new camera object initially focused at the given world coordinates, +;; (`x', `y'). +(fn make-camera [x y] + {:x-pos x + :y-pos y}) + +;; Returns a new collision map containing `player' and everything in `map'. +(fn make-collision-map [player tiles] + (let [world (bump.newWorld 32) + width (# (. tiles 1)) + height (# tiles)] + (: world :add player (. player :x-pos) (. player :y-pos) (. player :width) (. player :height)) + (for [x 0 (- width 1)] + (for [y 0 (- height 1)] + (let [tile (. tiles (+ 1 y) (+ 1 x))] + (when (~= :empty (. tile :type)) + (: world :add tile (* x (. map :tiles :width)) (* y (. map :tiles :height)) (. map :tiles :width) (. map :tiles :height)))))) + world)) + +(local camera (make-camera 0 0)) +(local player (make-player 128 128)) +(local world (map.load "sandbox")) +(local collision-map (make-collision-map player (. world :tiles))) + +;; Draws the slime effect for a given orientation at the screen coordinates, +;; (`x', `y'). +(fn draw-slime-decal [tile orientation x y] + (let [decal-offset (. map :slime :offsets orientation)] + (let [quad (love.graphics.newQuad (+ (. map :slime :padding-x) + (* (+ (. map :slime :width) + (. map :slime :padding-x)) + decal-offset)) + (. map :slime :padding-y) + (. map :slime :width) + (. map :slime :height) + (: (. map :slime :img) :getWidth) + (: (. map :slime :img) :getHeight))] + (love.graphics.draw (. map :slime :img) quad x y)))) + +(fn draw-slime [tile x y] + (each [orientation slimed (pairs (. tile :slimed))] + (when slimed + (draw-slime-decal tile orientation x y)))) + +;; Draws a single tile at the screen coordinates, (`x', `y'). +(fn draw-tile [tile x y] + (let [tile-offset (. map :tiles :offsets (. tile :type))] + (let [quad (love.graphics.newQuad (+ (. map :tiles :padding-x) + (* (+ (. map :tiles :width) (. map :tiles :padding-x)) tile-offset)) + (. map :tiles :padding-y) + (. map :tiles :width) + (. map :tiles :height) + (: (. map :tiles :img) :getWidth) + (: (. map :tiles :img) :getHeight))] + (love.graphics.draw (. map :tiles :img) quad x y)))) + +;; Drawing routine for rendering the tiles visible from a given camera offset. +(fn draw-tiles [tiles camera-x camera-y] + (let [how-many-x (+ 1 (/ screen-width (. map :tiles :width))) + how-many-y (+ 1 (/ screen-height (. map :tiles :height))) + start-x (math.floor (/ camera-x (. map :tiles :width))) + start-y (math.floor (/ camera-y (. map :tiles :height))) + width (# (. tiles 1)) + height (# tiles)] + (for [x-offset 0 how-many-x] + (for [y-offset 0 how-many-y] + (when (and (and (>= (+ start-x x-offset) 0) (< (+ start-x x-offset) width)) + (and (>= (+ start-y y-offset) 0) (< (+ start-y y-offset) height))) + (let [tile (. tiles (+ start-y y-offset 1) (+ start-x x-offset 1)) + x (- (* x-offset (. map :tiles :width)) (% camera-x (. map :tiles :width))) + y (- (* y-offset (. map :tiles :height)) (% camera-y (. map :tiles :height)))] + (when (~= :empty (. tile :type)) + (draw-tile tile x y) + (draw-slime tile x y)))))))) + +;; Draws from a given sprite sheet, `sheet' to the screen coordinates (`x', `y') +;; with the given animation parameters. +(fn draw-sprite [sheet animation-offset frame orientation x y] + (let [x-offset (+ (. sheet :padding-x) + (* frame (+ (. sheet :width) (. sheet :padding-x))) + (if (= orientation :right) 0 (. sheet :orientation-offset))) + y-offset (+ (. sheet :padding-y) + (* animation-offset (+ (. sheet :height) (. sheet :padding-y))))] + (let [quad (love.graphics.newQuad x-offset + y-offset + (. sheet :width) + (. sheet :height) + (: (. sheet :img) :getWidth) + (: (. sheet :img) :getHeight))] + (love.graphics.draw (. sheet :img) quad x y)))) + +(fn draw [message] + (love.graphics.clear 1 1 1) + (draw-tiles (. world :tiles) (. camera :x-pos) (. camera :y-pos)) + (let [x (- (. player :x-pos) (. camera :x-pos)) + y (- (. player :y-pos) (. camera :y-pos)) + animation-offset (. player-animations (. player :animation) :offset)] + (draw-sprite player-sheet + animation-offset + (. player :frame) + (. player :orientation) + x + y))) + +(fn update [dt set-mode] + (local gravity 128) + (local camera-lock-goal-x (math.floor (- (/ screen-width 2) + (/ (. player-sheet :width) 2)))) + (local camera-lock-goal-y (math.floor (- (/ screen-height 2) + (/ (. player-sheet :height) 2)))) + + ;; Update animations. + ;; TODO + + ;; Update camera. + (tset camera :x-pos (lume.lerp (. camera :x-pos) + (- (. player :x-pos) camera-lock-goal-x) (* 4 dt))) + (tset camera :y-pos (lume.lerp (. camera :y-pos) + (- (. player :y-pos) camera-lock-goal-x) (* 4 dt))) + + ;; Lock camera so that it doesn't go out of bounds. + (when (> 0 (. camera :x-pos)) + (tset camera :x-pos 0)) + + (when (> 0 (. camera :y-pos)) + (tset camera :y-pos 0)) + + (let [max-x (- (* (. map :tiles :width) (. world :width)) screen-width)] + (when (>= (. camera :x-pos) max-x) + (tset camera :x-pos max-x))) + + (let [max-y (- (* (. map :tiles :height) (. world :height)) screen-height)] + (when (>= (. camera :y-pos) max-y) + (tset camera :y-pos max-y))) + + ;; Update the swanky's velocities to reflect controls. + (let [goal-x-vel (if (. player :action :right) (. player :goal-x-vel) + (. player :action :left) (- (. player :goal-x-vel)) + 0)] + (tset player :x-vel (lume.lerp (. player :x-vel) goal-x-vel dt))) + + (when (and (. player :action :jump) (. player :grounded)) + (tset player :y-vel (- (. player :y-vel) (. player :goal-y-vel)))) + + ;; Update the y-velocity to reflect gravity. + (if (and (. player :grounded) (not (. player :action :jump))) + (tset player :y-vel 0) + (tset player :y-vel (+ (. player :y-vel) (* gravity dt)))) + + ;; Perform collision detection and update the player's position accordingly. + (let [goal-x (+ (. player :x-pos) (* dt (. player :x-vel))) + goal-y (+ (. player :y-pos) (* dt (. player :y-vel)))] + (let [(x y collisions length) (: collision-map :move player goal-x goal-y)] + (tset player :x-pos x) + (tset player :y-pos y) + + (tset player :grounded false) + (each [_ collision (ipairs collisions)] + (let [tile (. collision :other)] + ;; Touching top. + (when (> 0 (. collision :normal :y)) + (tset tile :slimed :top true) + (tset player :grounded true)) + + ;; Touching bottom. + (when (< 0 (. collision :normal :y)) + (tset tile :slimed :bottom true)) + + ;; Touching left. + (when (> 0 (. collision :normal :x)) + (tset tile :slimed :left true)) + + ;; Touching right. + (when (< 0 (. collision :normal :x)) + (tset tile :slimed :right true))))))) + + +(fn keypressed [key set-mode] + (when (= key "right") + (player-turn-right player)) + + (when (= key "left") + (player-turn-left player)) + + (when (= key "z") + (tset player :action :jump true))) + +(fn keyreleased [key set-mode] + (when (= key "right") + (tset player :action :right false)) + + (when (= key "left") + (tset player :action :left false)) + + (when (= key "z") + (tset player :action :jump false))) + +{:draw draw + :update update + :keypressed keypressed + :keyreleased keyreleased} @@ -15,20 +15,43 @@ ;;;; You should have received a copy of the GNU General Public License along ;;;; with swanky. If not, see <http://www.gnu.org/licenses/>. -(local tileset-values +(local tiles + {:img (love.graphics.newImage "art/tiles.png") + :width 32 :height 32 + :padding-x 8 :padding-y 8 + :offsets {:bricks 0}}) + +(local tile-values {:empty [1 0 0 0] :bricks [0 0 0 1]}) -;; Returns the keyword for a given tile pixel. +(local slime + {:img (love.graphics.newImage "art/slime.png") + :width 32 :height 32 + :padding-x 8 :padding-y 8 + :offsets {:top 0 :bottom 1 :left 2 :right 3}}) + +;; Creates a new tile object of the given `type-type' positioned at world +;; coordinates (`x', `y'). +(fn make-tile [tile-type x y] + {:x-pos x + :y-pos y + :type tile-type + :slimed {:top false + :bottom false + :left false + :right false}}) + +;; Returns the tile object for a given pixel in `image'. (fn get-tile [image x y] - (var res :empty) + (var res (make-tile :empty (* x (. tiles :width)) (* y (. tiles :width)))) (let [(r g b a) (: image :getPixel x y)] - (each [name colors (pairs tileset-values)] + (each [tile-type colors (pairs tile-values)] (when (and (= (. colors 1) r) (= (. colors 2) g) (= (. colors 3) b) (= (. colors 4) a)) - (set res name)))) + (tset res :type tile-type)))) res) ;; Loads the tile layout of the level from the given ImageData, returning a @@ -44,20 +67,13 @@ (table.insert tiles row)) (values tiles width height))) -;; (for [y 0 (- height 1)] -;; (for [x 0 (- width 1)] -;; (let [tile (. tiles (+ 1 y) (+ 1 x))] -;; (if (= tile :empty) -;; (io.write " ") -;; :else -;; (io.write "b")))) -;; (print)) - ;; Returns the metadata and objects stored in the metadata file at the given ;; path. (fn load-meta [path] (fennel.dofile path)) +;; Loads the map of the given name. Will error out if either 'maps/${name}.png' +;; or 'maps/${name}.fnl' do not exist. (fn load [name] (let [tiles-path (.. "maps/" name ".png") meta-path (.. "maps/" name ".fnl")] @@ -67,4 +83,6 @@ :height height :meta (load-meta meta-path)}))) -{:load load} +{:tiles tiles + :slime slime + :load load} diff --git a/sandbox.fnl b/sandbox.fnl deleted file mode 100644 index b5f84a6..0000000 --- a/sandbox.fnl +++ /dev/null @@ -1,256 +0,0 @@ -;;;; Copyright (C) 2018 Jakob L. Kreuze, All Rights Reserved. -;;;; -;;;; This file is part of swanky. -;;;; -;;;; swanky is free software: you can redistribute it and/or modify it under the -;;;; terms of the GNU General Public License as published by the Free Software -;;;; Foundation, either version 3 of the License, or (at your option) any later -;;;; version. -;;;; -;;;; swanky is distributed in the hope that it will be useful, but WITHOUT ANY -;;;; WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -;;;; FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -;;;; details. -;;;; -;;;; You should have received a copy of the GNU General Public License along -;;;; with swanky. If not, see <http://www.gnu.org/licenses/>. - -(local bump (require :lib.bump)) -(local lume (require :lib.lume)) - -(local map (require :map)) - -(local sandbox (map.load "sandbox")) - -(local tiles (love.graphics.newImage "art/tiles.png")) -(local tile-width 32) -(local tile-height 32) -(local tile-offsets {:bricks 0}) - -;; Drawing routine for rendering the tiles visible from a given camera offset. -(fn draw-tiles [map camera-x camera-y] - (let [how-many-x (math.ceil (+ 3 (/ screen-width tile-width))) ; fixme: why +3? - how-many-y (math.ceil (+ 2 (/ screen-height tile-height))) ; fixme: why +2? - start-x (math.floor (/ camera-x tile-width)) - start-y (math.floor (/ camera-y tile-height)) - width (. map :width) - height (. map :height)] - (for [x 0 how-many-x] - (for [y 0 how-many-y] - (each [tile offset (pairs tile-offsets)] - (when (and (and (>= (+ x start-x) 0) (< (+ x start-x) width)) - (and (>= (+ y start-y) 0) (< (+ y start-y) height)) - (= tile (. map :tiles (+ y start-y 1) (+ x start-x 1)))) - (let [x (- (* x tile-width) (% camera-x tile-width)) - y (- (* y tile-height) (% camera-y tile-height)) - quad (love.graphics.newQuad (* tile-width offset) - 0 - tile-width - tile-height - (: tiles :getWidth) - (: tiles :getHeight))] - (love.graphics.draw tiles quad x y)))))))) - -;; (local swanky-tile-width 32) -;; (local swanky-tile-height 32) -;; (local swanky-width 24) -;; (local swanky-height 22) - -;; Okay, here are the things we need to keep track of: -;; - Camera -;; - camera-x -;; - camera-y -;; - camera-x-velocity -;; - camera-y-velocity -;; -;; - Player -;; - orientation (right vs left) -;; - x -;; - y -;; - x-velocity -;; - y-velocity -;; - goal-x-velocity -;; - goal-y-velocity -;; - Whether or not is grounded -;; - Jumping (?) -;; - The current action (moving right, etc.) -;; -;; - Animations -;; - offsets -;; - whether or not to sustain -;; - number of frames - -;; --- - -(local swanky-animation-offsets {:idle 0 - :jump 2 - :fall 3}) -(local swanky-animation-sustains {:idle false - :jump true - :fall false}) -(local swanky-animation-frame-counts {:idle 2 - :jump 4 - :fall 4}) - -(local swanky (love.graphics.newImage "art/swanky.png")) -(local swanky-width 32) -(local swanky-height 32) - -(fn draw-swanky [x y animation frame orientation] - (let [x-offset (+ (* frame swanky-width) - (if (= orientation :left) (* 4 swanky-width) 0)) - y-offset (* (. swanky-animation-offsets animation) swanky-height)] - (let [quad (love.graphics.newQuad x-offset - y-offset - swanky-width - swanky-height - (: swanky :getWidth) - (: swanky :getHeight))] - (love.graphics.draw swanky quad x y)))) - -(var swanky-orientation :right) - -(local swanky-animation-frame-delay 16) -(var swanky-animation-frame-timer swanky-animation-frame-delay) -(var swanky-animation-frame 0) -(var swanky-animation :idle) - -(var swanky-animation-stack []) - -(var swanky-x 128) -(var swanky-y 128) -(var swanky-x-vel 0) -(var swanky-y-vel 0) - -(var swanky-moving-right false) -(var swanky-moving-left false) - -(local swanky-x-vel-goal 128) -(local swanky-y-vel-goal 128) - -(var swanky-jumping false) -(var swanky-grounded false) -(var swanky-should-play-grounding-animation true) - -(var gravity 128) - -(var camera-x 64) -(var camera-y 64) -(var camera-x-vel 0) -(var camera-y-vel 0) - -(local camera-lock-goal-x (math.floor (+ (/ screen-width 2) (/ swanky-width 2)))) -(local camera-lock-goal-y (math.floor (+ (/ screen-height 2) (/ swanky-height 2)))) - -(local world (bump.newWorld 32)) -(: world :add :swanky swanky-x swanky-y swanky-width swanky-height) - -(for [x 0 (- (. sandbox :width) 1)] - (for [y 0 (- (. sandbox :height) 1)] - (let [tile (. sandbox :tiles (+ 1 y) (+ 1 x))] - (when (~= :empty tile) - (: world :add [tile] (* x tile-width) (* y tile-height) tile-width tile-height))))) - -(fn draw [message] - (love.graphics.clear 1 1 1) - (draw-tiles sandbox camera-x camera-y) - (let [x (- swanky-x camera-x) - y (- swanky-y camera-y)] - (draw-swanky x y swanky-animation swanky-animation-frame swanky-orientation))) - -(fn update [dt set-mode] - ;; Update animations. - (when (< 0 (# swanky-animation-stack)) - (set swanky-animation (table.remove swanky-animation-stack (# swanky-animation-stack))) - (set swanky-animation-frame 0)) - - (when (> 0 swanky-animation-frame-timer) - (let [frame-count (. swanky-animation-frame-counts swanky-animation) - sustain (. swanky-animation-sustains swanky-animation)] - (if (and (= frame-count (+ 1 swanky-animation-frame)) (not sustain)) - (do - (set swanky-animation-frame 0) - (when (~= swanky-animation :idle) - (set swanky-animation :idle))) - (> frame-count (+ 1 swanky-animation-frame)) - (set swanky-animation-frame (+ 1 swanky-animation-frame)))) - (set swanky-animation-frame-timer swanky-animation-frame-delay)) - - (set swanky-animation-frame-timer (- swanky-animation-frame-timer (* 64 dt))) - - ;; Update camera. - (set camera-x (lume.lerp camera-x (- swanky-x camera-lock-goal-x) dt)) - (set camera-y (lume.lerp camera-y (- swanky-y camera-lock-goal-y) dt)) - - ;; Lock camera so that it doesn't go out of bounds. - (when (> 0 camera-x) - (set camera-x 0)) - - (when (> 0 camera-y) - (set camera-y 0)) - - (when (>= camera-x (- (* tile-width (- (. sandbox :width) 3)) screen-width)) - (set camera-x (- (* tile-width (- (. sandbox :width) 3)) screen-width))) - - (when (>= camera-y (- (* tile-height (- (. sandbox :height) 2)) screen-height)) - (set camera-y (- (* tile-height (- (. sandbox :height) 2)) screen-height))) - - ;; Update the swanky's velocities to reflect controls. - (let [swanky-x-vel-goal (if swanky-moving-right swanky-x-vel-goal - swanky-moving-left (- swanky-x-vel-goal) - 0)] - (set swanky-x-vel (lume.lerp swanky-x-vel swanky-x-vel-goal dt))) - - (when (and swanky-jumping swanky-grounded) - (set swanky-y-vel (- swanky-y-vel swanky-y-vel-goal))) - - ;; Update the y-velocity to reflect gravity. - (if (and swanky-grounded (not swanky-jumping)) - (set swanky-y-vel 0) - (set swanky-y-vel (+ swanky-y-vel (* gravity dt)))) - - (when (and (> 0 swanky-y-vel) (not swanky-grounded)) - (set swanky-should-play-grounding-animation true)) - - ;; Calculate the goal position for swanky. - (set swanky-x (+ swanky-x (* dt swanky-x-vel))) - (set swanky-y (+ swanky-y (* dt swanky-y-vel))) - - ;; Perform collision detection and update swanky's position accordingly - (let [(actual-x actual-y collisions length) (: world :move :swanky swanky-x swanky-y)] - (set swanky-x actual-x) - (set swanky-y actual-y) - (set swanky-grounded false) - (each [_ collision (ipairs collisions)] - (when (> 0 (. collision :normal :y)) - (set swanky-grounded true) - (when swanky-should-play-grounding-animation - (table.insert swanky-animation-stack :fall) - (set swanky-should-play-grounding-animation false)))))) - -(fn keypressed [key set-mode] - (if (= key "d") - (do (set swanky-moving-right true) - (set swanky-orientation :right)) - (= key "a") - (do (set swanky-moving-left true) - (set swanky-orientation :left)) - (= key "w") - (do - (set swanky-jumping true) - (set swanky-animation :jump)))) - -(fn keyreleased [key set-mode] - (if (= key "d") - (do (set swanky-x-vel (/ swanky-x-vel 2)) - (set swanky-moving-right false)) - (= key "a") - (do (set swanky-x-vel (/ swanky-x-vel 2)) - (set swanky-moving-left false)) - (= key "w") - (set swanky-jumping false))) - -{:draw draw - :update update - :keypressed keypressed - :keyreleased keyreleased} @@ -35,7 +35,7 @@ "abcdefghijklmnopqrstuvwxyz" "[\\]^_`{|}~"))) -(var mode (require :sandbox)) +(var mode (require :game)) (fn set-mode [mode-name ...] (set mode (require mode-name)) @@ -44,7 +44,8 @@ (fn love.load [] (: canvas :setFilter "nearest" "nearest") - (love.graphics.setFont font)) + (love.graphics.setFont font) + (love.window.setMode canvas-width canvas-height {})) (fn love.draw [] (love.graphics.setCanvas canvas) @@ -78,3 +79,6 @@ (fn love.keyreleased [key] (mode.keyreleased key set-mode)) + +(fn love.gamepadpressed [_ button] + (print button)) |