├── JSONMap.json
├── LICENSE
├── README.md
├── conf.lua
├── dkjson.lua
├── isomap.lua
├── lovebird.lua
├── main.lua
├── minimalDemo.lua
├── props
├── pixelTree.png
└── praca.png
└── textures
├── DirtTile.png
├── GrassTile.png
├── SelectTile.png
├── WaterTile.png
├── ls.png
├── rd.png
├── rdl.png
├── rdr.png
├── rdrd.png
├── rdv.png
└── water.png
/JSONMap.json:
--------------------------------------------------------------------------------
1 | {
2 | "textures":
3 | [
4 | {
5 | "file": "ls.png",
6 | "mnemonic": "grass"
7 | },
8 | {
9 | "file": "rd.png",
10 | "mnemonic": "road"
11 | },
12 | {
13 | "file":"rdl.png",
14 | "mnemonic":"roadL"
15 | },
16 | {
17 | "file":"rdv.png",
18 | "mnemonic":"roadV"
19 | },
20 | {
21 | "file":"rdr.png",
22 | "mnemonic":"roadR"
23 | },
24 | {
25 | "file":"rdrd.png",
26 | "mnemonic":"roadD"
27 | },
28 | {
29 | "file":"water.png",
30 | "mnemonic":"water"
31 | }
32 | ],
33 |
34 | "props":
35 | [
36 | {
37 | "file": "pixelTree.png",
38 | "mnemonic": "tree",
39 | "origin" : "72|245"
40 | },
41 | {
42 | "file":"praca.png",
43 | "mnemonic":"post",
44 | "origin":"15|65"
45 | }
46 | ],
47 |
48 | "data":
49 | [
50 | [["water"],["water"],["water"],["water"],["water"],["water"],["water"],["water"],["water"],["water"],["water"],["water"],["water"],["water"],["water"]]
51 | [["grass", "tree"],["grass"],["grass"],["grass"],["grass"],["grass"],["grass"],["grass"],["grass"],["grass"],["grass", "tree"],["grass"],["grass"],["grass"],["grass"]]
52 | [["grass"],["grass", "tree"],["grass"],["grass"],["grass"],["grass"],["grass"],["grass"],["grass"],["grass"],["grass"],["grass"],["grass"],["grass"],["grass"]]
53 | [["grass"],["grass"],["roadD"],["road"], ["road"], ["road"], ["road"], ["road"], ["road"], ["road"], ["road"], ["roadR"],["grass"],["grass"],["grass"]]
54 | [["grass"],["grass"],["roadV"],["grass"],["grass"],["grass"],["grass"],["grass"],["grass"],["grass", "post"],["grass"],["roadV"],["grass"],["grass", "tree"],["grass"]]
55 | [["grass"],["grass"],["roadV"],["grass"],["grass"],["grass"],["grass"],["grass"],["grass"],["grass"],["grass"],["roadV"],["grass"],["grass"],["grass"]]
56 | [["grass"],["grass"],["roadV"],["grass"],["grass"],["grass", "tree"],["grass"],["grass"],["grass"],["grass"],["grass"],["roadV"],["grass"],["grass"],["grass", "tree"]]
57 | [["grass"],["grass"],["roadV"],["grass"],["grass"],["grass"],["grass"],["grass"],["grass", "tree"],["grass"],["grass"],["roadV"],["grass"],["grass"],["grass"]]
58 | [["grass"],["grass"],["roadV"],["grass"],["grass"],["grass"],["grass"],["grass"],["grass"],["grass"],["grass"],["roadV"],["grass"],["grass"],["grass"]]
59 | [["grass", "tree"],["grass"],["roadV"],["grass", "tree"],["grass"],["grass"],["grass"],["grass", "tree"],["grass"],["grass"],["grass"],["roadV"],["grass"],["grass", "tree"],["grass"]]
60 | [["grass"],["grass"],["roadV"],["grass"],["grass"],["grass"],["grass"],["grass"],["grass"],["grass"],["grass"],["roadV"],["grass"],["grass"],["grass"]]
61 | [["grass"],["grass"],["roadV"],["grass"],["grass"],["grass"],["grass"],["grass"],["grass"],["grass", "tree"],["grass"],["roadV"],["grass"],["grass"],["grass"]]
62 | [["grass"],["grass"],["roadV"],["grass"],["grass"],["grass", "tree"],["grass"],["grass"],["grass"],["grass"],["grass"],["roadV"],["grass"],["grass"],["grass"]]
63 | [["grass", "tree"],["grass"],["roadV"],["grass"],["grass"],["grass"],["grass"],["grass", "tree"],["grass"],["grass"],["grass"],["roadV"],["grass"],["grass"],["grass"]]
64 | [["grass"],["grass"],["roadV"],["grass"],["grass"],["grass"],["grass"],["grass"],["grass"],["grass"],["grass"],["roadV"],["grass"],["grass"],["grass", "tree"]]
65 | [["grass"],["grass"],["roadV"],["grass", "tree"],["grass"],["grass"],["grass"],["grass", "tree"],["grass"],["grass"],["grass"],["roadV"],["grass"],["grass", "tree"],["grass"]]
66 | ],
67 |
68 | "general":
69 | [
70 | {
71 | "name":"Simple road",
72 | "version":"v0.1",
73 | "lighting":"255|255|255"
74 | }
75 | ]
76 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Pedro Polez
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # isomap-love2d
2 | Isometric map engine/library for Love2D
3 |
4 |
5 |
6 | ## What's this?
7 | This is a simple isometric map decoder and renderer. It can load maps with information stored on a JSON file and render the isometric map to the screen with a simple function call and a few parameters.
8 | The example uses mouse wheel to zoom in and zoom out, and arrow keys to move the map around.
9 |
10 | ## What now?
11 | I'll keep on adding things, such as elevation and maybe programmable tiles. I'll make a nice level editor too if needed. Won't be fast though.
12 |
13 | ### Modules used:
14 | * [DKJson](https://github.com/LuaDist/dkjson) for json parsing. Used by the library itself.
15 | * [Lovebird](https://github.com/rxi/lovebird) since it helps wonders with table content viewing. Used in the demo included.
16 | * [Kenney's isometric sprites](https://kenney.nl/) since I suck at drawing. Used in the demo.
17 | * [segfaultd](https://github.com/danielpontello) for drawing an example notice board, can be seen in the demo.
18 |
19 | # Great, but how do I use it?
20 | * First, create a JSON file, a "props" new folder, and a "textures" new folder in the root of your love project. Your project will look like this:
21 |
22 |
23 | * Add all textures you want to use for the ground layer to the *"textures"* folder. They **need** to have absolutely the same dimensions.
24 |
25 | * Add all prop textures you will place on your map to the *"props"* folder. These can be any dimensions you'd like.
26 |
27 | And you should be set up to create everything you need.
28 |
29 | # JSON map structure
30 | The basic JSON map will look a bit like this:
31 | ```JSON
32 | {
33 | "textures":
34 | [
35 | {
36 | "file": "myTexture.*",
37 | "mnemonic": "myTexture"
38 | }
39 | ],
40 |
41 | "props":
42 | [
43 | {
44 | "file": "myProp.*",
45 | "mnemonic": "myProp",
46 | "origin" : "50|72"
47 | }
48 | ],
49 |
50 | "data":
51 | [
52 | [["myTexture"],["myTexture"],["myTexture"]],
53 | [["myTexture"],["myTexture", "myProp"],["myTexture"]],
54 | [["myTexture"],["myTexture"],["myTexture"]]
55 | ],
56 |
57 | "general":
58 | [
59 | {
60 | "name":"Map name",
61 | "version":"string with map version",
62 | "lighting":"255|255|255"
63 | }
64 | ]
65 | }
66 | ```
67 | Lets analyze it's parts.
68 |
69 | ### Textures
70 | ```JSON
71 | "textures":
72 | [
73 | {
74 | "file": "myTexture.png",
75 | "mnemonic": "myTexture"
76 | },
77 | {
78 | "file": "myTexture2.jpg",
79 | "mnemonic": "myTexture2"
80 | },
81 | {
82 | "And so on":"for all textures you'll use"
83 | }
84 | ],
85 | ```
86 | This is where you'll load your ground layer textures. It has 2 fields:
87 | * name: Specifies the texture filename. Can be any kind of image file Love loads. Examples are .PNG and .JPG files.
88 | * mnemonic: Specifies a more friendly name given to the texture. Used in the map matrix. (See below).
89 |
90 | **All ground textures need to have the same exact dimensions!**
91 |
92 | ### Props
93 | ```JSON
94 | "textures":
95 | [
96 | {
97 | "file": "myProp.png",
98 | "mnemonic": "myProp",
99 | "origin": "X|Y"
100 | },
101 | {
102 | "file": "myProp2.jpg",
103 | "mnemonic": "myProp2"
104 | "origin": "X|Y"
105 | },
106 | {
107 | "And so on":"for all props you'll use"
108 | }
109 | ],
110 | ```
111 | This is where you'll load your map props or objects. It has 3 fields:
112 | * name: Specifies the texture used in the prop. Can be any kind of image file Love loads.
113 | * mnemonic: Specifies a more friendly name given to the prop. Used in the map matrix. (See below).
114 | * origin: Specifies the offset used to draw the prop on the tile where it should be. Values should be X and Y separated by a pipe ("|"). To find out this offset, use any image editor you want! Then you modify your values until you can get it right.
115 |
116 | Prop textures can be any size you want.
117 |
118 | ### Data
119 | ```JSON
120 | "data":
121 | [
122 | [["myTexture"],["myMnemonic"],["myTexture"]],
123 | [["myTexture"],["myTexture", "myProp"],["myTexture"]],
124 | [["myTexture"],["myTexture"],["myTexture"]]
125 | ],
126 | ```
127 | Pretty straightforward. Use the *mnemonics* you defined for your props and textures above and put then into a JSON matrix. I'm not sure, but I think only one prop can be placed per tile. In this example, a map with a 3x3 size would be rendered with texture *myTexture*, and *myProp* prop would be placed in the middle tile[2][2]. Obviously, larger data matrixes will yield bigger maps.
128 |
129 | ### General
130 | ```JSON
131 | "general":
132 | [
133 | {
134 | "name":"Map name",
135 | "version":"string with map version",
136 | "lighting":"R|G|B"
137 | }
138 | ]
139 | ```
140 | Specifies general map information, as well as other extras.
141 | * name: Specifies the map name.
142 | * version: Specifies a map version.
143 | * lighting: A small trick. Values are RGB values separated by a pipe ("|"). Defines the color you want to use to draw your map. If you specify, say, a dark blue, it'll give the map a blue tone, faking a night environment. Be creative! Set this value to "255|255|255" if you don't want to use this feature.
144 |
145 | # Isomap methods
146 | ## isomap.decodeJson(filename)
147 | Decodes a given JSON file.
148 |
149 | *Arguments:*
150 | * filename: The JSON filepath.
151 |
152 | *Example*:
153 | ```Lua
154 | isomap.decodeJson("Jsonfile.json")
155 | ```
156 | ## isomap.generatePlayfield()
157 | Generates the playfield with information provided by the preovously loaded JSON file.
158 |
159 | *No arguments.*
160 |
161 | *Example:*
162 | ```Lua
163 | isomap.generatePlayfield()
164 | ```
165 | ## isomap.drawGround(x, y, zoomLevel)
166 | Draws the map with a *X* and a *Y* offset scaled by *zoomLevel*.
167 |
168 | *Arguments:*
169 | * **x** and **y**: X and Y offset for map drawing.
170 | * zoomLevel: a number specifiying the scale the map should be rendered. Used primarily for zooming in and out.
171 |
172 | *Example:*
173 | ```Lua
174 | isomap.drawGround(300, 200, 1.5)
175 | ```
176 |
177 | ## isomap.drawObjects(x, y, zoomLevel)
178 | Sorts ZBuffer and draws objects on the map with a *X* and a *Y* offset scaled by *zoomLevel*.
179 |
180 | *Arguments:*
181 | * **x** and **y**: X and Y offset for object drawing.
182 | * zoomLevel: a number specifiying the scale the objects should be rendered. Used primarily for zooming in and out.
183 |
184 | *Example:*
185 | ```Lua
186 | isomap.drawObjects(300, 200, 1.5)
187 | ```
188 | ## isomap.toIso(x, y)
189 | Converts *x* and *y* from cartesian (2D) to isometric coordinates.
190 |
191 | *Arguments:*
192 | * **x** and **y**: X and Y values to be converted.
193 |
194 | *Example:*
195 | ```Lua
196 | isomap.toIso(420, 350)
197 | ```
198 | ## isomap.toCartesian(x, y)
199 | Converts *x* and *y* from isometric to cartesian (2D) coordinates.
200 |
201 | *Arguments:*
202 | * **x** and **y**: X and Y values to be converted.
203 |
204 | *Example:*
205 | ```Lua
206 | isomap.toCartesian(5, 8)
207 | ```
208 | # Minimal usage example
209 | ```Lua
210 | isomap = require ("isomap")
211 | function love.load()
212 | --Variables
213 | x = 0
214 | y = 0
215 |
216 | --Set background to deep blue
217 | love.graphics.setBackgroundColor(0, 0, 69)
218 |
219 | --Decode JSON map file
220 | isomap.decodeJson("JSONMap.json")
221 |
222 | --Generate map from JSON file (loads assets and creates tables)
223 | isomap.generatePlayField()
224 | end
225 |
226 | function love.update(dt)
227 | --Get player input so map moves around.
228 | if love.keyboard.isDown("left") then x = x + 900*dt end
229 | if love.keyboard.isDown("right") then x = x - 900*dt end
230 | if love.keyboard.isDown("up") then y = y+900*dt end
231 | if love.keyboard.isDown("down") then y = y-900*dt end
232 | end
233 |
234 | function love.draw()
235 | isomap.drawGround(x, y, 1)
236 | isomap.drawObjects(x, y, 1)
237 | end
238 |
239 | ```
240 |
241 | # Personal recommendations
242 | I recommend using [rxi's autobatch](https://github.com/rxi/autobatch) library to reduce draw calls made by this library to draw your map!
243 |
244 | # Contact
245 | Rants, questions, suggestions and anything else, [drop me an email here](mailto:pedrorocha@gec.inatel.br).
246 |
--------------------------------------------------------------------------------
/conf.lua:
--------------------------------------------------------------------------------
1 | function love.conf(t)
2 | t.identity = nil -- The name of the save directory (string)
3 | t.version = "0.10.1" -- The L�VE version this game was made for (string)
4 | t.console = true -- Attach a console (boolean, Windows only)
5 | t.accelerometerjoystick = true -- Enable the accelerometer on iOS and Android by exposing it as a Joystick (boolean)
6 | t.externalstorage = false -- True to save files (and read from the save directory) in external storage on Android (boolean)
7 | t.gammacorrect = false -- Enable gamma-correct rendering, when supported by the system (boolean)
8 |
9 | t.window.title = "IsoMap" -- The window title (string)
10 | t.window.icon = nil -- Filepath to an image to use as the window's icon (string)
11 | t.window.width = 800 -- The window width (number)
12 | t.window.height = 600 -- The window height (number)
13 | t.window.borderless = false -- Remove all border visuals from the window (boolean)
14 | t.window.resizable = true -- Let the window be user-resizable (boolean)
15 | t.window.minwidth = 1 -- Minimum window width if the window is resizable (number)
16 | t.window.minheight = 1 -- Minimum window height if the window is resizable (number)
17 | t.window.fullscreen = false -- Enable fullscreen (boolean)
18 | t.window.fullscreentype = "desktop" -- Choose between "desktop" fullscreen or "exclusive" fullscreen mode (string)
19 | t.window.vsync = false -- Enable vertical sync (boolean)
20 | t.window.msaa = 0 -- The number of samples to use with multi-sampled antialiasing (number)
21 | t.window.display = 1 -- Index of the monitor to show the window in (number)
22 | t.window.highdpi = false -- Enable high-dpi mode for the window on a Retina display (boolean)
23 | t.window.x = nil -- The x-coordinate of the window's position in the specified display (number)
24 | t.window.y = nil -- The y-coordinate of the window's position in the specified display (number)
25 |
26 | t.modules.audio = true -- Enable the audio module (boolean)
27 | t.modules.event = true -- Enable the event module (boolean)
28 | t.modules.graphics = true -- Enable the graphics module (boolean)
29 | t.modules.image = true -- Enable the image module (boolean)
30 | t.modules.joystick = true -- Enable the joystick module (boolean)
31 | t.modules.keyboard = true -- Enable the keyboard module (boolean)
32 | t.modules.math = true -- Enable the math module (boolean)
33 | t.modules.mouse = true -- Enable the mouse module (boolean)
34 | t.modules.physics = true -- Enable the physics module (boolean)
35 | t.modules.sound = true -- Enable the sound module (boolean)
36 | t.modules.system = true -- Enable the system module (boolean)
37 | t.modules.timer = true -- Enable the timer module (boolean), Disabling it will result 0 delta time in love.update
38 | t.modules.touch = true -- Enable the touch module (boolean)
39 | t.modules.video = true -- Enable the video module (boolean)
40 | t.modules.window = true -- Enable the window module (boolean)
41 | t.modules.thread = true -- Enable the thread module (boolean)
42 | end
43 |
--------------------------------------------------------------------------------
/dkjson.lua:
--------------------------------------------------------------------------------
1 | -- Module options:
2 | local always_try_using_lpeg = true
3 | local register_global_module_table = false
4 | local global_module_name = 'json'
5 |
6 | --[==[
7 |
8 | David Kolf's JSON module for Lua 5.1/5.2
9 |
10 | Version 2.5
11 |
12 |
13 | For the documentation see the corresponding readme.txt or visit
14 | .
15 |
16 | You can contact the author by sending an e-mail to 'david' at the
17 | domain 'dkolf.de'.
18 |
19 |
20 | Copyright (C) 2010-2013 David Heiko Kolf
21 |
22 | Permission is hereby granted, free of charge, to any person obtaining
23 | a copy of this software and associated documentation files (the
24 | "Software"), to deal in the Software without restriction, including
25 | without limitation the rights to use, copy, modify, merge, publish,
26 | distribute, sublicense, and/or sell copies of the Software, and to
27 | permit persons to whom the Software is furnished to do so, subject to
28 | the following conditions:
29 |
30 | The above copyright notice and this permission notice shall be
31 | included in all copies or substantial portions of the Software.
32 |
33 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
34 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
35 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
36 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
37 | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
38 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
39 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
40 | SOFTWARE.
41 |
42 | --]==]
43 |
44 | -- global dependencies:
45 | local pairs, type, tostring, tonumber, getmetatable, setmetatable, rawset =
46 | pairs, type, tostring, tonumber, getmetatable, setmetatable, rawset
47 | local error, require, pcall, select = error, require, pcall, select
48 | local floor, huge = math.floor, math.huge
49 | local strrep, gsub, strsub, strbyte, strchar, strfind, strlen, strformat =
50 | string.rep, string.gsub, string.sub, string.byte, string.char,
51 | string.find, string.len, string.format
52 | local strmatch = string.match
53 | local concat = table.concat
54 |
55 | local json = { version = "dkjson 2.5" }
56 |
57 | if register_global_module_table then
58 | _G[global_module_name] = json
59 | end
60 |
61 | local _ENV = nil -- blocking globals in Lua 5.2
62 |
63 | pcall (function()
64 | -- Enable access to blocked metatables.
65 | -- Don't worry, this module doesn't change anything in them.
66 | local debmeta = require "debug".getmetatable
67 | if debmeta then getmetatable = debmeta end
68 | end)
69 |
70 | json.null = setmetatable ({}, {
71 | __tojson = function () return "null" end
72 | })
73 |
74 | local function isarray (tbl)
75 | local max, n, arraylen = 0, 0, 0
76 | for k,v in pairs (tbl) do
77 | if k == 'n' and type(v) == 'number' then
78 | arraylen = v
79 | if v > max then
80 | max = v
81 | end
82 | else
83 | if type(k) ~= 'number' or k < 1 or floor(k) ~= k then
84 | return false
85 | end
86 | if k > max then
87 | max = k
88 | end
89 | n = n + 1
90 | end
91 | end
92 | if max > 10 and max > arraylen and max > n * 2 then
93 | return false -- don't create an array with too many holes
94 | end
95 | return true, max
96 | end
97 |
98 | local escapecodes = {
99 | ["\""] = "\\\"", ["\\"] = "\\\\", ["\b"] = "\\b", ["\f"] = "\\f",
100 | ["\n"] = "\\n", ["\r"] = "\\r", ["\t"] = "\\t"
101 | }
102 |
103 | local function escapeutf8 (uchar)
104 | local value = escapecodes[uchar]
105 | if value then
106 | return value
107 | end
108 | local a, b, c, d = strbyte (uchar, 1, 4)
109 | a, b, c, d = a or 0, b or 0, c or 0, d or 0
110 | if a <= 0x7f then
111 | value = a
112 | elseif 0xc0 <= a and a <= 0xdf and b >= 0x80 then
113 | value = (a - 0xc0) * 0x40 + b - 0x80
114 | elseif 0xe0 <= a and a <= 0xef and b >= 0x80 and c >= 0x80 then
115 | value = ((a - 0xe0) * 0x40 + b - 0x80) * 0x40 + c - 0x80
116 | elseif 0xf0 <= a and a <= 0xf7 and b >= 0x80 and c >= 0x80 and d >= 0x80 then
117 | value = (((a - 0xf0) * 0x40 + b - 0x80) * 0x40 + c - 0x80) * 0x40 + d - 0x80
118 | else
119 | return ""
120 | end
121 | if value <= 0xffff then
122 | return strformat ("\\u%.4x", value)
123 | elseif value <= 0x10ffff then
124 | -- encode as UTF-16 surrogate pair
125 | value = value - 0x10000
126 | local highsur, lowsur = 0xD800 + floor (value/0x400), 0xDC00 + (value % 0x400)
127 | return strformat ("\\u%.4x\\u%.4x", highsur, lowsur)
128 | else
129 | return ""
130 | end
131 | end
132 |
133 | local function fsub (str, pattern, repl)
134 | -- gsub always builds a new string in a buffer, even when no match
135 | -- exists. First using find should be more efficient when most strings
136 | -- don't contain the pattern.
137 | if strfind (str, pattern) then
138 | return gsub (str, pattern, repl)
139 | else
140 | return str
141 | end
142 | end
143 |
144 | local function quotestring (value)
145 | -- based on the regexp "escapable" in https://github.com/douglascrockford/JSON-js
146 | value = fsub (value, "[%z\1-\31\"\\\127]", escapeutf8)
147 | if strfind (value, "[\194\216\220\225\226\239]") then
148 | value = fsub (value, "\194[\128-\159\173]", escapeutf8)
149 | value = fsub (value, "\216[\128-\132]", escapeutf8)
150 | value = fsub (value, "\220\143", escapeutf8)
151 | value = fsub (value, "\225\158[\180\181]", escapeutf8)
152 | value = fsub (value, "\226\128[\140-\143\168-\175]", escapeutf8)
153 | value = fsub (value, "\226\129[\160-\175]", escapeutf8)
154 | value = fsub (value, "\239\187\191", escapeutf8)
155 | value = fsub (value, "\239\191[\176-\191]", escapeutf8)
156 | end
157 | return "\"" .. value .. "\""
158 | end
159 | json.quotestring = quotestring
160 |
161 | local function replace(str, o, n)
162 | local i, j = strfind (str, o, 1, true)
163 | if i then
164 | return strsub(str, 1, i-1) .. n .. strsub(str, j+1, -1)
165 | else
166 | return str
167 | end
168 | end
169 |
170 | -- locale independent num2str and str2num functions
171 | local decpoint, numfilter
172 |
173 | local function updatedecpoint ()
174 | decpoint = strmatch(tostring(0.5), "([^05+])")
175 | -- build a filter that can be used to remove group separators
176 | numfilter = "[^0-9%-%+eE" .. gsub(decpoint, "[%^%$%(%)%%%.%[%]%*%+%-%?]", "%%%0") .. "]+"
177 | end
178 |
179 | updatedecpoint()
180 |
181 | local function num2str (num)
182 | return replace(fsub(tostring(num), numfilter, ""), decpoint, ".")
183 | end
184 |
185 | local function str2num (str)
186 | local num = tonumber(replace(str, ".", decpoint))
187 | if not num then
188 | updatedecpoint()
189 | num = tonumber(replace(str, ".", decpoint))
190 | end
191 | return num
192 | end
193 |
194 | local function addnewline2 (level, buffer, buflen)
195 | buffer[buflen+1] = "\n"
196 | buffer[buflen+2] = strrep (" ", level)
197 | buflen = buflen + 2
198 | return buflen
199 | end
200 |
201 | function json.addnewline (state)
202 | if state.indent then
203 | state.bufferlen = addnewline2 (state.level or 0,
204 | state.buffer, state.bufferlen or #(state.buffer))
205 | end
206 | end
207 |
208 | local encode2 -- forward declaration
209 |
210 | local function addpair (key, value, prev, indent, level, buffer, buflen, tables, globalorder, state)
211 | local kt = type (key)
212 | if kt ~= 'string' and kt ~= 'number' then
213 | return nil, "type '" .. kt .. "' is not supported as a key by JSON."
214 | end
215 | if prev then
216 | buflen = buflen + 1
217 | buffer[buflen] = ","
218 | end
219 | if indent then
220 | buflen = addnewline2 (level, buffer, buflen)
221 | end
222 | buffer[buflen+1] = quotestring (key)
223 | buffer[buflen+2] = ":"
224 | return encode2 (value, indent, level, buffer, buflen + 2, tables, globalorder, state)
225 | end
226 |
227 | local function appendcustom(res, buffer, state)
228 | local buflen = state.bufferlen
229 | if type (res) == 'string' then
230 | buflen = buflen + 1
231 | buffer[buflen] = res
232 | end
233 | return buflen
234 | end
235 |
236 | local function exception(reason, value, state, buffer, buflen, defaultmessage)
237 | defaultmessage = defaultmessage or reason
238 | local handler = state.exception
239 | if not handler then
240 | return nil, defaultmessage
241 | else
242 | state.bufferlen = buflen
243 | local ret, msg = handler (reason, value, state, defaultmessage)
244 | if not ret then return nil, msg or defaultmessage end
245 | return appendcustom(ret, buffer, state)
246 | end
247 | end
248 |
249 | function json.encodeexception(reason, value, state, defaultmessage)
250 | return quotestring("<" .. defaultmessage .. ">")
251 | end
252 |
253 | encode2 = function (value, indent, level, buffer, buflen, tables, globalorder, state)
254 | local valtype = type (value)
255 | local valmeta = getmetatable (value)
256 | valmeta = type (valmeta) == 'table' and valmeta -- only tables
257 | local valtojson = valmeta and valmeta.__tojson
258 | if valtojson then
259 | if tables[value] then
260 | return exception('reference cycle', value, state, buffer, buflen)
261 | end
262 | tables[value] = true
263 | state.bufferlen = buflen
264 | local ret, msg = valtojson (value, state)
265 | if not ret then return exception('custom encoder failed', value, state, buffer, buflen, msg) end
266 | tables[value] = nil
267 | buflen = appendcustom(ret, buffer, state)
268 | elseif value == nil then
269 | buflen = buflen + 1
270 | buffer[buflen] = "null"
271 | elseif valtype == 'number' then
272 | local s
273 | if value ~= value or value >= huge or -value >= huge then
274 | -- This is the behaviour of the original JSON implementation.
275 | s = "null"
276 | else
277 | s = num2str (value)
278 | end
279 | buflen = buflen + 1
280 | buffer[buflen] = s
281 | elseif valtype == 'boolean' then
282 | buflen = buflen + 1
283 | buffer[buflen] = value and "true" or "false"
284 | elseif valtype == 'string' then
285 | buflen = buflen + 1
286 | buffer[buflen] = quotestring (value)
287 | elseif valtype == 'table' then
288 | if tables[value] then
289 | return exception('reference cycle', value, state, buffer, buflen)
290 | end
291 | tables[value] = true
292 | level = level + 1
293 | local isa, n = isarray (value)
294 | if n == 0 and valmeta and valmeta.__jsontype == 'object' then
295 | isa = false
296 | end
297 | local msg
298 | if isa then -- JSON array
299 | buflen = buflen + 1
300 | buffer[buflen] = "["
301 | for i = 1, n do
302 | buflen, msg = encode2 (value[i], indent, level, buffer, buflen, tables, globalorder, state)
303 | if not buflen then return nil, msg end
304 | if i < n then
305 | buflen = buflen + 1
306 | buffer[buflen] = ","
307 | end
308 | end
309 | buflen = buflen + 1
310 | buffer[buflen] = "]"
311 | else -- JSON object
312 | local prev = false
313 | buflen = buflen + 1
314 | buffer[buflen] = "{"
315 | local order = valmeta and valmeta.__jsonorder or globalorder
316 | if order then
317 | local used = {}
318 | n = #order
319 | for i = 1, n do
320 | local k = order[i]
321 | local v = value[k]
322 | if v then
323 | used[k] = true
324 | buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
325 | prev = true -- add a seperator before the next element
326 | end
327 | end
328 | for k,v in pairs (value) do
329 | if not used[k] then
330 | buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
331 | if not buflen then return nil, msg end
332 | prev = true -- add a seperator before the next element
333 | end
334 | end
335 | else -- unordered
336 | for k,v in pairs (value) do
337 | buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
338 | if not buflen then return nil, msg end
339 | prev = true -- add a seperator before the next element
340 | end
341 | end
342 | if indent then
343 | buflen = addnewline2 (level - 1, buffer, buflen)
344 | end
345 | buflen = buflen + 1
346 | buffer[buflen] = "}"
347 | end
348 | tables[value] = nil
349 | else
350 | return exception ('unsupported type', value, state, buffer, buflen,
351 | "type '" .. valtype .. "' is not supported by JSON.")
352 | end
353 | return buflen
354 | end
355 |
356 | function json.encode (value, state)
357 | state = state or {}
358 | local oldbuffer = state.buffer
359 | local buffer = oldbuffer or {}
360 | state.buffer = buffer
361 | updatedecpoint()
362 | local ret, msg = encode2 (value, state.indent, state.level or 0,
363 | buffer, state.bufferlen or 0, state.tables or {}, state.keyorder, state)
364 | if not ret then
365 | error (msg, 2)
366 | elseif oldbuffer == buffer then
367 | state.bufferlen = ret
368 | return true
369 | else
370 | state.bufferlen = nil
371 | state.buffer = nil
372 | return concat (buffer)
373 | end
374 | end
375 |
376 | local function loc (str, where)
377 | local line, pos, linepos = 1, 1, 0
378 | while true do
379 | pos = strfind (str, "\n", pos, true)
380 | if pos and pos < where then
381 | line = line + 1
382 | linepos = pos
383 | pos = pos + 1
384 | else
385 | break
386 | end
387 | end
388 | return "line " .. line .. ", column " .. (where - linepos)
389 | end
390 |
391 | local function unterminated (str, what, where)
392 | return nil, strlen (str) + 1, "unterminated " .. what .. " at " .. loc (str, where)
393 | end
394 |
395 | local function scanwhite (str, pos)
396 | while true do
397 | pos = strfind (str, "%S", pos)
398 | if not pos then return nil end
399 | local sub2 = strsub (str, pos, pos + 1)
400 | if sub2 == "\239\187" and strsub (str, pos + 2, pos + 2) == "\191" then
401 | -- UTF-8 Byte Order Mark
402 | pos = pos + 3
403 | elseif sub2 == "//" then
404 | pos = strfind (str, "[\n\r]", pos + 2)
405 | if not pos then return nil end
406 | elseif sub2 == "/*" then
407 | pos = strfind (str, "*/", pos + 2)
408 | if not pos then return nil end
409 | pos = pos + 2
410 | else
411 | return pos
412 | end
413 | end
414 | end
415 |
416 | local escapechars = {
417 | ["\""] = "\"", ["\\"] = "\\", ["/"] = "/", ["b"] = "\b", ["f"] = "\f",
418 | ["n"] = "\n", ["r"] = "\r", ["t"] = "\t"
419 | }
420 |
421 | local function unichar (value)
422 | if value < 0 then
423 | return nil
424 | elseif value <= 0x007f then
425 | return strchar (value)
426 | elseif value <= 0x07ff then
427 | return strchar (0xc0 + floor(value/0x40),
428 | 0x80 + (floor(value) % 0x40))
429 | elseif value <= 0xffff then
430 | return strchar (0xe0 + floor(value/0x1000),
431 | 0x80 + (floor(value/0x40) % 0x40),
432 | 0x80 + (floor(value) % 0x40))
433 | elseif value <= 0x10ffff then
434 | return strchar (0xf0 + floor(value/0x40000),
435 | 0x80 + (floor(value/0x1000) % 0x40),
436 | 0x80 + (floor(value/0x40) % 0x40),
437 | 0x80 + (floor(value) % 0x40))
438 | else
439 | return nil
440 | end
441 | end
442 |
443 | local function scanstring (str, pos)
444 | local lastpos = pos + 1
445 | local buffer, n = {}, 0
446 | while true do
447 | local nextpos = strfind (str, "[\"\\]", lastpos)
448 | if not nextpos then
449 | return unterminated (str, "string", pos)
450 | end
451 | if nextpos > lastpos then
452 | n = n + 1
453 | buffer[n] = strsub (str, lastpos, nextpos - 1)
454 | end
455 | if strsub (str, nextpos, nextpos) == "\"" then
456 | lastpos = nextpos + 1
457 | break
458 | else
459 | local escchar = strsub (str, nextpos + 1, nextpos + 1)
460 | local value
461 | if escchar == "u" then
462 | value = tonumber (strsub (str, nextpos + 2, nextpos + 5), 16)
463 | if value then
464 | local value2
465 | if 0xD800 <= value and value <= 0xDBff then
466 | -- we have the high surrogate of UTF-16. Check if there is a
467 | -- low surrogate escaped nearby to combine them.
468 | if strsub (str, nextpos + 6, nextpos + 7) == "\\u" then
469 | value2 = tonumber (strsub (str, nextpos + 8, nextpos + 11), 16)
470 | if value2 and 0xDC00 <= value2 and value2 <= 0xDFFF then
471 | value = (value - 0xD800) * 0x400 + (value2 - 0xDC00) + 0x10000
472 | else
473 | value2 = nil -- in case it was out of range for a low surrogate
474 | end
475 | end
476 | end
477 | value = value and unichar (value)
478 | if value then
479 | if value2 then
480 | lastpos = nextpos + 12
481 | else
482 | lastpos = nextpos + 6
483 | end
484 | end
485 | end
486 | end
487 | if not value then
488 | value = escapechars[escchar] or escchar
489 | lastpos = nextpos + 2
490 | end
491 | n = n + 1
492 | buffer[n] = value
493 | end
494 | end
495 | if n == 1 then
496 | return buffer[1], lastpos
497 | elseif n > 1 then
498 | return concat (buffer), lastpos
499 | else
500 | return "", lastpos
501 | end
502 | end
503 |
504 | local scanvalue -- forward declaration
505 |
506 | local function scantable (what, closechar, str, startpos, nullval, objectmeta, arraymeta)
507 | local len = strlen (str)
508 | local tbl, n = {}, 0
509 | local pos = startpos + 1
510 | if what == 'object' then
511 | setmetatable (tbl, objectmeta)
512 | else
513 | setmetatable (tbl, arraymeta)
514 | end
515 | while true do
516 | pos = scanwhite (str, pos)
517 | if not pos then return unterminated (str, what, startpos) end
518 | local char = strsub (str, pos, pos)
519 | if char == closechar then
520 | return tbl, pos + 1
521 | end
522 | local val1, err
523 | val1, pos, err = scanvalue (str, pos, nullval, objectmeta, arraymeta)
524 | if err then return nil, pos, err end
525 | pos = scanwhite (str, pos)
526 | if not pos then return unterminated (str, what, startpos) end
527 | char = strsub (str, pos, pos)
528 | if char == ":" then
529 | if val1 == nil then
530 | return nil, pos, "cannot use nil as table index (at " .. loc (str, pos) .. ")"
531 | end
532 | pos = scanwhite (str, pos + 1)
533 | if not pos then return unterminated (str, what, startpos) end
534 | local val2
535 | val2, pos, err = scanvalue (str, pos, nullval, objectmeta, arraymeta)
536 | if err then return nil, pos, err end
537 | tbl[val1] = val2
538 | pos = scanwhite (str, pos)
539 | if not pos then return unterminated (str, what, startpos) end
540 | char = strsub (str, pos, pos)
541 | else
542 | n = n + 1
543 | tbl[n] = val1
544 | end
545 | if char == "," then
546 | pos = pos + 1
547 | end
548 | end
549 | end
550 |
551 | scanvalue = function (str, pos, nullval, objectmeta, arraymeta)
552 | pos = pos or 1
553 | pos = scanwhite (str, pos)
554 | if not pos then
555 | return nil, strlen (str) + 1, "no valid JSON value (reached the end)"
556 | end
557 | local char = strsub (str, pos, pos)
558 | if char == "{" then
559 | return scantable ('object', "}", str, pos, nullval, objectmeta, arraymeta)
560 | elseif char == "[" then
561 | return scantable ('array', "]", str, pos, nullval, objectmeta, arraymeta)
562 | elseif char == "\"" then
563 | return scanstring (str, pos)
564 | else
565 | local pstart, pend = strfind (str, "^%-?[%d%.]+[eE]?[%+%-]?%d*", pos)
566 | if pstart then
567 | local number = str2num (strsub (str, pstart, pend))
568 | if number then
569 | return number, pend + 1
570 | end
571 | end
572 | pstart, pend = strfind (str, "^%a%w*", pos)
573 | if pstart then
574 | local name = strsub (str, pstart, pend)
575 | if name == "true" then
576 | return true, pend + 1
577 | elseif name == "false" then
578 | return false, pend + 1
579 | elseif name == "null" then
580 | return nullval, pend + 1
581 | end
582 | end
583 | return nil, pos, "no valid JSON value at " .. loc (str, pos)
584 | end
585 | end
586 |
587 | local function optionalmetatables(...)
588 | if select("#", ...) > 0 then
589 | return ...
590 | else
591 | return {__jsontype = 'object'}, {__jsontype = 'array'}
592 | end
593 | end
594 |
595 | function json.decode (str, pos, nullval, ...)
596 | local objectmeta, arraymeta = optionalmetatables(...)
597 | return scanvalue (str, pos, nullval, objectmeta, arraymeta)
598 | end
599 |
600 | function json.use_lpeg ()
601 | local g = require ("lpeg")
602 |
603 | if g.version() == "0.11" then
604 | error "due to a bug in LPeg 0.11, it cannot be used for JSON matching"
605 | end
606 |
607 | local pegmatch = g.match
608 | local P, S, R = g.P, g.S, g.R
609 |
610 | local function ErrorCall (str, pos, msg, state)
611 | if not state.msg then
612 | state.msg = msg .. " at " .. loc (str, pos)
613 | state.pos = pos
614 | end
615 | return false
616 | end
617 |
618 | local function Err (msg)
619 | return g.Cmt (g.Cc (msg) * g.Carg (2), ErrorCall)
620 | end
621 |
622 | local SingleLineComment = P"//" * (1 - S"\n\r")^0
623 | local MultiLineComment = P"/*" * (1 - P"*/")^0 * P"*/"
624 | local Space = (S" \n\r\t" + P"\239\187\191" + SingleLineComment + MultiLineComment)^0
625 |
626 | local PlainChar = 1 - S"\"\\\n\r"
627 | local EscapeSequence = (P"\\" * g.C (S"\"\\/bfnrt" + Err "unsupported escape sequence")) / escapechars
628 | local HexDigit = R("09", "af", "AF")
629 | local function UTF16Surrogate (match, pos, high, low)
630 | high, low = tonumber (high, 16), tonumber (low, 16)
631 | if 0xD800 <= high and high <= 0xDBff and 0xDC00 <= low and low <= 0xDFFF then
632 | return true, unichar ((high - 0xD800) * 0x400 + (low - 0xDC00) + 0x10000)
633 | else
634 | return false
635 | end
636 | end
637 | local function UTF16BMP (hex)
638 | return unichar (tonumber (hex, 16))
639 | end
640 | local U16Sequence = (P"\\u" * g.C (HexDigit * HexDigit * HexDigit * HexDigit))
641 | local UnicodeEscape = g.Cmt (U16Sequence * U16Sequence, UTF16Surrogate) + U16Sequence/UTF16BMP
642 | local Char = UnicodeEscape + EscapeSequence + PlainChar
643 | local String = P"\"" * g.Cs (Char ^ 0) * (P"\"" + Err "unterminated string")
644 | local Integer = P"-"^(-1) * (P"0" + (R"19" * R"09"^0))
645 | local Fractal = P"." * R"09"^0
646 | local Exponent = (S"eE") * (S"+-")^(-1) * R"09"^1
647 | local Number = (Integer * Fractal^(-1) * Exponent^(-1))/str2num
648 | local Constant = P"true" * g.Cc (true) + P"false" * g.Cc (false) + P"null" * g.Carg (1)
649 | local SimpleValue = Number + String + Constant
650 | local ArrayContent, ObjectContent
651 |
652 | -- The functions parsearray and parseobject parse only a single value/pair
653 | -- at a time and store them directly to avoid hitting the LPeg limits.
654 | local function parsearray (str, pos, nullval, state)
655 | local obj, cont
656 | local npos
657 | local t, nt = {}, 0
658 | repeat
659 | obj, cont, npos = pegmatch (ArrayContent, str, pos, nullval, state)
660 | if not npos then break end
661 | pos = npos
662 | nt = nt + 1
663 | t[nt] = obj
664 | until cont == 'last'
665 | return pos, setmetatable (t, state.arraymeta)
666 | end
667 |
668 | local function parseobject (str, pos, nullval, state)
669 | local obj, key, cont
670 | local npos
671 | local t = {}
672 | repeat
673 | key, obj, cont, npos = pegmatch (ObjectContent, str, pos, nullval, state)
674 | if not npos then break end
675 | pos = npos
676 | t[key] = obj
677 | until cont == 'last'
678 | return pos, setmetatable (t, state.objectmeta)
679 | end
680 |
681 | local Array = P"[" * g.Cmt (g.Carg(1) * g.Carg(2), parsearray) * Space * (P"]" + Err "']' expected")
682 | local Object = P"{" * g.Cmt (g.Carg(1) * g.Carg(2), parseobject) * Space * (P"}" + Err "'}' expected")
683 | local Value = Space * (Array + Object + SimpleValue)
684 | local ExpectedValue = Value + Space * Err "value expected"
685 | ArrayContent = Value * Space * (P"," * g.Cc'cont' + g.Cc'last') * g.Cp()
686 | local Pair = g.Cg (Space * String * Space * (P":" + Err "colon expected") * ExpectedValue)
687 | ObjectContent = Pair * Space * (P"," * g.Cc'cont' + g.Cc'last') * g.Cp()
688 | local DecodeValue = ExpectedValue * g.Cp ()
689 |
690 | function json.decode (str, pos, nullval, ...)
691 | local state = {}
692 | state.objectmeta, state.arraymeta = optionalmetatables(...)
693 | local obj, retpos = pegmatch (DecodeValue, str, pos, nullval, state)
694 | if state.msg then
695 | return nil, state.pos, state.msg
696 | else
697 | return obj, retpos
698 | end
699 | end
700 |
701 | -- use this function only once:
702 | json.use_lpeg = function () return json end
703 |
704 | json.using_lpeg = true
705 |
706 | return json -- so you can get the module using json = require "dkjson".use_lpeg()
707 | end
708 |
709 | if always_try_using_lpeg then
710 | pcall (json.use_lpeg)
711 | end
712 |
713 | return json
714 |
715 |
--------------------------------------------------------------------------------
/isomap.lua:
--------------------------------------------------------------------------------
1 | --[[MIT License
2 |
3 | Copyright (c) 2016 Pedro Polez
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.]]--
22 |
23 | local json = require("dkjson")
24 | --TODO: Load dkjson relative to mapDecoder's path.
25 |
26 |
27 | map = {}
28 | mapDec = {}
29 | local mapTextures = {}
30 | mapPositions = {}
31 | mapProps = {}
32 | local mapLighting = {}
33 | mapPropsfield = {}
34 | local tileWidth = 0
35 | local tileHeight = 0
36 |
37 | local mapPlayfieldWidthInTiles = 0
38 | local mapPlayfieldHeightInTiles = 0
39 |
40 | local objectListSize = 0
41 |
42 | local zoomLevel = 1
43 |
44 | function map.decodeJson(filename)
45 | assert(filename, "Filename is nil!")
46 | if not love.filesystem.isFile(filename) then error("Given filename is not a file! Is it a directory? Does it exist?") end
47 |
48 | --Reads file
49 | mapJson = love.filesystem.read(filename)
50 |
51 | --Attempts to decode file
52 | mapDec = json.decode(mapJson)
53 |
54 | end
55 |
56 |
57 | function map.generatePlayField()
58 | --TODO: Maps will be packed as renamed ZIP file extensios and will be able to be installed in users machines. So, textures and props have to be loaded from this directory.
59 | --Currently, the mapDecoder will look for textures in folder named textures in the root of the project, and props in a props folder.
60 |
61 | print("Current map information:")
62 | print("General information: =-=-=-=-=-=-=")
63 | if mapDec.general ~= nil then
64 | print("Map name: "..mapDec.general[1].name)
65 | print("Map version: "..mapDec.general[1].version)
66 | print("Map lighting: "..mapDec.general[1].lighting)
67 | if mapDec.general[1].lighting ~= nil then
68 | mapLighting = string.split_(mapDec.general[1].lighting, "|")
69 | end
70 | print("----")
71 | end
72 |
73 | print("Ground textures: =-=-=-=-=-=-=-=")
74 | for i, texture in ipairs(mapDec.textures) do
75 | --Print table contents for now
76 | print(texture.file)
77 | print(texture.mnemonic)
78 | print("---")
79 |
80 | table.insert(mapTextures, {file = texture.file, mnemonic = texture.mnemonic, image = love.graphics.newImage("textures/"..texture.file)})
81 |
82 | end
83 |
84 | --Get ground texture dimensions
85 | tileWidth = mapTextures[1].image:getWidth()/2
86 | tileHeight = mapTextures[1].image:getHeight()/2
87 |
88 | print("Playfield props: =-=-=-=-=-=-=-=")
89 | if mapDec.props ~= nil then
90 | for i, props in ipairs(mapDec.props) do
91 | print(props.file)
92 | print(props.mnemonic)
93 | print(props.origin)
94 | print("----")
95 | table.insert(mapProps, {file = props.file, mnemonic = props.mnemonic, image = love.graphics.newImage("props/"..props.file), origins = string.split_(props.origin, "|")})
96 | end
97 | else
98 | print("No props found on current map!")
99 | end
100 |
101 |
102 | --Add each ground tile to a table according to their texture
103 | --TODO: the following should be done on a separate thread. I have not tested the performance of the following lines on a colossal map.
104 | timerStart = love.timer.getTime()
105 | for i, groundTexture in ipairs(mapTextures) do
106 | for colunas in ipairs(mapDec.data) do
107 | for linhas in ipairs(mapDec.data[colunas]) do
108 | for i, properties in ipairs(mapDec.data[colunas][linhas]) do
109 |
110 | --Add ground texture if mnemonic is found
111 | if properties == groundTexture.mnemonic then
112 | local xPos = linhas
113 | local yPos = colunas
114 | if mapPositions[colunas] == nil then
115 | mapPositions[colunas] = {}
116 | end
117 | if mapPositions[colunas][linhas] == nil then
118 | mapPositions[colunas][linhas] = {}
119 | end
120 | table.insert(mapPositions[colunas][linhas], {texture = groundTexture.image, x=xPos, y=yPos})
121 | end
122 |
123 | end
124 | end
125 | end
126 | end
127 |
128 | --TODO: Merge these loops, since both save stuff to the same table?
129 | --Add object to map accordingly
130 | for i, props in ipairs(mapProps) do --For each object
131 |
132 | --Loop through map terrain information
133 | for colunas in ipairs(mapDec.data) do
134 | for linhas in ipairs(mapDec.data[colunas]) do
135 |
136 | --Iterate over the objects in a given 2D position
137 | for i, objects in ipairs(mapDec.data[colunas][linhas]) do
138 | if objects == props.mnemonic then
139 | --table.insert(mapPositions[colunas][linhas], {texture=props.image, x=linhas, y=colunas, offX=props.origins[1], offY=props.origins[2]})
140 |
141 | --VERY IMPORTANT NOTE ABOUT THE FOLLOWING LINES
142 | --these control the ZBuffer in some *dark manner*. IT WORKS. I **really** have to figure out why.
143 | pX, pY = map.toIso(linhas, colunas)
144 |
145 | colX = linhas * (tileWidth*zoomLevel)
146 | colY = colunas * (tileWidth*zoomLevel)
147 | colX, colY = map.toIso(colX, colY)
148 | table.insert(mapPropsfield,{texture=props.image, x=linhas, y=colunas, offX=props.origins[1], offY=props.origins[2], mapY = pY, mapX = pX, colX = colX, colY = colY, width = props.image:getWidth(), height = props.image:getHeight(), alpha = false})
149 | end
150 | end
151 |
152 | end
153 | end
154 |
155 | end
156 | --Calculate map dimensions
157 | mapPlayfieldWidthInTiles = #mapPositions
158 | mapPlayfieldHeightInTiles = #mapPositions[1]
159 |
160 | --Store map original object list size without any extra dynamic objects
161 | objectListSize = #mapPropsfield
162 |
163 | timerEnd = love.timer.getTime()
164 | print("Decode loop took "..((timerEnd-timerStart)*100).."ms")
165 |
166 | end
167 |
168 | function map.drawGround(xOff, yOff, size)
169 | assert(xOff)
170 | assert(yOff)
171 | assert(size)
172 | zoomLevel = size
173 | --Apply lighting
174 | love.graphics.setColor(tonumber(mapLighting[1]), tonumber(mapLighting[2]), tonumber(mapLighting[3]), 255)
175 |
176 | --Draw the flat ground layer for the map, without elevation or props.
177 | for i in ipairs(mapPositions) do
178 | for j=1,#mapPositions[i], 1 do
179 | local xPos = mapPositions[i][j][1].x * (tileWidth*zoomLevel)
180 | local yPos = mapPositions[i][j][1].y * (tileWidth*zoomLevel)
181 | local xPos, yPos = map.toIso(xPos, yPos)
182 | love.graphics.draw(mapPositions[i][j][1].texture,xPos+xOff, yPos+yOff, 0, size, size, mapPositions[i][j][1].texture:getWidth()/2, mapPositions[i][j][1].texture:getHeight()/2 )
183 | end
184 | end
185 |
186 | end
187 |
188 | function map.drawObjects(xOff, yOff, size)
189 |
190 | --Figure out dynamic object occlusion
191 | if #mapPropsfield > objectListSize then
192 | for i=objectListSize+1, #mapPropsfield do
193 | for j=1, objectListSize do
194 | if CheckCollision(mapPropsfield[j].colX, mapPropsfield[j].colY, mapPropsfield[j].width, mapPropsfield[j].height, mapPropsfield[i].colX, mapPropsfield[i].colY, mapPropsfield[i].width, mapPropsfield[i].height) and mapPropsfield[i].y < mapPropsfield[j].y and mapPropsfield[i].x < mapPropsfield[j].x then
195 | mapPropsfield[j].alpha = true
196 | end
197 | end
198 | end
199 | end
200 |
201 | --Sort ZBuffer and draw objects.
202 | for k,v in spairs(mapPropsfield, function(t,a,b) return t[b].mapY > t[a].mapY end) do
203 | local xPos = v.x * (tileWidth*zoomLevel)
204 | local yPos = v.y * (tileWidth*zoomLevel)
205 | local xPos, yPos = map.toIso(xPos, yPos)
206 |
207 | if v.alpha then
208 | love.graphics.setColor(255, 255, 255, 90)
209 | else
210 | love.graphics.setColor(255, 255, 255, 255)
211 | end
212 | love.graphics.draw(v.texture, xPos+xOff, yPos+yOff, 0, size, size, v.offX, v.offY)
213 |
214 | --Update values in order to minimize for loops
215 | v.alpha = false
216 | v.colX = xPos-v.offX
217 | v.colY = yPos-v.offY
218 | v.mapX, v.mapY = map.toIso(v.x, v.y)
219 | end
220 | end
221 |
222 |
223 | function map.getTileCoordinates2D(i, j)
224 | local xP = mapPositions[i][j][1].x * (tileWidth*zoomLevel)
225 | local yP = mapPositions[i][j][1].y * (tileWidth*zoomLevel)
226 | xP, yP = map.toIso(xP, yP)
227 | return xP, yP
228 | end
229 |
230 | function map.getPlayfieldWidth()
231 | return mapPlayfieldWidthInTiles
232 | end
233 |
234 | function map.getPlayfieldHeight()
235 | return mapPlayfieldHeightInTiles
236 | end
237 |
238 | function map.getGroundTileWidth()
239 | return tileWidth
240 | end
241 |
242 | --Links used whilst searching for information on isometric maps:
243 | --http://stackoverflow.com/questions/892811/drawing-isometric-game-worlds
244 | --https://gamedevelopment.tutsplus.com/tutorials/creating-isometric-worlds-a-primer-for-game-developers--gamedev-6511
245 | --Give it a good read if you don't understand whats happening over here.
246 |
247 | function map.toIso(x, y)
248 | assert(x, "Position X is nil!")
249 | assert(y, "Position Y is nil!")
250 |
251 | newX = x-y
252 | newY = (x + y)/2
253 | return newX, newY
254 | end
255 |
256 | function map.toCartesian(x, y)
257 | assert(x, "Position X is nil!")
258 | assert(y, "Position Y is nil!")
259 | x = (2 * y + x)/2
260 | y = (2 * y - x)/2
261 | return x, y
262 | end
263 |
264 | function map.insertNewObject(textureI, isoX, isoY, offXR, offYR)
265 | --User checks
266 | if offXR == nil then offXR = 0 end
267 | if offYR == nil then offYR = 0 end
268 | assert(textureI, "Invalid texture file for object!")
269 | assert(isoX, "No X position for object! (Isometric coordinates)")
270 | assert(isoY, "No Y position for object! (Isometric coordinates)")
271 | assert(mapPlayfieldWidthInTiles>=isoX, "Insertion coordinates out of map bounds! (X)")
272 | assert(mapPlayfieldWidthInTiles>=isoY, "Insertion coordinates out of map bounds! (Y)")
273 | local rx, ry = map.toIso(isoX, isoY)
274 |
275 | local colX = isoX * (tileWidth*zoomLevel)
276 | local colY = isoY * (tileWidth*zoomLevel)
277 | colX, colY = map.toIso(colX, colY)
278 | --Insert object on map
279 | table.insert(mapPropsfield, {texture=textureI, x=isoY, y=isoX+0.001, offX=offXR, offY = offYR, mapY = ry, mapX = rx, colX = colX, colY = colY, width = textureI:getWidth(), height = textureI:getHeight(), alpha = false})
280 | end
281 |
282 | function map.removeObject(x, y)
283 | if #mapPositions[x][y] > 1 then
284 | table.remove(mapPositions[x][y], #mapPositions[x][y])
285 | end
286 | end
287 |
288 |
289 | --This next function had the underscore added to avoid collisions with
290 | --any other possible split function the user may want to use.
291 | function string:split_(sSeparator, nMax, bRegexp)
292 | assert(sSeparator ~= '')
293 | assert(nMax == nil or nMax >= 1)
294 |
295 | local aRecord = {}
296 |
297 | if self:len() > 0 then
298 | local bPlain = not bRegexp
299 | nMax = nMax or -1
300 |
301 | local nField, nStart = 1, 1
302 | local nFirst,nLast = self:find(sSeparator, nStart, bPlain)
303 | while nFirst and nMax ~= 0 do
304 | aRecord[nField] = self:sub(nStart, nFirst-1)
305 | nField = nField+1
306 | nStart = nLast+1
307 | nFirst,nLast = self:find(sSeparator, nStart, bPlain)
308 | nMax = nMax-1
309 | end
310 | aRecord[nField] = self:sub(nStart)
311 | end
312 |
313 | return aRecord
314 | --Credit goes to JoanOrdinas @ lua-users.org
315 | end
316 |
317 | function spairs(t, order)
318 | -- collect the keys
319 | local keys = {}
320 | for k in pairs(t) do keys[#keys+1] = k end
321 |
322 | -- if order function given, sort by it by passing the table and keys a, b,
323 | -- otherwise just sort the keys
324 | if order then
325 | table.sort(keys, function(a,b) return order(t, a, b) end)
326 | else
327 | table.sort(keys)
328 | end
329 |
330 | -- return the iterator function
331 | local i = 0
332 | return function()
333 | i = i + 1
334 | if keys[i] then
335 | return keys[i], t[keys[i]]
336 | end
337 | end
338 | --https://stackoverflow.com/questions/15706270/sort-a-table-in-lua
339 | --Function "spairs" by Michal Kottman.
340 | end
341 |
342 | -- Collision detection function;
343 | -- Returns true if two boxes overlap, false if they don't;
344 | -- x1,y1 are the top-left coords of the first box, while w1,h1 are its width and height;
345 | -- x2,y2,w2 & h2 are the same, but for the second box.
346 | function CheckCollision(x1,y1,w1,h1, x2,y2,w2,h2)
347 | return x1 < x2+w2 and
348 | x2 < x1+w1 and
349 | y1 < y2+h2 and
350 | y2 < y1+h1
351 | end
352 |
353 | return map
354 |
--------------------------------------------------------------------------------
/lovebird.lua:
--------------------------------------------------------------------------------
1 | --
2 | -- lovebird
3 | --
4 | -- Copyright (c) 2017 rxi
5 | --
6 | -- This library is free software; you can redistribute it and/or modify it
7 | -- under the terms of the MIT license. See LICENSE for details.
8 | --
9 |
10 | local socket = require "socket"
11 |
12 | local lovebird = { _version = "0.4.2" }
13 |
14 | lovebird.loadstring = loadstring or load
15 | lovebird.inited = false
16 | lovebird.host = "*"
17 | lovebird.buffer = ""
18 | lovebird.lines = {}
19 | lovebird.connections = {}
20 | lovebird.pages = {}
21 |
22 | lovebird.wrapprint = true
23 | lovebird.timestamp = true
24 | lovebird.allowhtml = false
25 | lovebird.echoinput = true
26 | lovebird.port = 8000
27 | lovebird.whitelist = { "127.0.0.1" }
28 | lovebird.maxlines = 200
29 | lovebird.updateinterval = .5
30 |
31 |
32 | lovebird.pages["index"] = [[
33 |
47 |
48 |
49 |
50 |
51 |
52 | lovebird
53 |
187 |
188 |
189 |
196 |
197 |
198 |
199 |
200 |
206 |
207 |
208 |
212 |
213 |
375 |
376 |
377 | ]]
378 |
379 |
380 | lovebird.pages["buffer"] = [[ ]]
381 |
382 |
383 | lovebird.pages["env.json"] = [[
384 |
399 | {
400 | "valid": true,
401 | "path": "",
402 | "vars": [
403 |
414 | {
415 | "key": "",
416 | "value": ,
421 | "type": "",
422 | },
423 |
424 | ]
425 | }
426 | ]]
427 |
428 |
429 |
430 | function lovebird.init()
431 | -- Init server
432 | lovebird.server = assert(socket.bind(lovebird.host, lovebird.port))
433 | lovebird.addr, lovebird.port = lovebird.server:getsockname()
434 | lovebird.server:settimeout(0)
435 | -- Wrap print
436 | lovebird.origprint = print
437 | if lovebird.wrapprint then
438 | local oldprint = print
439 | print = function(...)
440 | oldprint(...)
441 | lovebird.print(...)
442 | end
443 | end
444 | -- Compile page templates
445 | for k, page in pairs(lovebird.pages) do
446 | lovebird.pages[k] = lovebird.template(page, "lovebird, req",
447 | "pages." .. k)
448 | end
449 | lovebird.inited = true
450 | end
451 |
452 |
453 | function lovebird.template(str, params, chunkname)
454 | params = params and ("," .. params) or ""
455 | local f = function(x) return string.format(" echo(%q)", x) end
456 | str = ("?>"..str.."(.-)<%?lua", f)
457 | str = "local echo " .. params .. " = ..." .. str
458 | local fn = assert(lovebird.loadstring(str, chunkname))
459 | return function(...)
460 | local output = {}
461 | local echo = function(str) table.insert(output, str) end
462 | fn(echo, ...)
463 | return table.concat(lovebird.map(output, tostring))
464 | end
465 | end
466 |
467 |
468 | function lovebird.map(t, fn)
469 | local res = {}
470 | for k, v in pairs(t) do res[k] = fn(v) end
471 | return res
472 | end
473 |
474 |
475 | function lovebird.trace(...)
476 | local str = "[lovebird] " .. table.concat(lovebird.map({...}, tostring), " ")
477 | print(str)
478 | if not lovebird.wrapprint then lovebird.print(str) end
479 | end
480 |
481 |
482 | function lovebird.unescape(str)
483 | local f = function(x) return string.char(tonumber("0x"..x)) end
484 | return (str:gsub("%+", " "):gsub("%%(..)", f))
485 | end
486 |
487 |
488 | function lovebird.parseurl(url)
489 | local res = {}
490 | res.path, res.search = url:match("/([^%?]*)%??(.*)")
491 | res.query = {}
492 | for k, v in res.search:gmatch("([^&^?]-)=([^&^#]*)") do
493 | res.query[k] = lovebird.unescape(v)
494 | end
495 | return res
496 | end
497 |
498 |
499 | function lovebird.htmlescape(str)
500 | return str:gsub("<", "<")
501 | end
502 |
503 |
504 | function lovebird.truncate(str, len)
505 | if #str <= len then
506 | return str
507 | end
508 | return str:sub(1, len - 3) .. "..."
509 | end
510 |
511 |
512 | function lovebird.compare(a, b)
513 | local na, nb = tonumber(a), tonumber(b)
514 | if na then
515 | if nb then return na < nb end
516 | return false
517 | elseif nb then
518 | return true
519 | end
520 | return tostring(a) < tostring(b)
521 | end
522 |
523 |
524 | function lovebird.checkwhitelist(addr)
525 | if lovebird.whitelist == nil then return true end
526 | for _, a in pairs(lovebird.whitelist) do
527 | local ptn = "^" .. a:gsub("%.", "%%."):gsub("%*", "%%d*") .. "$"
528 | if addr:match(ptn) then return true end
529 | end
530 | return false
531 | end
532 |
533 |
534 | function lovebird.clear()
535 | lovebird.lines = {}
536 | lovebird.buffer = ""
537 | end
538 |
539 |
540 | function lovebird.pushline(line)
541 | line.time = os.time()
542 | line.count = 1
543 | table.insert(lovebird.lines, line)
544 | if #lovebird.lines > lovebird.maxlines then
545 | table.remove(lovebird.lines, 1)
546 | end
547 | lovebird.recalcbuffer()
548 | end
549 |
550 |
551 | function lovebird.recalcbuffer()
552 | local function doline(line)
553 | local str = line.str
554 | if not lovebird.allowhtml then
555 | str = lovebird.htmlescape(line.str):gsub("\n", "
")
556 | end
557 | if line.type == "input" then
558 | str = '' .. str .. ''
559 | else
560 | if line.type == "error" then
561 | str = '! ' .. str
562 | str = '' .. str .. ''
563 | end
564 | if line.count > 1 then
565 | str = '' .. line.count .. ' ' .. str
566 | end
567 | if lovebird.timestamp then
568 | str = os.date('%H:%M:%S ', line.time) ..
569 | str
570 | end
571 | end
572 | return str
573 | end
574 | lovebird.buffer = table.concat(lovebird.map(lovebird.lines, doline), "
")
575 | end
576 |
577 |
578 | function lovebird.print(...)
579 | local t = {}
580 | for i = 1, select("#", ...) do
581 | table.insert(t, tostring(select(i, ...)))
582 | end
583 | local str = table.concat(t, " ")
584 | local last = lovebird.lines[#lovebird.lines]
585 | if last and str == last.str then
586 | -- Update last line if this line is a duplicate of it
587 | last.time = os.time()
588 | last.count = last.count + 1
589 | lovebird.recalcbuffer()
590 | else
591 | -- Create new line
592 | lovebird.pushline({ type = "output", str = str })
593 | end
594 | end
595 |
596 |
597 | function lovebird.onerror(err)
598 | lovebird.pushline({ type = "error", str = err })
599 | if lovebird.wrapprint then
600 | lovebird.origprint("[lovebird] ERROR: " .. err)
601 | end
602 | end
603 |
604 |
605 | function lovebird.onrequest(req, client)
606 | local page = req.parsedurl.path
607 | page = page ~= "" and page or "index"
608 | -- Handle "page not found"
609 | if not lovebird.pages[page] then
610 | return "HTTP/1.1 404\r\nContent-Length: 8\r\n\r\nBad page"
611 | end
612 | -- Handle page
613 | local str
614 | xpcall(function()
615 | local data = lovebird.pages[page](lovebird, req)
616 | str = "HTTP/1.1 200 OK\r\n" ..
617 | "Content-Length: " .. #data .. "\r\n" ..
618 | "\r\n" .. data
619 | end, lovebird.onerror)
620 | return str
621 | end
622 |
623 |
624 | function lovebird.receive(client, pattern)
625 | while 1 do
626 | local data, msg = client:receive(pattern)
627 | if not data then
628 | if msg == "timeout" then
629 | -- Wait for more data
630 | coroutine.yield(true)
631 | else
632 | -- Disconnected -- yielding nil means we're done
633 | coroutine.yield(nil)
634 | end
635 | else
636 | return data
637 | end
638 | end
639 | end
640 |
641 |
642 | function lovebird.send(client, data)
643 | local idx = 1
644 | while idx < #data do
645 | local res, msg = client:send(data, idx)
646 | if not res and msg == "closed" then
647 | -- Handle disconnect
648 | coroutine.yield(nil)
649 | else
650 | idx = idx + res
651 | coroutine.yield(true)
652 | end
653 | end
654 | end
655 |
656 |
657 | function lovebird.onconnect(client)
658 | -- Create request table
659 | local requestptn = "(%S*)%s*(%S*)%s*(%S*)"
660 | local req = {}
661 | req.socket = client
662 | req.addr, req.port = client:getsockname()
663 | req.request = lovebird.receive(client, "*l")
664 | req.method, req.url, req.proto = req.request:match(requestptn)
665 | req.headers = {}
666 | while 1 do
667 | local line, msg = lovebird.receive(client, "*l")
668 | if not line or #line == 0 then break end
669 | local k, v = line:match("(.-):%s*(.*)$")
670 | req.headers[k] = v
671 | end
672 | if req.headers["Content-Length"] then
673 | req.body = lovebird.receive(client, req.headers["Content-Length"])
674 | end
675 | -- Parse body
676 | req.parsedbody = {}
677 | if req.body then
678 | for k, v in req.body:gmatch("([^&]-)=([^&^#]*)") do
679 | req.parsedbody[k] = lovebird.unescape(v)
680 | end
681 | end
682 | -- Parse request line's url
683 | req.parsedurl = lovebird.parseurl(req.url)
684 | -- Handle request; get data to send and send
685 | local data = lovebird.onrequest(req)
686 | lovebird.send(client, data)
687 | -- Clear up
688 | client:close()
689 | end
690 |
691 |
692 | function lovebird.update()
693 | if not lovebird.inited then lovebird.init() end
694 | -- Handle new connections
695 | while 1 do
696 | -- Accept new connections
697 | local client = lovebird.server:accept()
698 | if not client then break end
699 | client:settimeout(0)
700 | local addr = client:getsockname()
701 | if lovebird.checkwhitelist(addr) then
702 | -- Connection okay -- create and add coroutine to set
703 | local conn = coroutine.wrap(function()
704 | xpcall(function() lovebird.onconnect(client) end, function() end)
705 | end)
706 | lovebird.connections[conn] = true
707 | else
708 | -- Reject connection not on whitelist
709 | lovebird.trace("got non-whitelisted connection attempt: ", addr)
710 | client:close()
711 | end
712 | end
713 | -- Handle existing connections
714 | for conn in pairs(lovebird.connections) do
715 | -- Resume coroutine, remove if it has finished
716 | local status = conn()
717 | if status == nil then
718 | lovebird.connections[conn] = nil
719 | end
720 | end
721 | end
722 |
723 |
724 | return lovebird
725 |
--------------------------------------------------------------------------------
/main.lua:
--------------------------------------------------------------------------------
1 | isomap = require ("isomap")
2 | function love.load()
3 | --Variables
4 | x = 0
5 | y = 0
6 | zoomL = 1
7 | zoom = 1
8 |
9 | --Set background to deep blue
10 | love.graphics.setBackgroundColor(0, 0, 69)
11 | love.graphics.setDefaultFilter("linear", "linear", 8)
12 |
13 |
14 | --Decode JSON map file
15 | isomap.decodeJson("JSONMap.json")
16 |
17 | --Generate map from JSON file (loads assets and creates tables)
18 | isomap.generatePlayField()
19 | end
20 |
21 | function love.update(dt)
22 | require("lovebird").update()
23 | if love.keyboard.isDown("left") then x = x + 900*dt end
24 | if love.keyboard.isDown("right") then x = x - 900*dt end
25 | if love.keyboard.isDown("up") then y = y+900*dt end
26 | if love.keyboard.isDown("down") then y = y-900*dt end
27 | zoomL = lerp(zoomL, zoom, 0.05*(dt*300))
28 | end
29 |
30 | function love.draw()
31 | isomap.drawGround(x, y, zoomL)
32 | isomap.drawObjects(x, y, zoomL)
33 | info = love.graphics.getStats()
34 | love.graphics.print("FPS: "..love.timer.getFPS())
35 | love.graphics.print("Draw calls: "..info.drawcalls, 0, 12)
36 | love.graphics.print("Texture memory: "..((info.texturememory/1024)/1024).."mb", 0, 24)
37 | love.graphics.print("Zoom level: "..zoom, 0, 36)
38 | love.graphics.print("X: "..math.floor(x).." Y: "..math.floor(y), 0, 48)
39 | end
40 |
41 | function love.wheelmoved(x, y)
42 | if y > 0 then
43 | zoom = zoom + 0.1
44 | elseif y < 0 then
45 | zoom = zoom - 0.1
46 | end
47 |
48 | if zoom < 0.1 then zoom = 0.1 end
49 | end
50 |
51 | function lerp(a, b, rate) --EMPLOYEE OF THE MONTH
52 | local result = (1-rate)*a + rate*b
53 | return result
54 | end
55 |
--------------------------------------------------------------------------------
/minimalDemo.lua:
--------------------------------------------------------------------------------
1 | isomap = require ("isomap")
2 | function love.load()
3 | --Variables
4 | x = 0
5 | y = 0
6 |
7 | --Set background to deep blue
8 | love.graphics.setBackgroundColor(0, 0, 69)
9 |
10 | --Decode JSON map file
11 | isomap.decodeJson("JSONMap.json")
12 |
13 | --Generate map from JSON file (loads assets and creates tables)
14 | isomap.generatePlayField()
15 | end
16 |
17 | function love.update(dt)
18 | --Get player input so map moves around.
19 | if love.keyboard.isDown("left") then x = x + 900*dt end
20 | if love.keyboard.isDown("right") then x = x - 900*dt end
21 | if love.keyboard.isDown("up") then y = y+900*dt end
22 | if love.keyboard.isDown("down") then y = y-900*dt end
23 | end
24 |
25 | function love.draw()
26 | isomap.draw(x, y, 1)
27 | end
28 |
--------------------------------------------------------------------------------
/props/pixelTree.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sulunia/isomap-love2d/a08498efef310289617411b8bafb19f36331313a/props/pixelTree.png
--------------------------------------------------------------------------------
/props/praca.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sulunia/isomap-love2d/a08498efef310289617411b8bafb19f36331313a/props/praca.png
--------------------------------------------------------------------------------
/textures/DirtTile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sulunia/isomap-love2d/a08498efef310289617411b8bafb19f36331313a/textures/DirtTile.png
--------------------------------------------------------------------------------
/textures/GrassTile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sulunia/isomap-love2d/a08498efef310289617411b8bafb19f36331313a/textures/GrassTile.png
--------------------------------------------------------------------------------
/textures/SelectTile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sulunia/isomap-love2d/a08498efef310289617411b8bafb19f36331313a/textures/SelectTile.png
--------------------------------------------------------------------------------
/textures/WaterTile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sulunia/isomap-love2d/a08498efef310289617411b8bafb19f36331313a/textures/WaterTile.png
--------------------------------------------------------------------------------
/textures/ls.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sulunia/isomap-love2d/a08498efef310289617411b8bafb19f36331313a/textures/ls.png
--------------------------------------------------------------------------------
/textures/rd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sulunia/isomap-love2d/a08498efef310289617411b8bafb19f36331313a/textures/rd.png
--------------------------------------------------------------------------------
/textures/rdl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sulunia/isomap-love2d/a08498efef310289617411b8bafb19f36331313a/textures/rdl.png
--------------------------------------------------------------------------------
/textures/rdr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sulunia/isomap-love2d/a08498efef310289617411b8bafb19f36331313a/textures/rdr.png
--------------------------------------------------------------------------------
/textures/rdrd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sulunia/isomap-love2d/a08498efef310289617411b8bafb19f36331313a/textures/rdrd.png
--------------------------------------------------------------------------------
/textures/rdv.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sulunia/isomap-love2d/a08498efef310289617411b8bafb19f36331313a/textures/rdv.png
--------------------------------------------------------------------------------
/textures/water.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sulunia/isomap-love2d/a08498efef310289617411b8bafb19f36331313a/textures/water.png
--------------------------------------------------------------------------------