diff options
author | chai <chaifix@163.com> | 2018-09-02 19:49:27 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2018-09-02 19:49:27 +0800 |
commit | cf608a2af7106f9901bc0632c96594d2c938b416 (patch) | |
tree | ad18a2edd0c8e1bc26e668d321d24af34ff3ac25 | |
parent | 340861d2a5e4391e2f1671663f6812f1228a4c78 (diff) |
*update
-rw-r--r-- | Base64/Base64.lua | 178 | ||||
-rw-r--r-- | bump/.gitignore | 1 | ||||
-rw-r--r-- | bump/MIT-LICENSE.txt | 20 | ||||
-rw-r--r-- | bump/README.md | 14 | ||||
-rw-r--r-- | bump/bump.lua | 773 | ||||
-rw-r--r-- | bump/bump_debug.lua | 31 | ||||
-rw-r--r-- | bump/config.lua | 6 | ||||
-rw-r--r-- | bump/main.lua | 163 | ||||
-rw-r--r-- | json/README.md | 0 | ||||
-rw-r--r-- | json/json.lua | 400 | ||||
-rw-r--r-- | log/log.lua (renamed from log/init.lua) | 2 | ||||
-rw-r--r-- | main.lua | 94 | ||||
-rw-r--r-- | tiled/atlas.png | bin | 0 -> 10939 bytes | |||
-rw-r--r-- | tiled/eventset.png | bin | 0 -> 548 bytes | |||
-rw-r--r-- | tiled/map1.tmx | 69 | ||||
-rw-r--r-- | tiled/map2.tmx | 83 | ||||
-rw-r--r-- | tiled/map3.tmx | 74 | ||||
-rw-r--r-- | tiled/map4.tmx | 105 | ||||
-rw-r--r-- | tiled/map5.tmx | 110 | ||||
-rw-r--r-- | tiled/map6.tmx | 120 | ||||
-rw-r--r-- | tiled/signs.png | bin | 0 -> 348 bytes | |||
-rw-r--r-- | tiled/signs_OLD.png | bin | 0 -> 271 bytes | |||
-rw-r--r-- | tiled/tiled.lua | 244 | ||||
-rw-r--r-- | tiled/tileset.png | bin | 0 -> 6340 bytes |
24 files changed, 2391 insertions, 96 deletions
diff --git a/Base64/Base64.lua b/Base64/Base64.lua new file mode 100644 index 0000000..33e78bd --- /dev/null +++ b/Base64/Base64.lua @@ -0,0 +1,178 @@ +--------------------------------------------------------------------------------------------------- +-- -= Base64 =- +--------------------------------------------------------------------------------------------------- + +-- Make some functions easier to write +local floor = math.floor +local sub = string.sub +local gsub = string.gsub +local rem = table.remove + +--------------------------------------------------------------------------------------------------- +-- Our base64 value table +local base64 = { ['A']=0,['B']=1,['C']=2,['D']=3,['E']=4,['F']=5,['G']=6,['H']=7,['I']=8, + ['J']=9,['K']=10,['L']=11,['M']=12,['N']=13,['O']=14,['P']=15,['Q']=16, + ['R']=17,['S']=18,['T']=19,['U']=20,['V']=21,['W']=22,['X']=23,['Y']=24, + ['Z']=25,['a']=26,['b']=27,['c']=28,['d']=29,['e']=30,['f']=31,['g']=32, + ['h']=33,['i']=34,['j']=35,['k']=36,['l']=37,['m']=38,['n']=39,['o']=40, + ['p']=41,['q']=42,['r']=43,['s']=44,['t']=45,['u']=46,['v']=47,['w']=48, + ['x']=49,['y']=50,['z']=51,['0']=52,['1']=53,['2']=54,['3']=55,['4']=56, + ['5']=57,['6']=58,['7']=59,['8']=60,['9']=61,['+']=62,['/']=63,['=']=nil} + +--------------------------------------------------------------------------------------------------- +-- Decimal values for binary digits +local bin ={} +local mult = 1 +for i = 1,40 do + bin[i] = mult + mult = mult*2 +end + +--------------------------------------------------------------------------------------------------- +-- A buffer we will use to process the bits +local buffer = 0 +local pos = 0 +local function clearBuffer() + buffer = 0 + pos = 1 +end + +--------------------------------------------------------------------------------------------------- +-- Shift all of the bits up in the buffer and put the base64 number on the bottom +local function pushBase64(n) + if base64[n] == nil then return end + buffer = buffer * bin[7] + base64[n] + pos = pos + 6 +end + +--------------------------------------------------------------------------------------------------- +-- Get an int out of the buffer. This is tricky. The byte order is in little endian so we're going +-- to have to isolate and cut the bytes out and then move them around. +local function getInt() + -- If our buffer isn't filled all the way then fill it with zeros + while pos < 33 do + buffer = buffer * bin[2] + pos = pos + 1 + end + -- Move the buffer position to just below the integer. + pos = pos - 32 + + -- Swap the first and forth byte and then the second and third. + local tmp = floor((buffer%bin[33+pos-1])/bin[25+pos-1]) + + floor((buffer%bin[25+pos-1])/bin[17+pos-1])*bin[9] + + floor((buffer%bin[17+pos-1])/bin[9+pos-1])*bin[17] + + floor((buffer%bin[9+pos-1])/bin[pos])*bin[25] + + -- We've got our integer so let's cut that portion out of the buffer + buffer = buffer % bin[pos] + -- Return the int + return tmp +end + +--------------------------------------------------------------------------------------------------- +-- Get a byte out of the buffer +local function getByte() + -- If our buffer isn't filled all the way then fill it with zeros + while pos < 9 do + buffer = buffer * bin[2] + pos = pos + 1 + end + -- Move the buffer position to just below the byte. + pos = pos - 8 + -- Cut out the byte + local tmp = floor((buffer%bin[9+pos-1])/bin[pos]) + -- Delete the byte from the buffer + buffer = buffer % bin[pos] + -- Return the byte + return tmp +end + +--------------------------------------------------------------------------------------------------- +-- Glues together an integer from four bytes. Little endian +local function glueInt(b1, b2, b3, b4) + return b1%bin[9] + b2%bin[9]*bin[9] + b3%bin[9]*bin[17] + b4%bin[9]*bin[25] +end + +--------------------------------------------------------------------------------------------------- +-- A Lua set that will filter out characters that aren't in the base64 table +local set = "[^%a%d%+%/%=]" + +--------------------------------------------------------------------------------------------------- +-- Decodes a base64 string into the given type +local function decode(mode, raw) + + -- Make sure the mode is supported + assert(mode=="string" or mode=="int" or mode=="byte", "Base64 decode - Invalid mode: " .. mode) + + -- Clear the buffer + clearBuffer() + + -- Filters undefined characters out of the string + raw = gsub(raw, set, "") + + local size = 0 -- Size of the returned type in bits + local val = {} -- A table containing the data to be returned + local raw_pos = 1 -- The position of the progress through the raw base64 string + local raw_size = #raw -- The size of the base64 string + local char = "" -- The current base64 character to be processed + + -- If we're expected to return an int then the bit size is 32, otherwise it's 8 + if mode == "int" then size = 32 else size = 8 end + + -- While we still have input + while raw_pos <= raw_size do + -- Fill the buffer until we have enough bits + while pos <= size and raw_pos <= raw_size do + char = sub(raw,raw_pos,raw_pos) + pushBase64( char ) + raw_pos = raw_pos + 1 + end + -- If a nil character is encountered the end the loop + if char == "=" then break end + -- Get data from the buffer depending on the type + if mode == "string" then val[#val+1] = string.char( getByte() ) end + if mode == "byte" then val[#val+1] = getByte() end + if mode == "int" then val[#val+1] = getInt() end + end + + if mode == "string" then return table.concat(val) end + return val +end + +--------------------------------------------------------------------------------------------------- +-- Encodes a table of ints into a base64 string. +local function encode(ints) + + -- Clear the buffer + clearBuffer() + + local size = 0 -- Size of the returned type in bits + local val = {} -- A table containing the data to be returned + local char = "" -- The current base64 character to be processed + + -- If we're expected to return an int then the bit size is 32, otherwise it's 8 + if mode == "int" then size = 32 else size = 8 end + + -- While we still have input + while raw_pos <= raw_size do + -- Fill the buffer until we have enough bits + while pos <= size and raw_pos <= raw_size do + char = sub(raw,raw_pos,raw_pos) + pushBase64( char ) + raw_pos = raw_pos + 1 + end + -- If a nil character is encountered the end the loop + if char == "=" then break end + -- Get data from the buffer depending on the type + if mode == "string" then val[#val+1] = string.char( getByte() ) end + if mode == "byte" then val[#val+1] = getByte() end + if mode == "int" then val[#val+1] = getInt() end + end + + if mode == "string" then return table.concat(val) end + return val +end + +--------------------------------------------------------------------------------------------------- +-- Returns the functions +return {decode = decode, glueInt = glueInt, base64 = base64}
\ No newline at end of file diff --git a/bump/.gitignore b/bump/.gitignore new file mode 100644 index 0000000..3159fbe --- /dev/null +++ b/bump/.gitignore @@ -0,0 +1 @@ +*.love diff --git a/bump/MIT-LICENSE.txt b/bump/MIT-LICENSE.txt new file mode 100644 index 0000000..2e015c6 --- /dev/null +++ b/bump/MIT-LICENSE.txt @@ -0,0 +1,20 @@ +Copyright (c) 2012 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. diff --git a/bump/README.md b/bump/README.md new file mode 100644 index 0000000..17521c7 --- /dev/null +++ b/bump/README.md @@ -0,0 +1,14 @@ +# bump.lua simple demo + +This is the simple demo of [bump.lua](http://github.com/kikito/bump.lua) + +It requires [LÖVE](http://love2d.org) to work properly. + +This simple demo creates a world populated by random boxes, and allows to move a player around using the keyboard arrow keys. The player has constant velocity +and can will "slide" over the boxes without penetrating them, similarly to some classic games such as Zelda. + +Pressing TAB will display some debug information. + + + + diff --git a/bump/bump.lua b/bump/bump.lua new file mode 100644 index 0000000..6dabca7 --- /dev/null +++ b/bump/bump.lua @@ -0,0 +1,773 @@ +local bump = { + _VERSION = 'bump v3.1.7', + _URL = 'https://github.com/kikito/bump.lua', + _DESCRIPTION = 'A collision detection library for Lua', + _LICENSE = [[ + MIT LICENSE + + Copyright (c) 2014 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. + ]] +} + +------------------------------------------ +-- Auxiliary functions +------------------------------------------ +local DELTA = 1e-10 -- floating-point margin of error + +local abs, floor, ceil, min, max = math.abs, math.floor, math.ceil, math.min, math.max + +local function sign(x) + if x > 0 then return 1 end + if x == 0 then return 0 end + return -1 +end + +local function nearest(x, a, b) + if abs(a - x) < abs(b - x) then return a else return b end +end + +local function assertType(desiredType, value, name) + if type(value) ~= desiredType then + error(name .. ' must be a ' .. desiredType .. ', but was ' .. tostring(value) .. '(a ' .. type(value) .. ')') + end +end + +local function assertIsPositiveNumber(value, name) + if type(value) ~= 'number' or value <= 0 then + error(name .. ' must be a positive integer, but was ' .. tostring(value) .. '(' .. type(value) .. ')') + end +end + +local function assertIsRect(x,y,w,h) + assertType('number', x, 'x') + assertType('number', y, 'y') + assertIsPositiveNumber(w, 'w') + assertIsPositiveNumber(h, 'h') +end + +local defaultFilter = function() + return 'slide' +end + +------------------------------------------ +-- Rectangle functions +------------------------------------------ + +local function rect_getNearestCorner(x,y,w,h, px, py) + return nearest(px, x, x+w), nearest(py, y, y+h) +end + +-- This is a generalized implementation of the liang-barsky algorithm, which also returns +-- the normals of the sides where the segment intersects. +-- Returns nil if the segment never touches the rect +-- Notice that normals are only guaranteed to be accurate when initially ti1, ti2 == -math.huge, math.huge +local function rect_getSegmentIntersectionIndices(x,y,w,h, x1,y1,x2,y2, ti1,ti2) + ti1, ti2 = ti1 or 0, ti2 or 1 + local dx, dy = x2-x1, y2-y1 + local nx, ny + local nx1, ny1, nx2, ny2 = 0,0,0,0 + local p, q, r + + for side = 1,4 do + if side == 1 then nx,ny,p,q = -1, 0, -dx, x1 - x -- left + elseif side == 2 then nx,ny,p,q = 1, 0, dx, x + w - x1 -- right + elseif side == 3 then nx,ny,p,q = 0, -1, -dy, y1 - y -- top + else nx,ny,p,q = 0, 1, dy, y + h - y1 -- bottom + end + + if p == 0 then + if q <= 0 then return nil end + else + r = q / p + if p < 0 then + if r > ti2 then return nil + elseif r > ti1 then ti1,nx1,ny1 = r,nx,ny + end + else -- p > 0 + if r < ti1 then return nil + elseif r < ti2 then ti2,nx2,ny2 = r,nx,ny + end + end + end + end + + return ti1,ti2, nx1,ny1, nx2,ny2 +end + +-- Calculates the minkowsky difference between 2 rects, which is another rect +local function rect_getDiff(x1,y1,w1,h1, x2,y2,w2,h2) + return x2 - x1 - w1, + y2 - y1 - h1, + w1 + w2, + h1 + h2 +end + +local function rect_containsPoint(x,y,w,h, px,py) + return px - x > DELTA and py - y > DELTA and + x + w - px > DELTA and y + h - py > DELTA +end + +local function rect_isIntersecting(x1,y1,w1,h1, x2,y2,w2,h2) + return x1 < x2+w2 and x2 < x1+w1 and + y1 < y2+h2 and y2 < y1+h1 +end + +local function rect_getSquareDistance(x1,y1,w1,h1, x2,y2,w2,h2) + local dx = x1 - x2 + (w1 - w2)/2 + local dy = y1 - y2 + (h1 - h2)/2 + return dx*dx + dy*dy +end + +local function rect_detectCollision(x1,y1,w1,h1, x2,y2,w2,h2, goalX, goalY) + goalX = goalX or x1 + goalY = goalY or y1 + + local dx, dy = goalX - x1, goalY - y1 + local x,y,w,h = rect_getDiff(x1,y1,w1,h1, x2,y2,w2,h2) + + local overlaps, ti, nx, ny + + if rect_containsPoint(x,y,w,h, 0,0) then -- item was intersecting other + local px, py = rect_getNearestCorner(x,y,w,h, 0, 0) + local wi, hi = min(w1, abs(px)), min(h1, abs(py)) -- area of intersection + ti = -wi * hi -- ti is the negative area of intersection + overlaps = true + else + local ti1,ti2,nx1,ny1 = rect_getSegmentIntersectionIndices(x,y,w,h, 0,0,dx,dy, -math.huge, math.huge) + + -- item tunnels into other + if ti1 + and ti1 < 1 + and (abs(ti1 - ti2) >= DELTA) -- special case for rect going through another rect's corner + and (0 < ti1 + DELTA + or 0 == ti1 and ti2 > 0) + then + ti, nx, ny = ti1, nx1, ny1 + overlaps = false + end + end + + if not ti then return end + + local tx, ty + + if overlaps then + if dx == 0 and dy == 0 then + -- intersecting and not moving - use minimum displacement vector + local px, py = rect_getNearestCorner(x,y,w,h, 0,0) + if abs(px) < abs(py) then py = 0 else px = 0 end + nx, ny = sign(px), sign(py) + tx, ty = x1 + px, y1 + py + else + -- intersecting and moving - move in the opposite direction + local ti1, _ + ti1,_,nx,ny = rect_getSegmentIntersectionIndices(x,y,w,h, 0,0,dx,dy, -math.huge, 1) + if not ti1 then return end + tx, ty = x1 + dx * ti1, y1 + dy * ti1 + end + else -- tunnel + tx, ty = x1 + dx * ti, y1 + dy * ti + end + + return { + overlaps = overlaps, + ti = ti, + move = {x = dx, y = dy}, + normal = {x = nx, y = ny}, + touch = {x = tx, y = ty}, + itemRect = {x = x1, y = y1, w = w1, h = h1}, + otherRect = {x = x2, y = y2, w = w2, h = h2} + } +end + +------------------------------------------ +-- Grid functions +------------------------------------------ + +local function grid_toWorld(cellSize, cx, cy) + return (cx - 1)*cellSize, (cy-1)*cellSize +end + +local function grid_toCell(cellSize, x, y) + return floor(x / cellSize) + 1, floor(y / cellSize) + 1 +end + +-- grid_traverse* functions are based on "A Fast Voxel Traversal Algorithm for Ray Tracing", +-- by John Amanides and Andrew Woo - http://www.cse.yorku.ca/~amana/research/grid.pdf +-- It has been modified to include both cells when the ray "touches a grid corner", +-- and with a different exit condition + +local function grid_traverse_initStep(cellSize, ct, t1, t2) + local v = t2 - t1 + if v > 0 then + return 1, cellSize / v, ((ct + v) * cellSize - t1) / v + elseif v < 0 then + return -1, -cellSize / v, ((ct + v - 1) * cellSize - t1) / v + else + return 0, math.huge, math.huge + end +end + +local function grid_traverse(cellSize, x1,y1,x2,y2, f) + local cx1,cy1 = grid_toCell(cellSize, x1,y1) + local cx2,cy2 = grid_toCell(cellSize, x2,y2) + local stepX, dx, tx = grid_traverse_initStep(cellSize, cx1, x1, x2) + local stepY, dy, ty = grid_traverse_initStep(cellSize, cy1, y1, y2) + local cx,cy = cx1,cy1 + + f(cx, cy) + + -- The default implementation had an infinite loop problem when + -- approaching the last cell in some occassions. We finish iterating + -- when we are *next* to the last cell + while abs(cx - cx2) + abs(cy - cy2) > 1 do + if tx < ty then + tx, cx = tx + dx, cx + stepX + f(cx, cy) + else + -- Addition: include both cells when going through corners + if tx == ty then f(cx + stepX, cy) end + ty, cy = ty + dy, cy + stepY + f(cx, cy) + end + end + + -- If we have not arrived to the last cell, use it + if cx ~= cx2 or cy ~= cy2 then f(cx2, cy2) end + +end + +local function grid_toCellRect(cellSize, x,y,w,h) + local cx,cy = grid_toCell(cellSize, x, y) + local cr,cb = ceil((x+w) / cellSize), ceil((y+h) / cellSize) + return cx, cy, cr - cx + 1, cb - cy + 1 +end + +------------------------------------------ +-- Responses +------------------------------------------ + +local touch = function(world, col, x,y,w,h, goalX, goalY, filter) + return col.touch.x, col.touch.y, {}, 0 +end + +local cross = function(world, col, x,y,w,h, goalX, goalY, filter) + local cols, len = world:project(col.item, x,y,w,h, goalX, goalY, filter) + return goalX, goalY, cols, len +end + +local slide = function(world, col, x,y,w,h, goalX, goalY, filter) + goalX = goalX or x + goalY = goalY or y + + local tch, move = col.touch, col.move + if move.x ~= 0 or move.y ~= 0 then + if col.normal.x ~= 0 then + goalX = tch.x + else + goalY = tch.y + end + end + + col.slide = {x = goalX, y = goalY} + + x,y = tch.x, tch.y + local cols, len = world:project(col.item, x,y,w,h, goalX, goalY, filter) + return goalX, goalY, cols, len +end + +local bounce = function(world, col, x,y,w,h, goalX, goalY, filter) + goalX = goalX or x + goalY = goalY or y + + local tch, move = col.touch, col.move + local tx, ty = tch.x, tch.y + + local bx, by = tx, ty + + if move.x ~= 0 or move.y ~= 0 then + local bnx, bny = goalX - tx, goalY - ty + if col.normal.x == 0 then bny = -bny else bnx = -bnx end + bx, by = tx + bnx, ty + bny + end + + col.bounce = {x = bx, y = by} + x,y = tch.x, tch.y + goalX, goalY = bx, by + + local cols, len = world:project(col.item, x,y,w,h, goalX, goalY, filter) + return goalX, goalY, cols, len +end + +------------------------------------------ +-- World +------------------------------------------ + +local World = {} +local World_mt = {__index = World} + +-- Private functions and methods + +local function sortByWeight(a,b) return a.weight < b.weight end + +local function sortByTiAndDistance(a,b) + if a.ti == b.ti then + local ir, ar, br = a.itemRect, a.otherRect, b.otherRect + local ad = rect_getSquareDistance(ir.x,ir.y,ir.w,ir.h, ar.x,ar.y,ar.w,ar.h) + local bd = rect_getSquareDistance(ir.x,ir.y,ir.w,ir.h, br.x,br.y,br.w,br.h) + return ad < bd + end + return a.ti < b.ti +end + +local function addItemToCell(self, item, cx, cy) + self.rows[cy] = self.rows[cy] or setmetatable({}, {__mode = 'v'}) + local row = self.rows[cy] + row[cx] = row[cx] or {itemCount = 0, x = cx, y = cy, items = setmetatable({}, {__mode = 'k'})} + local cell = row[cx] + self.nonEmptyCells[cell] = true + if not cell.items[item] then + cell.items[item] = true + cell.itemCount = cell.itemCount + 1 + end +end + +local function removeItemFromCell(self, item, cx, cy) + local row = self.rows[cy] + if not row or not row[cx] or not row[cx].items[item] then return false end + + local cell = row[cx] + cell.items[item] = nil + cell.itemCount = cell.itemCount - 1 + if cell.itemCount == 0 then + self.nonEmptyCells[cell] = nil + end + return true +end + +local function getDictItemsInCellRect(self, cl,ct,cw,ch) + local items_dict = {} + for cy=ct,ct+ch-1 do + local row = self.rows[cy] + if row then + for cx=cl,cl+cw-1 do + local cell = row[cx] + if cell and cell.itemCount > 0 then -- no cell.itemCount > 1 because tunneling + for item,_ in pairs(cell.items) do + items_dict[item] = true + end + end + end + end + end + + return items_dict +end + +local function getCellsTouchedBySegment(self, x1,y1,x2,y2) + + local cells, cellsLen, visited = {}, 0, {} + + grid_traverse(self.cellSize, x1,y1,x2,y2, function(cx, cy) + local row = self.rows[cy] + if not row then return end + local cell = row[cx] + if not cell or visited[cell] then return end + + visited[cell] = true + cellsLen = cellsLen + 1 + cells[cellsLen] = cell + end) + + return cells, cellsLen +end + +local function getInfoAboutItemsTouchedBySegment(self, x1,y1, x2,y2, filter) + local cells, len = getCellsTouchedBySegment(self, x1,y1,x2,y2) + local cell, rect, l,t,w,h, ti1,ti2, tii0,tii1 + local visited, itemInfo, itemInfoLen = {},{},0 + for i=1,len do + cell = cells[i] + for item in pairs(cell.items) do + if not visited[item] then + visited[item] = true + if (not filter or filter(item)) then + rect = self.rects[item] + l,t,w,h = rect.x,rect.y,rect.w,rect.h + + ti1,ti2 = rect_getSegmentIntersectionIndices(l,t,w,h, x1,y1, x2,y2, 0, 1) + if ti1 and ((0 < ti1 and ti1 < 1) or (0 < ti2 and ti2 < 1)) then + -- the sorting is according to the t of an infinite line, not the segment + tii0,tii1 = rect_getSegmentIntersectionIndices(l,t,w,h, x1,y1, x2,y2, -math.huge, math.huge) + itemInfoLen = itemInfoLen + 1 + itemInfo[itemInfoLen] = {item = item, ti1 = ti1, ti2 = ti2, weight = min(tii0,tii1)} + end + end + end + end + end + table.sort(itemInfo, sortByWeight) + return itemInfo, itemInfoLen +end + +local function getResponseByName(self, name) + local response = self.responses[name] + if not response then + error(('Unknown collision type: %s (%s)'):format(name, type(name))) + end + return response +end + + +-- Misc Public Methods + +function World:addResponse(name, response) + self.responses[name] = response +end + +function World:project(item, x,y,w,h, goalX, goalY, filter) + assertIsRect(x,y,w,h) + + goalX = goalX or x + goalY = goalY or y + filter = filter or defaultFilter + + local collisions, len = {}, 0 + + local visited = {} + if item ~= nil then visited[item] = true end + + -- This could probably be done with less cells using a polygon raster over the cells instead of a + -- bounding rect of the whole movement. Conditional to building a queryPolygon method + local tl, tt = min(goalX, x), min(goalY, y) + local tr, tb = max(goalX + w, x+w), max(goalY + h, y+h) + local tw, th = tr-tl, tb-tt + + local cl,ct,cw,ch = grid_toCellRect(self.cellSize, tl,tt,tw,th) + + local dictItemsInCellRect = getDictItemsInCellRect(self, cl,ct,cw,ch) + + for other,_ in pairs(dictItemsInCellRect) do + if not visited[other] then + visited[other] = true + + local responseName = filter(item, other) + if responseName then + local ox,oy,ow,oh = self:getRect(other) + local col = rect_detectCollision(x,y,w,h, ox,oy,ow,oh, goalX, goalY) + + if col then + col.other = other + col.item = item + col.type = responseName + + len = len + 1 + collisions[len] = col + end + end + end + end + + table.sort(collisions, sortByTiAndDistance) + + return collisions, len +end + +function World:countCells() + local count = 0 + for _,row in pairs(self.rows) do + for _,_ in pairs(row) do + count = count + 1 + end + end + return count +end + +function World:hasItem(item) + return not not self.rects[item] +end + +function World:getItems() + local items, len = {}, 0 + for item,_ in pairs(self.rects) do + len = len + 1 + items[len] = item + end + return items, len +end + +function World:countItems() + local len = 0 + for _ in pairs(self.rects) do len = len + 1 end + return len +end + +function World:getRect(item) + local rect = self.rects[item] + if not rect then + error('Item ' .. tostring(item) .. ' must be added to the world before getting its rect. Use world:add(item, x,y,w,h) to add it first.') + end + return rect.x, rect.y, rect.w, rect.h +end + +function World:toWorld(cx, cy) + return grid_toWorld(self.cellSize, cx, cy) +end + +function World:toCell(x,y) + return grid_toCell(self.cellSize, x, y) +end + + +--- Query methods + +function World:queryRect(x,y,w,h, filter) + + assertIsRect(x,y,w,h) + + local cl,ct,cw,ch = grid_toCellRect(self.cellSize, x,y,w,h) + local dictItemsInCellRect = getDictItemsInCellRect(self, cl,ct,cw,ch) + + local items, len = {}, 0 + + local rect + for item,_ in pairs(dictItemsInCellRect) do + rect = self.rects[item] + if (not filter or filter(item)) + and rect_isIntersecting(x,y,w,h, rect.x, rect.y, rect.w, rect.h) + then + len = len + 1 + items[len] = item + end + end + + return items, len +end + +function World:queryPoint(x,y, filter) + local cx,cy = self:toCell(x,y) + local dictItemsInCellRect = getDictItemsInCellRect(self, cx,cy,1,1) + + local items, len = {}, 0 + + local rect + for item,_ in pairs(dictItemsInCellRect) do + rect = self.rects[item] + if (not filter or filter(item)) + and rect_containsPoint(rect.x, rect.y, rect.w, rect.h, x, y) + then + len = len + 1 + items[len] = item + end + end + + return items, len +end + +function World:querySegment(x1, y1, x2, y2, filter) + local itemInfo, len = getInfoAboutItemsTouchedBySegment(self, x1, y1, x2, y2, filter) + local items = {} + for i=1, len do + items[i] = itemInfo[i].item + end + return items, len +end + +function World:querySegmentWithCoords(x1, y1, x2, y2, filter) + local itemInfo, len = getInfoAboutItemsTouchedBySegment(self, x1, y1, x2, y2, filter) + local dx, dy = x2-x1, y2-y1 + local info, ti1, ti2 + for i=1, len do + info = itemInfo[i] + ti1 = info.ti1 + ti2 = info.ti2 + + info.weight = nil + info.x1 = x1 + dx * ti1 + info.y1 = y1 + dy * ti1 + info.x2 = x1 + dx * ti2 + info.y2 = y1 + dy * ti2 + end + return itemInfo, len +end + + +--- Main methods + +function World:add(item, x,y,w,h) + local rect = self.rects[item] + if rect then + error('Item ' .. tostring(item) .. ' added to the world twice.') + end + assertIsRect(x,y,w,h) + + self.rects[item] = {x=x,y=y,w=w,h=h} + + local cl,ct,cw,ch = grid_toCellRect(self.cellSize, x,y,w,h) + for cy = ct, ct+ch-1 do + for cx = cl, cl+cw-1 do + addItemToCell(self, item, cx, cy) + end + end + + return item +end + +function World:remove(item) + local x,y,w,h = self:getRect(item) + + self.rects[item] = nil + local cl,ct,cw,ch = grid_toCellRect(self.cellSize, x,y,w,h) + for cy = ct, ct+ch-1 do + for cx = cl, cl+cw-1 do + removeItemFromCell(self, item, cx, cy) + end + end +end + +function World:update(item, x2,y2,w2,h2) + local x1,y1,w1,h1 = self:getRect(item) + w2,h2 = w2 or w1, h2 or h1 + assertIsRect(x2,y2,w2,h2) + + if x1 ~= x2 or y1 ~= y2 or w1 ~= w2 or h1 ~= h2 then + + local cellSize = self.cellSize + local cl1,ct1,cw1,ch1 = grid_toCellRect(cellSize, x1,y1,w1,h1) + local cl2,ct2,cw2,ch2 = grid_toCellRect(cellSize, x2,y2,w2,h2) + + if cl1 ~= cl2 or ct1 ~= ct2 or cw1 ~= cw2 or ch1 ~= ch2 then + + local cr1, cb1 = cl1+cw1-1, ct1+ch1-1 + local cr2, cb2 = cl2+cw2-1, ct2+ch2-1 + local cyOut + + for cy = ct1, cb1 do + cyOut = cy < ct2 or cy > cb2 + for cx = cl1, cr1 do + if cyOut or cx < cl2 or cx > cr2 then + removeItemFromCell(self, item, cx, cy) + end + end + end + + for cy = ct2, cb2 do + cyOut = cy < ct1 or cy > cb1 + for cx = cl2, cr2 do + if cyOut or cx < cl1 or cx > cr1 then + addItemToCell(self, item, cx, cy) + end + end + end + + end + + local rect = self.rects[item] + rect.x, rect.y, rect.w, rect.h = x2,y2,w2,h2 + + end +end + +function World:move(item, goalX, goalY, filter) + local actualX, actualY, cols, len = self:check(item, goalX, goalY, filter) + + self:update(item, actualX, actualY) + + return actualX, actualY, cols, len +end + +function World:check(item, goalX, goalY, filter) + filter = filter or defaultFilter + + local visited = {[item] = true} + local visitedFilter = function(itm, other) + if visited[other] then return false end + return filter(itm, other) + end + + local cols, len = {}, 0 + + local x,y,w,h = self:getRect(item) + + local projected_cols, projected_len = self:project(item, x,y,w,h, goalX,goalY, visitedFilter) + + while projected_len > 0 do + local col = projected_cols[1] + len = len + 1 + cols[len] = col + + visited[col.other] = true + + local response = getResponseByName(self, col.type) + + goalX, goalY, projected_cols, projected_len = response( + self, + col, + x, y, w, h, + goalX, goalY, + visitedFilter + ) + end + + return goalX, goalY, cols, len +end + + +-- Public library functions + +bump.newWorld = function(cellSize) + cellSize = cellSize or 64 + assertIsPositiveNumber(cellSize, 'cellSize') + local world = setmetatable({ + cellSize = cellSize, + rects = {}, + rows = {}, + nonEmptyCells = {}, + responses = {} + }, World_mt) + + world:addResponse('touch', touch) + world:addResponse('cross', cross) + world:addResponse('slide', slide) + world:addResponse('bounce', bounce) + + return world +end + +bump.rect = { + getNearestCorner = rect_getNearestCorner, + getSegmentIntersectionIndices = rect_getSegmentIntersectionIndices, + getDiff = rect_getDiff, + containsPoint = rect_containsPoint, + isIntersecting = rect_isIntersecting, + getSquareDistance = rect_getSquareDistance, + detectCollision = rect_detectCollision +} + +bump.responses = { + touch = touch, + cross = cross, + slide = slide, + bounce = bounce +} + +return bump diff --git a/bump/bump_debug.lua b/bump/bump_debug.lua new file mode 100644 index 0000000..308608f --- /dev/null +++ b/bump/bump_debug.lua @@ -0,0 +1,31 @@ + +local bump = require 'bump' + +local bump_debug = {} + +local function getCellRect(world, cx,cy) + local cellSize = world.cellSize + local l,t = world:toWorld(cx,cy) + return l,t,cellSize,cellSize +end + +function bump_debug.draw(world) + local cellSize = world.cellSize + -- local font = love.graphics.getFont() + local fontHeight = 20 + local topOffset = (cellSize - fontHeight) / 2 + for cy, row in pairs(world.rows) do + for cx, cell in pairs(row) do + local l,t,w,h = getCellRect(world, cx,cy) + local intensity = cell.itemCount * 12 + 16 + jin.graphics.setColor(255,255,255,intensity) + jin.graphics.rect('fill', l,t,w,h) + jin.graphics.setColor(255,255,255, 64) + -- jin.graphics.printf(cell.itemCount, l, t+topOffset, cellSize, 'center') + jin.graphics.setColor(255,255,255,10) + jin.graphics.rect('line', l,t,w,h) + end + end +end + +return bump_debug diff --git a/bump/config.lua b/bump/config.lua new file mode 100644 index 0000000..d3b3d68 --- /dev/null +++ b/bump/config.lua @@ -0,0 +1,6 @@ +return +{ + width = 800, + height = 600 + +}
\ No newline at end of file diff --git a/bump/main.lua b/bump/main.lua new file mode 100644 index 0000000..973cd61 --- /dev/null +++ b/bump/main.lua @@ -0,0 +1,163 @@ +local bump = require 'bump' +local bump_debug = require 'bump_debug' +io.stdout:setvbuf("no") +local instructions = [[ + bump.lua simple demo + + arrows: move + tab: toggle debug info + delete: run garbage collector +]] + +local cols_len = 0 -- how many collisions are happening + +-- World creation +local world = bump.newWorld() + + +-- Message/debug functions +local function drawMessage() + local msg = instructions:format(tostring(shouldDrawDebug)) + jin.graphics.setColor(255, 255, 255) + -- jin.graphics.print(msg, 550, 10) +end + +local function drawDebug() + bump_debug.draw(world) + + local statistics = ("fps: %d, mem: %dKB, collisions: %d, items: %d"):format(love.timer.getFPS(), collectgarbage("count"), cols_len, world:countItems()) + jin.graphics.setColor(255, 255, 255) + -- jin.graphics.printf(statistics, 0, 580, 790, 'right') +end + +local consoleBuffer = {} +local consoleBufferSize = 15 +for i=1,consoleBufferSize do consoleBuffer[i] = "" end +local function consolePrint(msg) + table.remove(consoleBuffer,1) + consoleBuffer[consoleBufferSize] = msg +end + +local function drawConsole() + local str = table.concat(consoleBuffer, "\n") + for i=1,consoleBufferSize do + jin.graphics.setColor(255,255,255, i*255/consoleBufferSize) + -- love.graphics.printf(consoleBuffer[i], 10, 580-(consoleBufferSize - i)*12, 790, "left") + end +end + +-- helper function +local function drawBox(box, r,g,b) + jin.graphics.setColor(r,g,b,70) + jin.graphics.rect("fill", box.x, box.y, box.w, box.h) + jin.graphics.setColor(r,g,b) + jin.graphics.rect("line", box.x, box.y, box.w, box.h) +end + + + +-- Player functions +local player = { x=50,y=50,w=20,h=20, speed = 80, onGround = false} +vx = 0 +vy = 0 +local function updatePlayer(dt) + local speed = player.speed + if jin.keyboard.isDown('Right') then + vx = speed + elseif jin.keyboard.isDown('Left') then + vx = -speed + end + if jin.keyboard.isDown('Down') then + vy = vy + elseif jin.keyboard.isDown('Up') then + vy = vy + elseif jin.keyboard.isDown('Space') and player.onGround then + vy = vy - 12000 * dt + print("jump") + print("on sky") + player.onGround = false + end + if not player.onGround then + vy = vy + 200 * dt + end + if vx ~= 0 or vy ~= 0 then + local cols + local py = player.y + player.x, player.y, cols, cols_len = world:move(player, player.x + vx * dt, player.y + vy * dt) + if py == player.y then + player.onGround = true + vy = 0 + print("on ground") + end + for i=1, cols_len do + local col = cols[i] + consolePrint(("col.other = %s, col.type = %s, col.normal = %d,%d"):format(col.other, col.type, col.normal.x, col.normal.y)) + end + end + vx = 0 +end + +local function drawPlayer() + drawBox(player, 0, 255, 0) +end + +-- Block functions + +local blocks = {} + +local function addBlock(x,y,w,h) + local block = {x=x,y=y,w=w,h=h} + blocks[#blocks+1] = block + world:add(block, x,y,w,h) +end + +local function drawBlocks() + for _,block in ipairs(blocks) do + drawBox(block, 255,0,0) + end +end + +function jin.core.onEvent(e) + if e.type == "quit" then + jin.core.stop() + end + if e.type == "keydown" then + if e.key == "Escape" then + jin.core.stop() + end + end +end + +-- Main LÖVE functions + +function jin.core.onLoad() + world:add(player, player.x, player.y, player.w, player.h) + + addBlock(0, 0, 800, 32) + addBlock(0, 32, 32, 600-32*2) + addBlock(800-32, 32, 32, 600-32*2) + addBlock(0, 600-32, 800, 32) + + for i=1,30 do + addBlock( math.random(100, 600), + math.random(100, 400), + math.random(10, 100), + math.random(10, 100) + ) + end +end + +function jin.core.onUpdate(dt) + cols_len = 0 + updatePlayer(dt) +end + +function jin.core.onDraw() + drawBlocks() + drawPlayer() + if shouldDrawDebug then + drawDebug() + drawConsole() + end + drawMessage() +end diff --git a/json/README.md b/json/README.md deleted file mode 100644 index e69de29..0000000 --- a/json/README.md +++ /dev/null diff --git a/json/json.lua b/json/json.lua new file mode 100644 index 0000000..a3d7530 --- /dev/null +++ b/json/json.lua @@ -0,0 +1,400 @@ +-- +-- json.lua +-- +-- Copyright (c) 2018 rxi +-- +-- 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 json = { _version = "0.1.1" } + +------------------------------------------------------------------------------- +-- Encode +------------------------------------------------------------------------------- + +local encode + +local escape_char_map = { + [ "\\" ] = "\\\\", + [ "\"" ] = "\\\"", + [ "\b" ] = "\\b", + [ "\f" ] = "\\f", + [ "\n" ] = "\\n", + [ "\r" ] = "\\r", + [ "\t" ] = "\\t", +} + +local escape_char_map_inv = { [ "\\/" ] = "/" } +for k, v in pairs(escape_char_map) do + escape_char_map_inv[v] = k +end + + +local function escape_char(c) + return escape_char_map[c] or string.format("\\u%04x", c:byte()) +end + + +local function encode_nil(val) + return "null" +end + + +local function encode_table(val, stack) + local res = {} + stack = stack or {} + + -- Circular reference? + if stack[val] then error("circular reference") end + + stack[val] = true + + if val[1] ~= nil or next(val) == nil then + -- Treat as array -- check keys are valid and it is not sparse + local n = 0 + for k in pairs(val) do + if type(k) ~= "number" then + error("invalid table: mixed or invalid key types") + end + n = n + 1 + end + if n ~= #val then + error("invalid table: sparse array") + end + -- Encode + for i, v in ipairs(val) do + table.insert(res, encode(v, stack)) + end + stack[val] = nil + return "[" .. table.concat(res, ",") .. "]" + + else + -- Treat as an object + for k, v in pairs(val) do + if type(k) ~= "string" then + error("invalid table: mixed or invalid key types") + end + table.insert(res, encode(k, stack) .. ":" .. encode(v, stack)) + end + stack[val] = nil + return "{" .. table.concat(res, ",") .. "}" + end +end + + +local function encode_string(val) + return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"' +end + + +local function encode_number(val) + -- Check for NaN, -inf and inf + if val ~= val or val <= -math.huge or val >= math.huge then + error("unexpected number value '" .. tostring(val) .. "'") + end + return string.format("%.14g", val) +end + + +local type_func_map = { + [ "nil" ] = encode_nil, + [ "table" ] = encode_table, + [ "string" ] = encode_string, + [ "number" ] = encode_number, + [ "boolean" ] = tostring, +} + + +encode = function(val, stack) + local t = type(val) + local f = type_func_map[t] + if f then + return f(val, stack) + end + error("unexpected type '" .. t .. "'") +end + + +function json.encode(val) + return ( encode(val) ) +end + + +------------------------------------------------------------------------------- +-- Decode +------------------------------------------------------------------------------- + +local parse + +local function create_set(...) + local res = {} + for i = 1, select("#", ...) do + res[ select(i, ...) ] = true + end + return res +end + +local space_chars = create_set(" ", "\t", "\r", "\n") +local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",") +local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u") +local literals = create_set("true", "false", "null") + +local literal_map = { + [ "true" ] = true, + [ "false" ] = false, + [ "null" ] = nil, +} + + +local function next_char(str, idx, set, negate) + for i = idx, #str do + if set[str:sub(i, i)] ~= negate then + return i + end + end + return #str + 1 +end + + +local function decode_error(str, idx, msg) + local line_count = 1 + local col_count = 1 + for i = 1, idx - 1 do + col_count = col_count + 1 + if str:sub(i, i) == "\n" then + line_count = line_count + 1 + col_count = 1 + end + end + error( string.format("%s at line %d col %d", msg, line_count, col_count) ) +end + + +local function codepoint_to_utf8(n) + -- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa + local f = math.floor + if n <= 0x7f then + return string.char(n) + elseif n <= 0x7ff then + return string.char(f(n / 64) + 192, n % 64 + 128) + elseif n <= 0xffff then + return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128) + elseif n <= 0x10ffff then + return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128, + f(n % 4096 / 64) + 128, n % 64 + 128) + end + error( string.format("invalid unicode codepoint '%x'", n) ) +end + + +local function parse_unicode_escape(s) + local n1 = tonumber( s:sub(3, 6), 16 ) + local n2 = tonumber( s:sub(9, 12), 16 ) + -- Surrogate pair? + if n2 then + return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000) + else + return codepoint_to_utf8(n1) + end +end + + +local function parse_string(str, i) + local has_unicode_escape = false + local has_surrogate_escape = false + local has_escape = false + local last + for j = i + 1, #str do + local x = str:byte(j) + + if x < 32 then + decode_error(str, j, "control character in string") + end + + if last == 92 then -- "\\" (escape char) + if x == 117 then -- "u" (unicode escape sequence) + local hex = str:sub(j + 1, j + 5) + if not hex:find("%x%x%x%x") then + decode_error(str, j, "invalid unicode escape in string") + end + if hex:find("^[dD][89aAbB]") then + has_surrogate_escape = true + else + has_unicode_escape = true + end + else + local c = string.char(x) + if not escape_chars[c] then + decode_error(str, j, "invalid escape char '" .. c .. "' in string") + end + has_escape = true + end + last = nil + + elseif x == 34 then -- '"' (end of string) + local s = str:sub(i + 1, j - 1) + if has_surrogate_escape then + s = s:gsub("\\u[dD][89aAbB]..\\u....", parse_unicode_escape) + end + if has_unicode_escape then + s = s:gsub("\\u....", parse_unicode_escape) + end + if has_escape then + s = s:gsub("\\.", escape_char_map_inv) + end + return s, j + 1 + + else + last = x + end + end + decode_error(str, i, "expected closing quote for string") +end + + +local function parse_number(str, i) + local x = next_char(str, i, delim_chars) + local s = str:sub(i, x - 1) + local n = tonumber(s) + if not n then + decode_error(str, i, "invalid number '" .. s .. "'") + end + return n, x +end + + +local function parse_literal(str, i) + local x = next_char(str, i, delim_chars) + local word = str:sub(i, x - 1) + if not literals[word] then + decode_error(str, i, "invalid literal '" .. word .. "'") + end + return literal_map[word], x +end + + +local function parse_array(str, i) + local res = {} + local n = 1 + i = i + 1 + while 1 do + local x + i = next_char(str, i, space_chars, true) + -- Empty / end of array? + if str:sub(i, i) == "]" then + i = i + 1 + break + end + -- Read token + x, i = parse(str, i) + res[n] = x + n = n + 1 + -- Next token + i = next_char(str, i, space_chars, true) + local chr = str:sub(i, i) + i = i + 1 + if chr == "]" then break end + if chr ~= "," then decode_error(str, i, "expected ']' or ','") end + end + return res, i +end + + +local function parse_object(str, i) + local res = {} + i = i + 1 + while 1 do + local key, val + i = next_char(str, i, space_chars, true) + -- Empty / end of object? + if str:sub(i, i) == "}" then + i = i + 1 + break + end + -- Read key + if str:sub(i, i) ~= '"' then + decode_error(str, i, "expected string for key") + end + key, i = parse(str, i) + -- Read ':' delimiter + i = next_char(str, i, space_chars, true) + if str:sub(i, i) ~= ":" then + decode_error(str, i, "expected ':' after key") + end + i = next_char(str, i + 1, space_chars, true) + -- Read value + val, i = parse(str, i) + -- Set + res[key] = val + -- Next token + i = next_char(str, i, space_chars, true) + local chr = str:sub(i, i) + i = i + 1 + if chr == "}" then break end + if chr ~= "," then decode_error(str, i, "expected '}' or ','") end + end + return res, i +end + + +local char_func_map = { + [ '"' ] = parse_string, + [ "0" ] = parse_number, + [ "1" ] = parse_number, + [ "2" ] = parse_number, + [ "3" ] = parse_number, + [ "4" ] = parse_number, + [ "5" ] = parse_number, + [ "6" ] = parse_number, + [ "7" ] = parse_number, + [ "8" ] = parse_number, + [ "9" ] = parse_number, + [ "-" ] = parse_number, + [ "t" ] = parse_literal, + [ "f" ] = parse_literal, + [ "n" ] = parse_literal, + [ "[" ] = parse_array, + [ "{" ] = parse_object, +} + + +parse = function(str, idx) + local chr = str:sub(idx, idx) + local f = char_func_map[chr] + if f then + return f(str, idx) + end + decode_error(str, idx, "unexpected character '" .. chr .. "'") +end + + +function json.decode(str) + if type(str) ~= "string" then + error("expected argument of type string, got " .. type(str)) + end + local res, idx = parse(str, next_char(str, 1, space_chars, true)) + idx = next_char(str, idx, space_chars, true) + if idx <= #str then + decode_error(str, idx, "trailing garbage") + end + return res +end + + +return json diff --git a/log/init.lua b/log/log.lua index bfa2e4e..0c1d3bc 100644 --- a/log/init.lua +++ b/log/log.lua @@ -1,5 +1,3 @@ --- 不能使用 debug 命名模块,会冲突, --- 要使用其余名字比如 loghelper local log = {} io.stdout:setvbuf("no") @@ -1,94 +0,0 @@ --- _require = require --- require = function(name) --- return _require("jin-modules." .. name) --- end -local jnet = require("jnet") -local log = require("log") -log.dateFormat("") -log.strict(log.LEVEL.INFO) -local EventMsgCenter = require("EventMsgCenter.EventMsgCenter") -local Events = require("EventMsgCenter.Events") -local timer = require("timer.timer") -require("gameloop") -_G["frame"] = 0 - -local thread = nil -local socket = nil -jin.core.onLoad = function() ----- 网络测试 - jin.net.init() - socket = jin.net.newSocket("TCP", 8807) - local Skill = { - id = jnet.DataType.INT, - damage = jnet.DataType.FLOAT, - name = jnet.DataType.STRING, - description = jnet.DataType.STRING, - -- bonus = { - -- damage = FLOAT, - -- range = FLOAT, - -- cd = BOOL - -- } - cd = jnet.DataType.BOOL - } - local buf = jin.net.newBuffer(0) - local mySkill = { - id = 12, - name = "Hell fire!!!", - damage = 3.4, - description = "1234", - -- bonus = { - -- damage = FLOAT, - -- range = FLOAT, - -- cd = BOOL - -- } - cd = true - } - local len = buf:append("Skill") - jnet.serialize(mySkill, buf) - local msgName = buf:grabString(0) - log.error(msgName) - local msg = jnet.deserialize(Skill, buf, len) - log.info(msg.id) - - thread = jin.thread.newThread("Test", [[ - local thread = jin.thread.getThread() - local socket = thread:demand(1) - while true do - local client = socket:accept() - local buf = client:receive() - local str = buf:grabString(0) - print(str) - end - ]]) - thread:start() - thread:send(1, socket) - EventMsgCenter.registerMsg(Events.Player_Move, function(msg) - -- print(msg) - end) - timer.every(1.0, function() - log.info(_G["frame"] .. "fps") - -- EventMsgCenter.sendMsg(Events.Player_Move, _G["frame"]) - _G["frame"] = 0 - end) - timer.after(4.0, function() - EventMsgCenter.unregisterAllMsgByEvent(Events.Player_Move) - end) -end - -jin.core.onEvent = function(e) - if e.type == "quit" then - jin.core.stop() elseif e.type == "keydown" then - if e.key == "Escape" then - jin.core.stop() - end - end -end - -jin.core.onUpdate = function(dt) - _G["frame"] = _G["frame"] + 1 - timer.update(dt) -end - -jin.core.onDraw = function() - -end
\ No newline at end of file diff --git a/tiled/atlas.png b/tiled/atlas.png Binary files differnew file mode 100644 index 0000000..e32d664 --- /dev/null +++ b/tiled/atlas.png diff --git a/tiled/eventset.png b/tiled/eventset.png Binary files differnew file mode 100644 index 0000000..929c3da --- /dev/null +++ b/tiled/eventset.png diff --git a/tiled/map1.tmx b/tiled/map1.tmx new file mode 100644 index 0000000..376c292 --- /dev/null +++ b/tiled/map1.tmx @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="UTF-8"?> +<map version="1.0" orientation="orthogonal" renderorder="right-down" width="70" height="40" tilewidth="16" tileheight="16" nextobjectid="1"> + <tileset firstgid="1" name="eventset" tilewidth="16" tileheight="16" tilecount="16" columns="4"> + <image source="eventset.png" width="64" height="64"/> + <tile id="1"> + <properties> + <property name="portal" value="1"/> + <property name="target" value="2-1"/> + </properties> + </tile> + <tile id="2"> + <properties> + <property name="start" value="player2"/> + </properties> + </tile> + <tile id="3"> + <properties> + <property name="floor" value="true"/> + </properties> + </tile> + <tile id="4"> + <properties> + <property name="lowest" value="true"/> + </properties> + </tile> + <tile id="5"> + <properties> + <property name="id" value="3"/> + <property name="portal" value="true"/> + </properties> + </tile> + <tile id="7"> + <properties> + <property name="block" value="true"/> + </properties> + </tile> + </tileset> + <tileset firstgid="17" name="atlas" tilewidth="16" tileheight="16" tilecount="1024" columns="32"> + <image source="atlas.png" width="512" height="512"/> + </tileset> + <tileset firstgid="1041" name="signs" tilewidth="16" tileheight="16" tilecount="4" columns="4"> + <image source="signs.png" width="64" height="16"/> + </tileset> + <layer name="bg" width="70" height="40"> + <data encoding="base64" compression="zlib"> + eJztzkVylGEYhdE/BPdi3nHreDEnuOsGsAT3DQQI7rABXINvAHdnAzjBbQPImbGFrq/eqnumT91clmUllFJGORVUUkU1NdRSR556GmikiWZaaCWXSG8UbYxmDGMZx3gmMJFJTGYKU5nGdGYwk1nMZk5CvbnMYz4LWEg7HSxiMUtYyjKWs4KVrGI1a1jLuoR6naxnAxvpYhOb2cJWtrGdHexkF7vZw172sZ8DCfUOcojDHOEoxzjOCU5yitOcoZuznOM8F7jIJS4n1LvCVa5xnRvc5Ba3ucNd7nGfBzzkEY95wlOe8Tyh3gte8orXvOEt73hPDx/4yCc+84WvfOM7P/jJr4R6v/nDX7IioxfF9KYPfelHfwYwkEEMZghDGcbwonR6OUoopYxyKqikimpqqKWOPPU00EgTzbTQmlAvH0IIIRtRAB8K0cgC+BBCCCGEEEIIIYQQQgghhBBC+O8fgFh8kg== + </data> + </layer> + <layer name="trees" width="70" height="40"> + <data encoding="base64" compression="zlib"> + eJzt0MkNwlAQRMGRHQVkAmmy5gHGzoM1HDoBFokT+lXSu/VlpgoAAH6z6qrWadN93m6z2aX9F9t/d8iNxzSkWV81719vT9mMaWrgL+fceEnXtMhPlm/+csvmnh4N/AUAAAAAAACAdjwBV0ANmg== + </data> + </layer> + <layer name="main" width="70" height="40"> + <data encoding="base64" compression="zlib"> + eJzt0DEKwjAYhuE/R6i2k6cQwcGeQkc9hrviGTyKJ9H2IrWDQxc/sdAQdHBJJbwPvCQpHZLfDAAAAADi2Duzq33upipVf9l3Y1w4krPm0mi9q1YddD4G3xobzic3fJ+5kS4dwUVvK1Sm5n15f371sPeae+eJ1qkqE55L5c1j4e3DlsF/q8Tn0upt6x/bqK3aJTwXAAAAAAAAAAAA/Kcn5RgnOg== + </data> + </layer> + <layer name="signs" width="70" height="40"> + <data encoding="base64" compression="zlib"> + eJztybEJADAIADAHH7D/H9sPdBOEZE0EAADAvsr+3/AAAAAAAAAAcNUHZv8ALA== + </data> + </layer> + <layer name="events" width="70" height="40"> + <data encoding="base64" compression="zlib"> + eJzt0MEJACAQA8FDtP+WbcCXDy/IDOQftgoAAHhpdB8g0rzc73Q50wUA8q3uAwAAAABAtA3ReQCw + </data> + </layer> +</map> diff --git a/tiled/map2.tmx b/tiled/map2.tmx new file mode 100644 index 0000000..0fba89a --- /dev/null +++ b/tiled/map2.tmx @@ -0,0 +1,83 @@ +<?xml version="1.0" encoding="UTF-8"?> +<map version="1.0" orientation="orthogonal" renderorder="right-down" width="70" height="45" tilewidth="16" tileheight="16" nextobjectid="1"> + <tileset firstgid="1" name="atlas" tilewidth="16" tileheight="16" tilecount="1024" columns="32"> + <image source="atlas.png" width="512" height="512"/> + </tileset> + <tileset firstgid="1025" name="eventset" tilewidth="16" tileheight="16" tilecount="16" columns="4"> + <image source="eventset.png" width="64" height="64"/> + <tile id="1"> + <properties> + <property name="portal" value="1"/> + <property name="target" value="1-1"/> + </properties> + </tile> + <tile id="2"> + <properties> + <property name="portal" value="2"/> + <property name="target" value="3-1"/> + </properties> + </tile> + <tile id="3"> + <properties> + <property name="floor" value="true"/> + </properties> + </tile> + <tile id="4"> + <properties> + <property name="lowest" value="true"/> + </properties> + </tile> + <tile id="5"> + <properties> + <property name="portal" value="true"/> + </properties> + </tile> + <tile id="7"> + <properties> + <property name="block" value="true"/> + </properties> + </tile> + <tile id="12"> + <properties> + <property name="checkpoint" value="true"/> + </properties> + </tile> + </tileset> + <tileset firstgid="1041" name="signs" tilewidth="16" tileheight="16" tilecount="4" columns="4"> + <image source="signs.png" width="64" height="16"/> + </tileset> + <layer name="bg" width="70" height="45"> + <data encoding="base64" compression="zlib"> + eJzt1XdSU1EUx/GXBSSUAAkQygbsBQuoG7Bhw+4GbNiwoG7A3rsbsKCIvWzAhiA21A3YRaWp3wxk5s0Vk5ec6/Aczp35/PfOL+eeeS8n5DhOFrKRg1yEkYd8FCCCKApRhGLEUIJSlKEcQYQEedJ6sx/JGY4RGIlRGI0xGItxGI8KTMBETMJkVKIKUzAV0zBMmCetN/uRnBmYiVmYjWrMwVzMw3wsQA0WYhEWYwmWYhmWYwWmC/Ok9WY/krMKq7EGa1GLdViPDdiITajDZmzBVmxDPbZjB3ZipTBPWm/2Izm7sQd7sQ/7cQAHcQiHcQRHcQzHcQIncQqncQZnsUuYJ603+5Gc87iAi2jAJVxGI66gCVdxDddxAzdxC7dxB3dxD+eEedJ6sx/JeYCHeITHaMYTtKAVT9GGZ3iOF3iJV2jHa7zBW9wX5knrzX4ke+09PuAjPuEzvuArOvAN3/EDnehCN3rQi5/4FR9wwHHeCfOk9WY/kr0Woj6cpmLEUIJSlKEcwUBfXhaykYPc/po85CfJjHmsL0AEURSiKEk/kr2W7kz+F9K9Ntj9/yvSvTbY/dtkay/G95r7e7TRW4ulWTc7f+a1Jcm2uRfb++eS4LXnVHvD/WyqveHl9/62hwZ61sZe7DXmEnTlJ9sHqfZGOJDe3rC9h2zlJXidc9cQYL4vXuYcr3PP2UYffsvLZC4RS737WSbfkfl/ZYPf8jJ9XxLvqa17+C3PPZdoBmzew0950rnYuovf8kIBpZRSSimllFJKKaWUUkqpoek3zxlDIw== + </data> + </layer> + <layer name="plants" width="70" height="45"> + <data encoding="base64" compression="zlib"> + eJzt17kNwkAQheGRnQBtcNMVdMJVCFcAVMEVAE3xEgcIJ6yNvIz/T3rhSjtPWmnHDAAAAACA740Ts0lS9S3iM1UnM3r5sFIn64K9zHV+oSwd9XvSLOeC82x0fqvsHPVShov6uCo3ekHkGqlZU2mlVd8kLgP1MVRG9AIAqBmPe08Z2Hvy1XHv2WvWg3J0PHM/4A98Vx8P5RlRL6F7Tsj8/yTbc7zPiXfs/fmy99BWOkpX6dETAAAAfugFJZkXWQ== + </data> + </layer> + <layer name="treetrunks" width="70" height="45"> + <data encoding="base64" compression="zlib"> + eJzt2MkNwjAQBVCTnFi64MAS2gAhUQV0AgfWKuDAWgUgsZYRCuEfyIEoRCEkdoz/k+aI8HxbY4MQRERERERERJQFFVuIqq16FfLl0XMBVUSVDOz/kxqyqKMcVIO50B8ZWkKMUGNL9UqyZYk8Vqi1Qbl48z/MCXmcURcNc2nm4n3Om/8mmmCfp6iZhvudpg3y2KJ2zOXNFXncUHfmYqQod4iJTL5D4nBi3tVxyXgHlyXufxd99BLoRYd38DdnpY8+Bgn0ovM7OMgcfSx8vXiz3OTZtUcmB18uWcqDv9+D6TC3VFAxt1qS7/IwR0Vraav52sjcVy5p5+P/D6aTobMRxg1Y5+PHtct+4+pClzNBRETpewJlgiX+ + </data> + </layer> + <layer name="main" width="70" height="45"> + <data encoding="base64" compression="zlib"> + eJztWFluE0EUnA6OYwchzgAhzsItICuERVwhiEVivwIICHxAuEJI2MRyBXASNgG5QuI4bBJnoErTT/Pc9NgxHiWTqEsq9awev+pXr99MFAUEBAQEBAQEBAQEBAQEBGSFiy3Om5R7boN3wLvgDHgPvJ/ye3Iu75g2cUwzLa5jjKKL1mceXACfgE/BZ+Bz8EWT32p2Li+4aeJ4foJv2+Q7cAlcBt+DH8CP4Cfwc5NnuvmVR8xBFwOuYnstSsZak/2aOl4HN8Dv4I8o1vdXC+r8WsGzX4GvwTc+o24TqvgvB8AesGQ1Kln2pezvsWOX3S6CA/YaatZrYq5G/pHsBr/ZY+tRvL2SI23mrC6MuaJGOebb7/Ocpy6D4JDVmBxWdPe7LY3aFm3ykDuiy2AH1LpUFIdTxorSwqX4k/qcaVObbrAI9oAlsNyBLjU8e6JDjoHjdnsSPLYJVlN0MTYHr4M3rC5TJqnzVXAR/O2JpR+sgAPgIDjUgS7bBc7HUXAEHPVoOws+Mo19gNR/+m2vJ5dGwTFwHJwAJ7csmq0FNdF9AOt80frxcIrHzoHnwQtR6z41T2DvIp7Q3uD6Ld5gr3nWNGpStJqUbA1P02UngvGKJ1Yd9ipvsNe8ZWLfsDcSTcjd5g/miWjCWKX/kVF7g2vkY9Ooh2iyG0AtxCfURDyh13jRRXujapJaIv3kbtFE1hFqQZ+wp3U1cdei41YXrlXrYB3csOu6nMsT5D1P18m0mklMOzUzrRfcybVzyiTzznfEayYmc2DN7uuaSUjdZB1J65GzyIGXpvV7ucwpe0HOYTt9MGM/YRr7SXnOJRy/bGPkO2IBXLaePwT2e/oJ1of9XfE1vjpSyChXvuA3vprku48vr6XWy3y20wdL7FdN3E+yFvB7Ab2hva49r3tVd+7lHjk/4tSSZrkisUke6LkSv0p/sw/a/zHJ9w3Ja+mLJb/pZfq23T6Y6+KS4oJJvlX53kOyhmhBDRhb2XqTcUmMnCvxq/iUxxkz1yy5TnK4YMeKXcseYHzYpnc5v3yvYO5rfUQbt65mBeqhc71s45XvOgVnW/xKny6q2GXsz0ALF6KN1oXzUDaN3zl1XpObqXmnbf06CZ4y8T5H7X2pXz4dGNus8p/49Ijxv3t2qoVPG3mGq4+sQTUbh3jX5zfxv8R9xd6vPSF1sGh1qHhiHMs4vixQt/9RtJk3ic9kPvm9pM+kr9OSBxwPmsY1TPoXrcNOQt3571Xz7/c2d52W95uCk3dLKify2sP+L+g1V6tx41+nfdcFBAQEBAQI/gKKMkyD + </data> + </layer> + <layer name="signs" width="70" height="45"> + <data encoding="base64" compression="zlib"> + eJzt1sEJACAMBME80oBi/7WmASE/hTBTwb2OjQAAAACAuU7+XgDQ274KAGC8F823dCUAAABcFc8tAFo= + </data> + </layer> + <layer name="events" width="70" height="45"> + <properties> + <property name="portal" value="2"/> + <property name="target" value="3-1"/> + </properties> + <data encoding="base64" compression="zlib"> + eJzt1k0OAiEMhmFUXHosvYm38e/IkqjJ7CwDtNPyPkkTF0bSbzrFlAAAAAAAAHQdsvy7OX8qktZ+fplEzKVX1Z65ZT1z0chUi3UekmxOBrlZZ+FhdjScS11S/2y853stdduldC/1KPUs9fp+XtaS535H8T4HI8y0f/71OuNOlvRLJvJcopnt2UvMsCdqe7TOZK9wxpr/7Vq5SH6v5XyvMz76LtvS+996l/fuwzKb2h6195f2nvR2X/WaU81517S2p2g5SLTkAsDGMcD7F6EHQOINSDISEA== + </data> + </layer> +</map> diff --git a/tiled/map3.tmx b/tiled/map3.tmx new file mode 100644 index 0000000..991b7b1 --- /dev/null +++ b/tiled/map3.tmx @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8"?> +<map version="1.0" orientation="orthogonal" renderorder="right-down" width="100" height="50" tilewidth="16" tileheight="16" nextobjectid="1"> + <tileset firstgid="1" name="atlas" tilewidth="16" tileheight="16" tilecount="1024" columns="32"> + <image source="atlas.png" width="512" height="512"/> + </tileset> + <tileset firstgid="1025" name="eventset" tilewidth="16" tileheight="16" tilecount="16" columns="4"> + <image source="eventset.png" width="64" height="64"/> + <tile id="1"> + <properties> + <property name="portal" value="1"/> + <property name="target" value="2-2"/> + </properties> + </tile> + <tile id="2"> + <properties> + <property name="portal" value="2"/> + <property name="target" value="4-1"/> + </properties> + </tile> + <tile id="3"> + <properties> + <property name="floor" value="true"/> + </properties> + </tile> + <tile id="4"> + <properties> + <property name="lowest" value="true"/> + </properties> + </tile> + <tile id="5"> + <properties> + <property name="portal" value="true"/> + </properties> + </tile> + <tile id="7"> + <properties> + <property name="block" value="true"/> + </properties> + </tile> + <tile id="12"> + <properties> + <property name="checkpoint" value="true"/> + </properties> + </tile> + </tileset> + <tileset firstgid="1041" name="signs" tilewidth="16" tileheight="16" tilecount="4" columns="4"> + <image source="signs.png" width="64" height="16"/> + </tileset> + <layer name="bg" width="100" height="50"> + <data encoding="base64" compression="zlib"> + eJzt2XVuG0EYxuH1AYJOYoecXKDM3AuUmXuBpsx4gTJzL1Bm7gXKzL1ACimn+IuykarKY83OzG6n0ffHo0gTz/vO5svG8iYdBEEFKlGFDLKoRg1qUYd65NCARhShGCUoRRnKkS6w7rpHJ892v+l5THt7oTf6oC/6oT8GYCAGYTCGYCiGYTi6oCu6oTt6oGeYp1p33aOTZ7vf9DymveMwHhMwEZMwGVMwFdMwHTMwE7MwGyMwEqMwGmMwNsxTrbvu0cmz3W96HtPehViExViCpViG5ViBlViF1ViDtViHOWjCXMzDfCwI81Trrnt08mz3m57HtHcrtmE7dmAndmE39mAv9mE/DuAgDmE9NmAjNmEztoR5qnXXPTp5tvtNz2PaexKncBpncBbncB4XcBGXcBlXcBXXcBhHcBTHcBwnwjzVuusenTyd/W9iOI/pue/iHu7jAR7iER7jCZ7iGZ7jBV7iFa7jBm7iFm7jTpinWnfdo5Nnu9/0PKa97/EBH/EJn/EFX9GKb/iOH/iJXwhSQdDMl9dB++/WW7xDS5inWnfdo5Nnu9/0PKa9aToqUIkqZJBFNWpQizrUI4cGNKIIxShBKcpQnmrPU6277tHJs91veh7T3uZACKHSIoQQQgghRCdm+5k/l+cZQi6Vf911j6tnFXFmR33+YvuZP5fndTnFuuseV88q4syO+vyl0IxbNbi4P0x7bPKSyo6q0Izbvv/njFXXYnt/mPbY5CWV7XIeGcNriToP0x6bvKSyo4rynqR7r0f9e2XaY5OXVLbr+6Pj3oz7/jDpsclLKjuqbEpPoWv5+7Ud89DNNu2xyUsqO655qPpdzyNKj6ufW5zZUbXdo0IIIYQQQnRWrv+f8q+v538n8/CLzMMvMg+/yDz8IvPwi8zDLzIPv8g8/CLz8IvMwy8yD7/IPPwi8/CLzMMvMg+//Ab3FJwp + </data> + </layer> + <layer name="trees" width="100" height="50"> + <data encoding="base64" compression="zlib"> + eJztlmtu00AURscJQQQk9hAglRoEiyBNeFRQttBKDfCDQpfAo5TAKoDSJCAoW8ijCQ/x2AJtCaJIsAWOlUSZUDsQJNc2+o50ZOvaM76eO7auMUIIIYQQQgghhBBCCCGEEEIIIYQQIq68cIx5iRv4ygk7m+AoJYy5glcTYWcynvfU4AN+xFo/ViPnZ/j8L3Kf556FiL+jyz1yXMX7HrmWiT3AhyG+xx2efRdXcI1a/MRPWOfaG2Jv8R2W/zDPLe65HYN6rJNjBaseuU6y/4LiiVsHfIo/qMMhXMIbeBOXsWqG34wfjxj/OAb1aJNjB1975GrvvyBI4UHT2+sNvMTazuFlZ3je5Nkt3MSjmHX2msNv1jxNbOFFa546Yxu4S/x7MK8Te7I4hZ9xy4zue/fcjbvnXzieYi1P+9TDNd0f547f5v4dvP7bt1QhdpjjkRD7Afv/GzUKWESH9UlgEg9gCrvGf+399JrHvt4xvW/pZIj1sP+/UWMRS5hhfY7hcTzRX7tBLDNhTcb51YRfD/v/GzXaZnTPnsE8zmABi3gWz+F5vOATt8cMzvM+c7lzzIZYj0nY7x692z/GaY32k6B79GvBTR170kl6jeRoLC49+v/INLXIYdaqyaBHF0IIQY8adgJiBPW1QgghhBBCCCGEEEL8G78A/dZihQ== + </data> + </layer> + <layer name="main" width="100" height="50"> + <data encoding="base64" compression="zlib"> + eJztmGlOFEEYhqtQNo3eAZUBNXoIERjcUK/gSqKIXgHccPcKgEuM2xGUAX8YtyPggEaN2w18v3RVpqboRpjunm5m3id50j3f9NR0V1XX8ilFCCGEEEIIIYQQQgghhBBCVksrbIPtsAN21hgnydANC7AH9sKdNcZJfDTshwNwEBbhUI1xEh9bj6fhGXgWjtQQHwkpOyo+CW8kcO+Nit+33XrXq4g/iSg3Kv6/70g83q4xnjZP0VmewefwBQfSzHmHNngPP8DHWd9Mhky2ZH0HAdIe0/A3/AhfIfYazsJr8Hq2t9d0/EQb/IIdcBRegGPwInyk1v87cwjPcRgegcO60teGQ2Li8RTGbLsHtX3d/u9RXX0ubsF7uhV26+Xugt9U9TtTUtXPJ2VcRew7/JH8o8TmHO7vvOljbl8bM/FRL3Yphfawe9AF+FlV93s5l7icL+G4B22xN6I9xE7nWcq4flFVnsOW+RCxTThuzuF64Cbu6Ra8De/Au/CeOQ+L30/hGeweVKPsFrgBboSt8IuKrvsow8pxv3+jgndpdw7bIwlO1fi7y/CKCsaWkoltQx1thztM3XXpINa1xjZZya8q+/bIY55Q5q4HOM6rYGyRfrtPB/bB/bAfDsBBWIRD8EBE3P2NPe+LKEvKOJhhe+QxT2jnLhmTpM826vgRRliesF6MwwkVjE8u7tyVdX+tNzLG+3nCeuG2h8wXsg7N29iZNXbfIfXRrqrrJul6moLTcEYF80Uex86ssWN3WN0kVU8nUP5JXdmXzalg7rbrnCzGzrzijt12XingvAf26mTqaRzlTDj7MtnP+fuJeo+decH2VZunfmnmTplXymY96K4fhbj1NKWD3N+MrGvNvqzNaYtizPLXM7avSp5a8qKf6rCWmcV/lOAcnDdtUDBHu65oVmxflTz1H/hXV3Jufm7NzzFKDu6YXp6n8z+710resWz2YEshe7xmx/ZVF8ndydju59bsXO/nsxec38h84H92r00j79hISF9djMhB+HuxsBzjSvkL9zzNvCMhhBBCCCGEEJIm/wAtkMkQ + </data> + </layer> + <layer name="signs" width="100" height="50"> + <data encoding="base64" compression="zlib"> + eJzt100Kg0AMBtBY3PdHz9k7Wo9Su+8RGvEAaqs4lPfgYzbDEBgISQQAAAAAAADfaOpt7wEAAPB/boXshG0hdQAwuerLAIuYY+eNO0eX5yPTH10M8cwMmdfRhQBQpHe139vmpnXOp4hL5r7jnwAAAAD86gMFzQct + </data> + </layer> + <layer name="events" width="100" height="50"> + <data encoding="base64" compression="zlib"> + eJzt2EEOgyAQBVBjMXHT+1+32yYqLS3tDPpewsYNMB9x4jQBAAAAAAAjm0v0CiBOKdvxyXMAgJ70Gbns5bHKp7v7mzXd68lr78xNVl95ddZb8xhNbX//2G/L/D0HdfLI5ap5ZOtFMtbo17Kej2zrAXiW9e6MFtGDyCHWKD3nVcjiWEQdZHFMPXJpuTvO8i8CANhafKsBgAE8ADCABsw= + </data> + </layer> +</map> diff --git a/tiled/map4.tmx b/tiled/map4.tmx new file mode 100644 index 0000000..ae383e9 --- /dev/null +++ b/tiled/map4.tmx @@ -0,0 +1,105 @@ +<?xml version="1.0" encoding="UTF-8"?> +<map version="1.0" orientation="orthogonal" renderorder="right-down" width="80" height="50" tilewidth="16" tileheight="16" nextobjectid="1"> + <tileset firstgid="1" name="atlas" tilewidth="16" tileheight="16" tilecount="1024" columns="32"> + <image source="atlas.png" width="512" height="512"/> + </tileset> + <tileset firstgid="1025" name="eventset" tilewidth="16" tileheight="16" tilecount="16" columns="4"> + <image source="eventset.png" width="64" height="64"/> + <tile id="1"> + <properties> + <property name="portal" value="1"/> + <property name="target" value="3-2"/> + </properties> + </tile> + <tile id="2"> + <properties> + <property name="portal" value="2"/> + <property name="target" value="5-1"/> + </properties> + </tile> + <tile id="3"> + <properties> + <property name="floor" value="true"/> + </properties> + </tile> + <tile id="4"> + <properties> + <property name="lowest" value="true"/> + </properties> + </tile> + <tile id="5"> + <properties> + <property name="portal" value="3"/> + <property name="target" value="6-1"/> + </properties> + </tile> + <tile id="7"> + <properties> + <property name="block" value="true"/> + </properties> + </tile> + <tile id="8"> + <properties> + <property name="spikes" value="true"/> + </properties> + </tile> + <tile id="9"> + <properties> + <property name="turnaround" value="true"/> + </properties> + </tile> + <tile id="10"> + <properties> + <property name="movingplatform" value="up"/> + </properties> + </tile> + <tile id="12"> + <properties> + <property name="checkpoint" value="true"/> + </properties> + </tile> + <tile id="15"> + <properties> + <property name="stop" value="true"/> + </properties> + </tile> + </tileset> + <tileset firstgid="1041" name="signs" tilewidth="16" tileheight="16" tilecount="4" columns="4"> + <image source="signs.png" width="64" height="16"/> + </tileset> + <layer name="bg" width="80" height="50"> + <data encoding="base64" compression="zlib"> + eJzt1klSFEEYxfHsA9CMDa0L8QI4yy2cGFyiF3AeluoFUFBxCVwAEQeWygUQ56VyAcB5Wgh/FhnRC1Iyk8qsXrzFLyoq4ov3KjKzKmrEGHMGZ9GCKlrRhnZ0oBNdqKHbc87mjSTOd83l6r2Bm7iFPuzDfhzAQRzCYRzBUfR7ztm81PmuuVy9k5jCNI7hOE7gJE5hAIMYwjBOe87ZvNT5rrlcvc/xAgs4h/O4gIu4hMu4gqu4huueczYvdb5rLlfvR3zCMkZxG3cwhnHcxT3cxwQeeM7ZvNT5rrlcvf+wDlMxZobLQ8ziEebwGE/wFM8wb/zmbF7qfNdcrt493PdiLxa5f4klvMJrvMFbvMN7fDB+czYvdb5rLlfvZo+1wv0q1vAZX/AV3/AdP/DT+M3ZvNT5rrlcvY09LaiiFW1oRwc60YUauj3nbF7qfNdcrt6YffrrYSfnLyS/yPMX0xuzT5s5da67sLvi7ok9fyH5RZ6/mN6Ynh5HdlHrF5Jf5PrF9Mac81/4jT+J3t+Q/CLf35je2H2y5zzV+fPNL/r8hfY29tQj/K+nniHfJVfvTntcXUWt33b5qdbPt7es71NoXmOuz/OWsX45v0+heVutXzM8b1nfp9C8rdavGZ63rO9T7Bo22/NWRUREJLtm+x/w/QdMlR2q7P0TEREREREREREREREREbE2AFiabOs= + </data> + </layer> + <layer name="plants" width="80" height="50"> + <data encoding="base64" compression="zlib"> + eJzt11kOgjAUheGGnWrisA3naRXO0yoUZzfledfYpiUQ6P8l502sHCxwjQEAAAAAAACA35qJMS2lnRT9S8ppqN5Gypj+vGzU21bZ0Z+Xm3q7Kw/6A0qjiGduTevVuU9466i7bsX6y/P9b641FgHr9HRsXxlU7Bq4Oum8zwHnvtSxK2UdaX+hUvV2Ua4l7C/mfZMF9k2YLPfNRN8zVWZcDy979XZQjvT3peHwmad6eylv+gNQEOb5MLZ5PvZ508Y2zzNv/meb513mTd6DkaeU/xoAAAAQrQ//nypV + </data> + </layer> + <layer name="treetrunks" width="80" height="50"> + <data encoding="base64" compression="zlib"> + eJzt1sEJwkAQBdAhOcU2VIIpTO3DWIlaiaYv5+LJgAEhIex78G9zGD4LsxEAAAAAAKzFpYroM9dq6U3W6Za93TOPgvrb1hG7+vdcO2Hmmb29MkNB/QEwnyZv0WbCPWLcIbvr9DfqmDllzksvMoPP32/vLUBR3ND/uKEAAAAAAPDtDd7dCNw= + </data> + </layer> + <layer name="main" width="80" height="50"> + <data encoding="base64" compression="zlib"> + eJztmFtu00AYhccR964CIUKhq+DS0pBy3UJJaKWWAFsA+sR9C9C+AksAWl6hS+DSRqIPLTvomWaMfiYztvENOzmf9HXkS+zJkRsfWylCCCGEEEIIIYQQQggheTDR+N8zqDdTzC8Ri571Mr+5QKmr8Bq8Dm/Am2JZrrf3uRX4zz2PbbdhB+7k+q2KJeIr/UHnt2j2XcKfZXgX9uA9eF8sy/X2Pg8iTvYQ2x7Bx3AiyaRqhLz+nuC7PYXP4HP4Ar4Uy3K9vc+riFxeY9sbuAqnRji/ogjzO5Qiv6rf38rM71yK/Kp+f2N+2Shjfp+Q2Skrv8PwCPwAP6rB/fwoxmPweMnzy0IZ8/uBbK4Y2ya/07AJv8HvanAfP4NxEp5NML+o/F19K65jpSVJ/yvivNNwBgY4dgM24WUsz8KWZ34SO/+eyN/Vt+I6VlraYn6+/uc6byfjefXnu/Ck+d/W2U1iXFB/d31ffnb+fTU4Rt9jXMfKA1//0+ct6to8j89fgLOw5TiWLz9f/q7sqsC/XJt5Evf7HJd/VYi6NjXhM659jfqWXet/qeHn46rff/MifMa1r1Hfsmv9iWD4+Xhc8pMdOYt2vx6X/HRHXmd+qdEd+Sec0fdC8Xt+CU6LMdzuWi/7dci45FcUzC8bdchPvl/vmtFl13SMtxjfwfcl9K065Cffr6+Y0eWK6Rhf4Fe4yfwOkO/X18zocs3cI3fhHvzt6cHj1p/D7rEBP5vRpatvJO3Laftzuwb5hd1jC26b0WX4Dk+/98ja85L2v1FEv/e4o5hfVi4G/n6cV38mhBBC6sA+f57HuQ== + </data> + </layer> + <layer name="signs" width="80" height="50"> + <data encoding="base64" compression="zlib"> + eJzt1jENAAAIwDAODIB/sUjgJCStgp2LAAAAAAAAAAAAADad1wUAAPBTeWkAAHhlADEZACw= + </data> + </layer> + <layer name="spikes" width="80" height="50"> + <data encoding="base64" compression="zlib"> + eJzt1sEJACAMBMEY7b9mEfFnChBn4B6BFLARAAAAAAAAAAAAQM96AADwm5Z71b06eVxa+fyllgYAgGdNLVUASg== + </data> + </layer> + <layer name="events" width="80" height="50"> + <data encoding="base64" compression="zlib"> + eJzt2NEKwiAUBuBRBkUEvf/TduFVQq151JV9H3ixXcj4ncezLQsAAAAAzOOe9n4CYISjvU5nKdWNT+fdyvmW1eZHJr8Y+cXIL+Zdfme5bhY9z8lqc+vRY9W4FvP+2ruwV26Mt7a2N2vd3CW9Hjyr/XZWqzL5xcgPvsvBnmIAdT6m9qwse+G16/L+LL10i96jR/9S/t+Yxaj8ZiY/gLZO6iB/6gFmoAhP + </data> + </layer> +</map> diff --git a/tiled/map5.tmx b/tiled/map5.tmx new file mode 100644 index 0000000..e3091e3 --- /dev/null +++ b/tiled/map5.tmx @@ -0,0 +1,110 @@ +<?xml version="1.0" encoding="UTF-8"?> +<map version="1.0" orientation="orthogonal" renderorder="right-down" width="100" height="45" tilewidth="16" tileheight="16" nextobjectid="1"> + <tileset firstgid="1" name="eventset" tilewidth="16" tileheight="16" tilecount="16" columns="4"> + <image source="eventset.png" width="64" height="64"/> + <tile id="1"> + <properties> + <property name="portal" value="1"/> + <property name="target" value="4-2"/> + </properties> + </tile> + <tile id="2"> + <properties> + <property name="portal" value="2"/> + <property name="target" value="6-1"/> + </properties> + </tile> + <tile id="3"> + <properties> + <property name="floor" value="true"/> + </properties> + </tile> + <tile id="4"> + <properties> + <property name="lowest" value="true"/> + </properties> + </tile> + <tile id="5"> + <properties> + <property name="portal" value="3"/> + <property name="target" value="6-1"/> + </properties> + </tile> + <tile id="7"> + <properties> + <property name="block" value="true"/> + </properties> + </tile> + <tile id="8"> + <properties> + <property name="spikes" value="true"/> + </properties> + </tile> + <tile id="9"> + <properties> + <property name="movingplatform" value="down"/> + </properties> + </tile> + <tile id="10"> + <properties> + <property name="movingplatform" value="up"/> + </properties> + </tile> + <tile id="12"> + <properties> + <property name="checkpoint" value="true"/> + </properties> + </tile> + <tile id="14"> + <properties> + <property name="movingplatform" value="right"/> + </properties> + </tile> + <tile id="15"> + <properties> + <property name="stop" value="true"/> + </properties> + </tile> + </tileset> + <tileset firstgid="17" name="signs" tilewidth="16" tileheight="16" tilecount="4" columns="4"> + <image source="signs.png" width="64" height="16"/> + </tileset> + <tileset firstgid="21" name="atlas" tilewidth="16" tileheight="16" tilecount="1024" columns="32"> + <image source="atlas.png" width="512" height="512"/> + </tileset> + <layer name="bg" width="100" height="45"> + <data encoding="base64" compression="zlib"> + eJzt07dNBFEYxPE9vA+ABji8DYAG8KYLvOkCb8KDBvAmBBrAmxBoAG9CoAD+BEgkLE/Le9ILJvgFK303mtHtJoIgWMAimtCMFrSiDe3oQCe60G14Zysv4aCfi0xbm3ewiz30oBd96McABjGEYYxg1PDOVp6Lfj5vvsQVrjGGcUxgElOYxgxmMYd5wztbeS76+bz5De/4wBKWsYJVrGEdG9jEFrYN72zluejn8+b8WBAUoBD7PB/gEEc4xglOcYZzXARmd7byXPTzeXM9GQ1oxA3Pt7jDPR7wiCc84wWvgdmdrTwX/Xze/NXtWwxJSEYKUpGGdGQgE1mGd7byXPTzefPPbkWIoxglKEUZylGBSlQZ3tnKc9HP581R3pU8A7byXPTzeXOUd+XrdzWoRV1Iro08F/183hylW3XI/xulW1iei34+b47y7WYjB7l/dLOR56Kfz5ujvivf35qtd+W3PBf9fN78s1tNBGHdbOS56Ofz5v92C9tsI89FP583x0VEREREREREREREREREREREREREREREPPAJYQJbxQ== + </data> + </layer> + <layer name="plants" width="100" height="45"> + <data encoding="base64" compression="zlib"> + eJzt2MttAjEQxnHDtkEfXCJBE9BJIhFog3dEqoCERxu8KYbvCFy8Ym12dvn/pDmsfLFnLHl2nAMAAAAAAEBI31XnuopeNe+dwKelGrWpkxmfqsXXk/WoJWH3Auf6qsXgyXp8BK5HlrtRFnOdf2EkB1nuRllsdf6dkRxYuhuxFKmnsnQ3AAA2TPQuTBU/nvdhqPWRYsw7EtVK+V0rNp48/2n9X7GkHlGdlN+z4uLJ817rB8WRegQ3U05/jeaVGSti6eS9gQDS9hd4jbT9BbJpJs7VU8yd0/YXsRSlry/zzP22fyhKX/8uM3erfX2jcv/9DjN3y732Yz2YuftZ/q8DAAAAAABA/q7mHjT2 + </data> + </layer> + <layer name="treetrunks" width="100" height="45"> + <data encoding="base64" compression="zlib"> + eJzt2EsOAUEUheHStQyPdXjbSGNZGGAZGGAZGGAjiCMhElEDkXR3Vf1fciMxcTntdKeMAQAAAAAgPlVrTM3mvQVeOsqiSx7wyCgxZqyZJHlvgoeFclhqVuRRCDvlsCeL4H32YF338YamGeH9vFGA7+zqwWYpn31i9+rBA12ICF113d++XPuu9/GW6vfpZzSD5ysQM9fZIGeG/5mqW2aa+Y8d4zob5MzwP2vlsNFs6fzMfeuSo3I4ac4e53FJ/HyuC7VLfM0jC+scPrNieY4okrYN97+PcHRLxvQ4vy2EVDkMNENHHmXrX8/7tOuvWta/nvdpVwAAAAAAAITnDllOMZ4= + </data> + </layer> + <layer name="main" width="100" height="45"> + <data encoding="base64" compression="zlib"> + eJztmXdy00AUxlcGjgA4jQwBrgCkQAYOASSxY0KAK0AoM6GEK+BQQucKJEDC0I4ACe0P2hEgBQb4duw3ft6sZFlry5Z538xvVlrL0krf9qeUSCQSiUQikUgkEolEIlHj9NxT6gU4AU56jS5NNHWnGl2C2ukzPPgCpsCVhPox2EJ+eHiXFOiDF4Mt4EcGx1kLoxbPZuMrYmhpP3rA/gT4cd4n36V9TINr4Dq4AW6y33g/2AbaQQfoBF3RHxkoah/N6sfmENdoP/y8qqQ58Bj0Fpk37kvSv/WBfjAA9kV8np/yqlA39PjB28cM8m7V+Fn1VjXtg+r5ON71OHinCt9av79ZJ/l9h8AwGAEZkHUvdpl030l1o4eNHws4f1bjZ9VbYf2Y9Erf3cYoyDE/cuy+E+AMOAvOqejtUesUnnEaTIC3OF8ES6pQN96DD6p5+yubXhvl5H7kA/532yvVc9OLTB3K6aereF4eTIOfOF8GK2AVrIFfKll+mKqmv+L1fAXvuwrWYn7vR3jeLJgDW8BWkAZtoB10WPrOJClp649FfOclPXaB3WAP2At6vcK40S9+xKplr9Q2h8AwOMKOR3T/aYxlSVLS/Gh15Rrkx4RPPs2fxsAxrzS3HvPJ+4P//I2z4P+ZaP50AVwEl8Dl4rktbxvoTljfRHsXfvtTYbDtYZk6aqnDlIbdA6f5U9BaxyRpY3dcY8SkpQ5TGnYPnOZPre6Hy5o4rPSa8Q64C+6B+yx9AB6G+G40fwr6/nw+Ze4LNLNoP7FS+4jDq2oV5Md85b8HiuKIfM+Z0jeqfB/mpXEd5bvMI5I4p63kx4zDvSmOyPecKf2hyvdhvhrXUb7LPKJRc1pXBfmx4HBfipNsiIjLniW1Td3uXnnr9xO5KI7gF2NqhLgPtRKPW7kQxQ9qm7rdfQPfA+7B4whPwFPl3le7ir//uIG5NgxzrtPtLK7L96gPIT3s2fdf+HHWYR5BMWXdzjaCTanCWsD2TmYc4SP4VMuPG1FmvewEXd76tWGYc50ewDc4mHKv69VIz5n0/Ir82AF2gl2pwlqAysrLbMYRfqvm9KMexLWG8Sxtk0hXKGOz+MGlYy9J9kOL4no8RjBQPO4rHqeL+fq8XnHuWon38ba+Phvwuy0/7jUlxfXMcYnie3ScYbjGuUUikUgkEolEIlHr6x9k/QMl + </data> + </layer> + <layer name="signs" width="100" height="45"> + <data encoding="base64" compression="zlib"> + eJztzsEJACAMALGuoLj/rK5QqVAoyfseFwEAAAAAAHnrcwcAAAAAAABQdboHHuzuAQAAAADGu3AnAEk= + </data> + </layer> + <layer name="spikes" width="100" height="45"> + <data encoding="base64" compression="zlib"> + eJzt1sEJACAMBMFgD8b+OxXRV8CXPmdguRYuAgAAAAAAAAAAAHg12i7LrgAAgLt+/jMAAAAA8McEmTYA3Q== + </data> + </layer> + <layer name="events" width="100" height="45"> + <data encoding="base64" compression="zlib"> + eJzt1k1OAkEQhuFCMBGNwa3eDOJOLoHeROEgmngQF9wDXVkkkzDg0MzIdPXf+yQVFvNDTX/T0y0CAAAAAMBpd6EbAGBmVBXikFMeE8exVNaZnPLo4rb6fdV601pqrWrHrw/Ov7JoSsrNY+td60N2Y/B55LxRQ/lSUh73Wg9aTwORudaX7I/xOmRzlZLyaHrPY3r+2Prxbao1k79ZPDac63P9d70XJeWx0HrWetHa6PfqW+tnYN8HeZzm2iv7sJ1/5AHkx7W23ph1gVS1Wa9zWCvOXXPb7GHHjmqrlDws9DFu5BGfkOM/NPiP1DAf4uI7j67fxD77SHVPm2seKfP1/CHzcF1/8Y9rLNWfv+u+ue19redG1/vENif7eJdj+vak0ucx5BFXHnU55CGJ9AgAAAA/LkM3AMDEL3mQEv0= + </data> + </layer> +</map> diff --git a/tiled/map6.tmx b/tiled/map6.tmx new file mode 100644 index 0000000..9d8b304 --- /dev/null +++ b/tiled/map6.tmx @@ -0,0 +1,120 @@ +<?xml version="1.0" encoding="UTF-8"?> +<map version="1.0" orientation="orthogonal" renderorder="right-down" width="80" height="65" tilewidth="16" tileheight="16" nextobjectid="1"> + <tileset firstgid="1" name="atlas" tilewidth="16" tileheight="16" tilecount="1024" columns="32"> + <image source="atlas.png" width="512" height="512"/> + </tileset> + <tileset firstgid="1025" name="eventset" tilewidth="16" tileheight="16" tilecount="16" columns="4"> + <image source="eventset.png" width="64" height="64"/> + <tile id="1"> + <properties> + <property name="portal" value="1"/> + <property name="target" value="5-2"/> + </properties> + </tile> + <tile id="2"> + <properties> + <property name="portal" value="2"/> + <property name="target" value="7-1"/> + </properties> + </tile> + <tile id="3"> + <properties> + <property name="floor" value="true"/> + </properties> + </tile> + <tile id="4"> + <properties> + <property name="lowest" value="true"/> + </properties> + </tile> + <tile id="5"> + <properties> + <property name="portal" value="3"/> + <property name="target" value="6-1"/> + </properties> + </tile> + <tile id="7"> + <properties> + <property name="block" value="true"/> + </properties> + </tile> + <tile id="8"> + <properties> + <property name="spikes" value="true"/> + </properties> + </tile> + <tile id="9"> + <properties> + <property name="movingplatform" value="down"/> + </properties> + </tile> + <tile id="10"> + <properties> + <property name="movingplatform" value="up"/> + </properties> + </tile> + <tile id="11"> + <properties> + <property name="fake" value="true"/> + </properties> + </tile> + <tile id="12"> + <properties> + <property name="checkpoint" value="true"/> + </properties> + </tile> + <tile id="13"> + <properties> + <property name="movingplatform" value="left"/> + </properties> + </tile> + <tile id="14"> + <properties> + <property name="movingplatform" value="right"/> + </properties> + </tile> + <tile id="15"> + <properties> + <property name="stop" value="true"/> + </properties> + </tile> + </tileset> + <tileset firstgid="1041" name="signs" tilewidth="16" tileheight="16" tilecount="4" columns="4"> + <image source="signs.png" width="64" height="16"/> + </tileset> + <layer name="bg" width="80" height="65"> + <data encoding="base64" compression="zlib"> + eJzt0VmWTgcUBeC/BlBVClVUFaomoC1NNMEEEE0kmmACEhE9wQQkekGECRDRRhcmoA8SQkxAE220yTcB/7oP977th2+dt7322qenVquNZBSjGcNHjGUc45nAx0xkEpMZzBCGMozhjKCRJprpRQu96UNfWmmjH/1pp4NOBjCQQXTRXUJe1X1mMotPmc1nfM4c5jKP+XzBAhayiClMZRqfMJ0ZdXbtKflPRfOq7vMNy1jOClayitWsYS3r+Jb1bGAji/mSr1jC1yyts2vZfyqaV3WfbWxnBzvZxQ/sZg97+ZF9/MR+DrCJ7/iezWxha51dy/5T0byq+xzlGMc5wUl+5RSnOcNZzvEb57nAQQ7xM4f5hSN1di37T0Xzqu5znd+5wU1u8Qd/cps7/MVd7vE397nIJS5zhatcq7Nr2X8qmld1n6c84zkveMm/vOI1b3jLO97zH7WGWu2B85BHPOYfntTZtew/Fc2ruk8fW/SllTb60Z92OuhkAAMZRBfdNNJEM71ooXedXcv+U9G8qvs0NZTrQ7uW/aeieVX3KXu/iIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiCjmf+jpWGQ= + </data> + </layer> + <layer name="plants" width="80" height="65"> + <data encoding="base64" compression="zlib"> + eJzt2TkOwkAMBdBRqOAmcE3We7BzDXZOhbsUUUI0gSLiPcnNKEX0C8vjSQkAAAAAIN+xSOlUfP5uOEhpNPj9//TNM7J7tchvHNlN5AcAAPBXFnFfXEatWtwbqdpFbvuog/yy3CK3e9RDfgAV0+iNs6i5HlmraY5Zx9kmaiu/Wk1zzDnOLlFX+dXq+xyjx3Sjx3SjxwAAAPyXnD2EN8xSzh7CG2YpZw/R990fAAAA3/MG3HQmtg== + </data> + </layer> + <layer name="treetrunks" width="80" height="65"> + <data encoding="base64" compression="zlib"> + eJzt2DEKAjEQBdCENOoxFFlXvIVH92KmSRMJLFkkGt4rhxTDL2aYhAAAAAAAAAAAAAAwxjWN7gDgdx3zjDyZk93WnN1dfl9xkesm59ENTOYZR3fAP2vtVLv20yPnsVSZtHZqqdfvi1J/RTMRAIA5HZK7Yo9b8ocHAABAnzd7mARG + </data> + </layer> + <layer name="main" width="80" height="65"> + <data encoding="base64" compression="zlib"> + eJztmutOE0EYhndNFChXIQpFehUeOBUP6C14NiDoLaCoiaByCxgP/7wFLIn6S29BaYyHH96C75edL5muU1l2utuh+z7Jk5ndbunwtvv18G0UEUIIIYQQQgghhBBCyMEYPdK5vQ534HvYgruO7XdxqUsMmobJ7yoyuQZfYf4afoN7sA2/WtufccwX+Avz331ZcVhofmtxks8Ixg8Yj2McgyfgSTOKf+LkmBocLeh1mD4nQkbz247/zczeTt82BRsF5dc4hPkJp5HHGXgWnos7t9O3NeEC8wtyrSGuqRsL1lrnMJ/3sNmj//sw5RcizM8P5ucH8/OD+fnB/PxgfvmpRcwvK0fhMTgEh+EInIo6P5OS7ozDCViHk/AUbPZ1ReFyHt+VL8DL8Ir53jwNZ+AsnIPz8E7fVhg2S8hsFd6D901+1+ENeBPegrf7t7zgeYrMNuALuFXB369d5x/Jjuv8KwPpxzyCj+GT8h625xR5/mnvRXoqabUf8wa+7e3DDgzSe3kAH8J101upWfPvUdI7+Bmxb+Wqoy2Mu44eyzicgHU4WULfKi96/pRRY1x1dA9j29FjmYYzcDZO+ltjxqL6VnnR86eMGpO3jrYCzk+e25fwI+afrP32e1/ZNSfdAw759af150eU1Gi9VsN+79uv5mhd24n+f+3HRRxzyXHcYqomym8wUlf0+MWA85PndhkOmxot87twJU6uRRjKsOYlcz/7vvZcrgNZsbbtcdlREyW/Neu41YDz0/q9CZ+Z+qTz5xlrlda1jS5/Z78x/TiSn33OqkVe9zBISH76vJZ13cMgwd+g/WB+fjA/P5ifH8zPjyrm5+pH5tkvVDE/7UfKdw3tR9r76xn3C1XsAbv6kVn2t1P7q0q3fuRB9xNCCCGEEOLLXwxPplk= + </data> + </layer> + <layer name="signs" width="80" height="65"> + <data encoding="base64" compression="zlib"> + eJzt2DENADAMA0EPJdDwB5u1DKKodwh+tJwAAAAAAAAAAAAAAL+5Z7oAAIBtyoYEAAAG+LMBAAB4Nc6mAEE= + </data> + </layer> + <layer name="spikes" width="80" height="65"> + <data encoding="base64" compression="zlib"> + eJztwTEBAAAAwqD1T20ND6AAAAAAAAAAAAAAAAAAAAAAAAAAAL4NUUAAAQ== + </data> + </layer> + <layer name="events" width="80" height="65"> + <data encoding="base64" compression="zlib"> + eJzt2csOgjAQBVCidYUa//9rjTsXSIdQKIPnJCxgQ3PpY0qHAQAAAICMXqV3C87tKt90so+JUuYvptVyk+M8+fFP7mX+PoPxq81r171nJY+M+QAATHmoa5oa5RliT82e9LE4e904WcUYfzn5bnVnPC/Yc15z7hIXyWHqX/iR89uyba368Rny61mrZMyv1uYec+QRtZizl56/R95j/VhHfgBATxe1Bxv6Vesuff7hDBgA2rhZUwF29waAIgVv + </data> + </layer> +</map> diff --git a/tiled/signs.png b/tiled/signs.png Binary files differnew file mode 100644 index 0000000..874ac34 --- /dev/null +++ b/tiled/signs.png diff --git a/tiled/signs_OLD.png b/tiled/signs_OLD.png Binary files differnew file mode 100644 index 0000000..70840d5 --- /dev/null +++ b/tiled/signs_OLD.png diff --git a/tiled/tiled.lua b/tiled/tiled.lua new file mode 100644 index 0000000..0e3b590 --- /dev/null +++ b/tiled/tiled.lua @@ -0,0 +1,244 @@ +-- see https://love2d.org/wiki/TiledMapLoader for latest version +-- loader for "tiled" map editor maps (.tmx,xml-based) http://www.mapeditor.org/ +-- supports multiple layers +-- NOTE : function ReplaceMapTileClass (tx,ty,oldTileType,newTileType,fun_callback) end +-- NOTE : function TransmuteMap (from_to_table) end -- from_to_table[old]=new +-- NOTE : function GetMousePosOnMap () return gMouseX+gCamX-gScreenW/2,gMouseY+gCamY-gScreenH/2 end + +kTileSize = 32 +kMapTileTypeEmpty = 0 +local floor = math.floor +local ceil = math.ceil +local max = math.max +local min = math.min +local abs = math.abs +gTileMap_LayerInvisByName = {} + +function TiledMap_Load (filepath,tilesize,spritepath_removeold,spritepath_prefix) + spritepath_removeold = spritepath_removeold or "../" + spritepath_prefix = spritepath_prefix or "" + kTileSize = tilesize or kTileSize or 32 + gTileGfx = {} + + local tiletype,layers = TiledMap_Parse(filepath) + gMapLayers = layers + for first_gid,path in pairs(tiletype) do + path = spritepath_prefix .. string.gsub(path,"^"..string.gsub(spritepath_removeold,"%.","%%."),"") + local raw = love.image.newImageData(path) + local w,h = raw:getWidth(),raw:getHeight() + local gid = first_gid + local e = kTileSize + for y=0,floor(h/kTileSize)-1 do + for x=0,floor(w/kTileSize)-1 do + local sprite = love.image.newImageData(kTileSize,kTileSize) + sprite:paste(raw,0,0,x*e,y*e,e,e) + gTileGfx[gid] = love.graphics.newImage(sprite) + gid = gid + 1 + end + end + end +end + +function TiledMap_GetMapW () return gMapLayers.width end +function TiledMap_GetMapH () return gMapLayers.height end + +-- returns the mapwidth actually used by tiles +function TiledMap_GetMapWUsed () + local maxx = 0 + local miny = 0 + local maxy = 0 + for layerid,layer in pairs(gMapLayers) do + if (type(layer) == "table") then for ty,row in pairs(layer) do + if (type(row) == "table") then for tx,t in pairs(row) do + if (t and t ~= kMapTileTypeEmpty) then + miny = min(miny,ty) + maxy = max(maxy,ty) + maxx = max(maxx,tx) + end + end end + end end + end + return maxx + 1,miny,maxy+1 +end + +-- x,y= position for nearest-distance(square,not round), z= layer, maxrad= optional limit for searching +-- returns x,y +-- if x,y can be far outside map, set a sensible maxrad, otherwise it'll get very slow since searching outside map isn't optimized +function TiledMap_GetNearestTileByTypeOnLayer (x,y,z,iTileType,maxrad) + local w = TiledMap_GetMapW() + local h = TiledMap_GetMapW() + local maxrad2 = max(x,w-x,y,h-y) if (maxrad) then maxrad2 = min(maxrad2,maxrad) end + if (TiledMap_GetMapTile(x,y,z) == iTileType) then return x,y end + for r = 1,maxrad2 do + for i=-r,r do + local xa,ya = x+i,y-r if (TiledMap_GetMapTile(xa,ya,z) == iTileType) then return xa,ya end -- top + local xa,ya = x+i,y+r if (TiledMap_GetMapTile(xa,ya,z) == iTileType) then return xa,ya end -- bot + local xa,ya = x-r,y+i if (TiledMap_GetMapTile(xa,ya,z) == iTileType) then return xa,ya end -- left + local xa,ya = x+r,y+i if (TiledMap_GetMapTile(xa,ya,z) == iTileType) then return xa,ya end -- right + end + end +end + +function TiledMap_GetMapTile (tx,ty,layerid) -- coords in tiles + local row = gMapLayers[layerid][ty] + return row and row[tx] or kMapTileTypeEmpty +end + +function TiledMap_SetMapTile (tx,ty,layerid,v) -- coords in tiles + local row = gMapLayers[layerid][ty] + if (not row) then row = {} gMapLayers[layerid][ty] = row end + row[tx] = v +end + +-- todo : maybe optimize during parse xml for types registered as to-be-listed before parsing ? +function TiledMap_ListAllOfTypeOnLayer (layerid,iTileType) + local res = {} + local w = TiledMap_GetMapW() + local h = TiledMap_GetMapH() + for x=0,w-1 do + for y=0,h-1 do + if (TiledMap_GetMapTile(x,y,layerid) == iTileType) then table.insert(res,{x=x,y=y}) end + end + end + return res +end + +function TiledMap_GetLayerZByName (layername) for z,layer in ipairs(gMapLayers) do if (layer.name == layername) then return z end end end +function TiledMap_SetLayerInvisByName (layername) gTileMap_LayerInvisByName[layername] = true end + +function TiledMap_IsLayerVisible (z) + local layer = gMapLayers[z] + return layer and (not gTileMap_LayerInvisByName[layer.name or "?"]) +end + +function TiledMap_GetTilePosUnderMouse (mx,my,camx,camy) + return floor((mx+camx-love.graphics.getWidth()/2)/kTileSize), + floor((my+camy-love.graphics.getHeight()/2)/kTileSize) +end + +function TiledMap_DrawNearCam (camx,camy,fun_layercallback) + camx,camy = floor(camx),floor(camy) + local screen_w = love.graphics.getWidth() + local screen_h = love.graphics.getHeight() + local minx,maxx = floor((camx-screen_w/2)/kTileSize),ceil((camx+screen_w/2)/kTileSize) + local miny,maxy = floor((camy-screen_h/2)/kTileSize),ceil((camy+screen_h/2)/kTileSize) + for z = 1,#gMapLayers do + if (fun_layercallback) then fun_layercallback(z,gMapLayers[z]) end + if (TiledMap_IsLayerVisible(z)) then + for x = minx,maxx do + for y = miny,maxy do + local gfx = gTileGfx[TiledMap_GetMapTile(x,y,z)] + if (gfx) then + local sx = x*kTileSize - camx + screen_w/2 + local sy = y*kTileSize - camy + screen_h/2 + love.graphics.draw(gfx,sx,sy) -- x, y, r, sx, sy, ox, oy + end + end + end + end + end +end + + +-- ***** ***** ***** ***** ***** xml parser + + +-- LoadXML from http://lua-users.org/wiki/LuaXml +function LoadXML(s) + local function LoadXML_parseargs(s) + local arg = {} + string.gsub(s, "(%w+)=([\"'])(.-)%2", function (w, _, a) + arg[w] = a + end) + return arg + end + local stack = {} + local top = {} + table.insert(stack, top) + local ni,c,label,xarg, empty + local i, j = 1, 1 + while true do + ni,j,c,label,xarg, empty = string.find(s, "<(%/?)([%w:]+)(.-)(%/?)>", i) + if not ni then break end + local text = string.sub(s, i, ni-1) + if not string.find(text, "^%s*$") then + table.insert(top, text) + end + if empty == "/" then -- empty element tag + table.insert(top, {label=label, xarg=LoadXML_parseargs(xarg), empty=1}) + elseif c == "" then -- start tag + top = {label=label, xarg=LoadXML_parseargs(xarg)} + table.insert(stack, top) -- new level + else -- end tag + local toclose = table.remove(stack) -- remove top + top = stack[#stack] + if #stack < 1 then + error("nothing to close with "..label) + end + if toclose.label ~= label then + error("trying to close "..toclose.label.." with "..label) + end + table.insert(top, toclose) + end + i = j+1 + end + local text = string.sub(s, i) + if not string.find(text, "^%s*$") then + table.insert(stack[#stack], text) + end + if #stack > 1 then + error("unclosed "..stack[stack.n].label) + end + return stack[1] +end + + +-- ***** ***** ***** ***** ***** parsing the tilemap xml file + +local function getTilesets(node) + local tiles = {} + for k, sub in ipairs(node) do + if (sub.label == "tileset") then + tiles[tonumber(sub.xarg.firstgid)] = sub[1].xarg.source + end + end + return tiles +end + +local function getLayers(node) + local layers = {} + layers.width = 0 + layers.height = 0 + for k, sub in ipairs(node) do + if (sub.label == "layer") then -- and sub.xarg.name == layer_name + layers.width = max(layers.width ,tonumber(sub.xarg.width ) or 0) + layers.height = max(layers.height,tonumber(sub.xarg.height) or 0) + local layer = {} + table.insert(layers,layer) + layer.name = sub.xarg.name + --~ print("layername",layer.name) + width = tonumber(sub.xarg.width) + i = 0 + j = 0 + for l, child in ipairs(sub[1]) do + if (j == 0) then + layer[i] = {} + end + layer[i][j] = tonumber(child.xarg.gid) + j = j + 1 + if j >= width then + j = 0 + i = i + 1 + end + end + end + end + return layers +end + +function TiledMap_Parse(filename) + local xml = LoadXML(jin.filesystem.read(filename)) + local tiles = getTilesets(xml[2]) + local layers = getLayers(xml[2]) + return tiles, layers +end
\ No newline at end of file diff --git a/tiled/tileset.png b/tiled/tileset.png Binary files differnew file mode 100644 index 0000000..b2e4407 --- /dev/null +++ b/tiled/tileset.png |