Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add Warper City atlas loader and initial animations |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | lisp-game-jam-2020 |
Files: | files | file ages | folders |
SHA3-256: |
02b8ba3fe4bd29d7613f92b22823bb26 |
User & Date: | chewbranca 2020-04-16 05:39:05 |
Context
2020-04-18
| ||
21:45 | Initial state logic and wip camera sacling check-in: 35d9508f68 user: chewbranca tags: lisp-game-jam-2020 | |
2020-04-16
| ||
05:39 | Add Warper City atlas loader and initial animations check-in: 02b8ba3fe4 user: chewbranca tags: lisp-game-jam-2020 | |
2020-04-13
| ||
20:06 | Add initial prototype with https://ansimuz.itch.io/warped-city assets check-in: a6620266bc user: chewbranca tags: lisp-game-jam-2020 | |
Changes
Added src/fahombo/lib/anim8.lua.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 |
local anim8 = { _VERSION = 'anim8 v2.3.1', _DESCRIPTION = 'An animation library for LÖVE', _URL = 'https://github.com/kikito/anim8', _LICENSE = [[ MIT LICENSE Copyright (c) 2011 Enrique García Cota Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ]] } local Grid = {} local _frames = {} local function assertPositiveInteger(value, name) if type(value) ~= 'number' then error(("%s should be a number, was %q"):format(name, tostring(value))) end if value < 1 then error(("%s should be a positive number, was %d"):format(name, value)) end if value ~= math.floor(value) then error(("%s should be an integer, was %d"):format(name, value)) end end local function createFrame(self, x, y) local fw, fh = self.frameWidth, self.frameHeight return love.graphics.newQuad( self.left + (x-1) * fw + x * self.border, self.top + (y-1) * fh + y * self.border, fw, fh, self.imageWidth, self.imageHeight ) end local function getGridKey(...) return table.concat( {...} ,'-' ) end local function getOrCreateFrame(self, x, y) if x < 1 or x > self.width or y < 1 or y > self.height then error(("There is no frame for x=%d, y=%d"):format(x, y)) end local key = self._key _frames[key] = _frames[key] or {} _frames[key][x] = _frames[key][x] or {} _frames[key][x][y] = _frames[key][x][y] or createFrame(self, x, y) return _frames[key][x][y] end local function parseInterval(str) if type(str) == "number" then return str,str,1 end str = str:gsub('%s', '') -- remove spaces local min, max = str:match("^(%d+)-(%d+)$") assert(min and max, ("Could not parse interval from %q"):format(str)) min, max = tonumber(min), tonumber(max) local step = min <= max and 1 or -1 return min, max, step end function Grid:getFrames(...) local result, args = {}, {...} local minx, maxx, stepx, miny, maxy, stepy for i=1, #args, 2 do minx, maxx, stepx = parseInterval(args[i]) miny, maxy, stepy = parseInterval(args[i+1]) for y = miny, maxy, stepy do for x = minx, maxx, stepx do result[#result+1] = getOrCreateFrame(self,x,y) end end end return result end local Gridmt = { __index = Grid, __call = Grid.getFrames } local function newGrid(frameWidth, frameHeight, imageWidth, imageHeight, left, top, border) assertPositiveInteger(frameWidth, "frameWidth") assertPositiveInteger(frameHeight, "frameHeight") assertPositiveInteger(imageWidth, "imageWidth") assertPositiveInteger(imageHeight, "imageHeight") left = left or 0 top = top or 0 border = border or 0 local key = getGridKey(frameWidth, frameHeight, imageWidth, imageHeight, left, top, border) local grid = setmetatable( { frameWidth = frameWidth, frameHeight = frameHeight, imageWidth = imageWidth, imageHeight = imageHeight, left = left, top = top, border = border, width = math.floor(imageWidth/frameWidth), height = math.floor(imageHeight/frameHeight), _key = key }, Gridmt ) return grid end ----------------------------------------------------------- local Animation = {} local function cloneArray(arr) local result = {} for i=1,#arr do result[i] = arr[i] end return result end local function parseDurations(durations, frameCount) local result = {} if type(durations) == 'number' then for i=1,frameCount do result[i] = durations end else local min, max, step for key,duration in pairs(durations) do assert(type(duration) == 'number', "The value [" .. tostring(duration) .. "] should be a number") min, max, step = parseInterval(key) for i = min,max,step do result[i] = duration end end end if #result < frameCount then error("The durations table has length of " .. tostring(#result) .. ", but it should be >= " .. tostring(frameCount)) end return result end local function parseIntervals(durations) local result, time = {0},0 for i=1,#durations do time = time + durations[i] result[i+1] = time end return result, time end local Animationmt = { __index = Animation } local nop = function() end local function newAnimation(frames, durations, onLoop) local td = type(durations); if (td ~= 'number' or durations <= 0) and td ~= 'table' then error("durations must be a positive number. Was " .. tostring(durations) ) end onLoop = onLoop or nop durations = parseDurations(durations, #frames) local intervals, totalDuration = parseIntervals(durations) return setmetatable({ frames = cloneArray(frames), durations = durations, intervals = intervals, totalDuration = totalDuration, onLoop = onLoop, timer = 0, position = 1, status = "playing", flippedH = false, flippedV = false }, Animationmt ) end function Animation:clone() local newAnim = newAnimation(self.frames, self.durations, self.onLoop) newAnim.flippedH, newAnim.flippedV = self.flippedH, self.flippedV return newAnim end function Animation:flipH() self.flippedH = not self.flippedH return self end function Animation:flipV() self.flippedV = not self.flippedV return self end local function seekFrameIndex(intervals, timer) local high, low, i = #intervals-1, 1, 1 while(low <= high) do i = math.floor((low + high) / 2) if timer >= intervals[i+1] then low = i + 1 elseif timer < intervals[i] then high = i - 1 else return i end end return i end function Animation:update(dt) if self.status ~= "playing" then return end self.timer = self.timer + dt local loops = math.floor(self.timer / self.totalDuration) if loops ~= 0 then self.timer = self.timer - self.totalDuration * loops local f = type(self.onLoop) == 'function' and self.onLoop or self[self.onLoop] f(self, loops) end self.position = seekFrameIndex(self.intervals, self.timer) end function Animation:pause() self.status = "paused" end function Animation:gotoFrame(position) self.position = position self.timer = self.intervals[self.position] end function Animation:pauseAtEnd() self.position = #self.frames self.timer = self.totalDuration self:pause() end function Animation:pauseAtStart() self.position = 1 self.timer = 0 self:pause() end function Animation:resume() self.status = "playing" end function Animation:draw(image, x, y, r, sx, sy, ox, oy, kx, ky) love.graphics.draw(image, self:getFrameInfo(x, y, r, sx, sy, ox, oy, kx, ky)) end function Animation:getFrameInfo(x, y, r, sx, sy, ox, oy, kx, ky) local frame = self.frames[self.position] if self.flippedH or self.flippedV then r,sx,sy,ox,oy,kx,ky = r or 0, sx or 1, sy or 1, ox or 0, oy or 0, kx or 0, ky or 0 local _,_,w,h = frame:getViewport() if self.flippedH then sx = sx * -1 ox = w - ox kx = kx * -1 ky = ky * -1 end if self.flippedV then sy = sy * -1 oy = h - oy kx = kx * -1 ky = ky * -1 end end return frame, x, y, r, sx, sy, ox, oy, kx, ky end function Animation:getDimensions() local _,_,w,h = self.frames[self.position]:getViewport() return w,h end ----------------------------------------------------------- anim8.newGrid = newGrid anim8.newAnimation = newAnimation return anim8 |
Changes to src/fahombo/play.fnl.
1 2 3 4 5 6 7 8 9 10 11 .. 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 .. 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 ... 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
;; This is a Fennel implementation of http://www.osmstudios.com/tutorials/love2d-platformer-tutorial-part-1-the-basics (local sti (require "lib.sti")) (local bump (require "lib.bump")) (local game-width 384) (local game-height 224) (local bg-1 (love.graphics.newImage "assets/warped_city/environment/bg-1.png")) (local bg-2 (love.graphics.newImage "assets/warped_city/environment/bg-2.png")) (local bg-3 (love.graphics.newImage "assets/warped_city/environment/bg-3.png")) ................................................................................ :isJumping false ;; are we in the process of jumping? :isGrounded false ;; are we on the ground? :hasReachedMax false ;; is this as high as we can go? :jumpAcc 500 ;; how fast do we accelerate towards the top :jumpMaxSpeed 9.5 ;; our speed limit while jumping ;; Here are some incidental storage areas :img player-img}) ;; store the sprite we'll be drawing (local map (sti "map.lua" ["bump"])) ;; TODO: add lint wrapper (local world (bump.newWorld 16)) (local ground-0 {}) (local ground-1 {}) ................................................................................ other-bottom (+ y h)] (if (<= player-bottom y) :slide)))) (fn update [dt set-mode] (let [goal-x (+ player.x player.xVelocity) goal-y (+ player.y player.yVelocity) (x y cols) (: world :move player goal-x goal-y player.filter)] (set player.x (lume.clamp x 5 1000)) (set player.y y) (each [i col (ipairs cols)] (if (> col.touch.y goal-y) (do (set player.hasReachedMax true) ................................................................................ (fn draw [map world player] (let [w (love.graphics.getWidth) h (love.graphics.getHeight) iw (: bg-1 :getWidth) ih (: bg-1 :getHeight) sw (/ w iw) sh (/ h ih)] (love.graphics.draw bg-1 0 0 0 sw sh) (love.graphics.draw bg-2 0 0 0 sw sh) (love.graphics.draw bg-3 0 0 0 sw sh)) (: map :draw) (love.graphics.draw player.img player.x player.y) (let [(x0 y0 w0 h0) (: world :getRect ground-0) (x1 y1 w1 h1) (: world :getRect ground-1)] (love.graphics.rectangle "fill" x0 y0 w0 h0) (love.graphics.rectangle "fill" x1 y1 w1 h1))) {:draw (partial draw map world player) :update update :keypressed keypressed} |
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > | > > > > | > |
1 2 3 4 5 6 7 8 9 10 11 12 .. 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 .. 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 ... 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
;; This is a Fennel implementation of http://www.osmstudios.com/tutorials/love2d-platformer-tutorial-part-1-the-basics (local anim8 (require "lib.anim8")) (local bump (require "lib.bump")) (local sti (require "lib.sti")) (local game-width 384) (local game-height 224) (local bg-1 (love.graphics.newImage "assets/warped_city/environment/bg-1.png")) (local bg-2 (love.graphics.newImage "assets/warped_city/environment/bg-2.png")) (local bg-3 (love.graphics.newImage "assets/warped_city/environment/bg-3.png")) ................................................................................ :isJumping false ;; are we in the process of jumping? :isGrounded false ;; are we on the ground? :hasReachedMax false ;; is this as high as we can go? :jumpAcc 500 ;; how fast do we accelerate towards the top :jumpMaxSpeed 9.5 ;; our speed limit while jumping ;; Here are some incidental storage areas :am-state :walk ;; player animation :img player-img}) ;; store the sprite we'll be drawing (local atlas-data (require "assets/warped_city/atlas/atlas")) (local atlas-tile (love.graphics.newImage "assets/warped_city/atlas/atlas.png")) ;; apparently this helps for scaling (: atlas-tile :setFilter "nearest" "linear") (local atlas-quads {}) (local atlas-imgs {}) (local atlas-ams {}) (local atlas-ams-imgs {}) ;; process atlas definition (let [(tw th) (: atlas-tile :getDimensions)] (each [i frame (ipairs atlas-data.frames)] (let [name frame.filename x frame.frame.x y frame.frame.y w frame.frame.w h frame.frame.h quad (love.graphics.newQuad x y w h tw th)] (if ;; annimation images end in the frame number (string.match name "^(.*)(-%d+)$") (let [(group scount) (string.match name "^(.*)-(%d+)$") count (tonumber scount)] (when (not (. atlas-ams-imgs group)) (tset atlas-ams-imgs group [])) (table.insert (. atlas-ams-imgs group) quad) (assert (= (length (. atlas-ams-imgs group)) count))) ;; other images (string.match name "[a-z]$") (tset atlas-imgs name quad))))) ;; create animations (each [name quads (pairs atlas-ams-imgs)] (let [am (anim8.newAnimation quads 0.1)] (tset atlas-ams name am))) (local map (sti "map.lua" ["bump"])) ;; TODO: add lint wrapper (local world (bump.newWorld 16)) (local ground-0 {}) (local ground-1 {}) ................................................................................ other-bottom (+ y h)] (if (<= player-bottom y) :slide)))) (fn update [dt set-mode] (let [goal-x (+ player.x player.xVelocity) goal-y (+ player.y player.yVelocity) (x y cols) (: world :move player goal-x goal-y player.filter) am (. atlas-ams player.am-state)] (: am :update dt) (set player.x (lume.clamp x 5 1000)) (set player.y y) (each [i col (ipairs cols)] (if (> col.touch.y goal-y) (do (set player.hasReachedMax true) ................................................................................ (fn draw [map world player] (let [w (love.graphics.getWidth) h (love.graphics.getHeight) iw (: bg-1 :getWidth) ih (: bg-1 :getHeight) sw (/ w iw) sh (/ h ih) am (. atlas-ams player.am-state)] (love.graphics.draw bg-1 0 0 0 sw sh) (love.graphics.draw bg-2 0 0 0 sw sh) (love.graphics.draw bg-3 0 0 0 sw sh)) (: map :draw) (let [p-img atlas-quads.walk-5 p-am atlas-ams.walk] ;; TODO: switch to drawing with a spritebatch ;;(love.graphics.draw atlas-tile p-img player.x player.y)) (: p-am :draw atlas-tile player.x player.y)) (let [(x0 y0 w0 h0) (: world :getRect ground-0) (x1 y1 w1 h1) (: world :getRect ground-1)] (love.graphics.rectangle "fill" x0 y0 w0 h0) (love.graphics.rectangle "fill" x1 y1 w1 h1))) {:draw (partial draw map world player) :update update :keypressed keypressed} |