format and stuff

main
Simon Kellet 2 months ago
parent 53aa6d698d
commit 99b420cc7f
  1. 12
      Game/GameKeyPressed.lua
  2. 32
      Game/UpdateGame.lua
  3. 59
      Menu/DrawMenu.lua
  4. 7
      Menu/MenuKeyPressed.lua
  5. 3
      Menu/UpdateMenu.lua
  6. 63
      Pause/DrawPause.lua
  7. 42
      Pause/PauseKeyPressed.lua
  8. 3
      Pause/UpdatePause.lua
  9. 12
      constants.lua
  10. BIN
      game.love
  11. 69
      libs/classic.lua
  12. 242
      libs/profile.lua
  13. 317
      libs/sti/atlas.lua
  14. 2
      libs/sti/graphics.lua
  15. 620
      libs/sti/init.lua
  16. 114
      libs/sti/plugins/box2d.lua
  17. 103
      libs/sti/plugins/bump.lua
  18. 78
      libs/sti/utils.lua
  19. 1653
      libs/windfield/init.lua
  20. 1043
      libs/windfield/mlib/mlib.lua
  21. 46
      main.lua
  22. 108
      player.lua

@ -1,8 +1,7 @@
function GameKeyPressed(key) function GameKeyPressed(key)
if key == "escape" then if key == "escape" then
musicBattle:setVolume(0) musicBattle:setVolume(0)
musicPause:setVolume(0.5) musicPause:setVolume(0.6)
_G.GAMESTATE = "PAUSE" _G.GAMESTATE = "PAUSE"
print("STATE CHANEGD: PAUSED!") print("STATE CHANEGD: PAUSED!")
@ -13,13 +12,8 @@ function GameKeyPressed(key)
DebugFlag = not DebugFlag DebugFlag = not DebugFlag
end end
--TODO: Move player movement code into here! --TODO: Better restart
--[[
-- TODO: Better restart
if key == "r" and not _G.PAUSED then if key == "r" and not _G.PAUSED then
love.load() love.load()
end end
]]--
end end

@ -1,9 +1,31 @@
local function checkWinState()
-- Check P1's health
if UserPlayer1.health <= 0 then --P1 win
_G.P1_WIN = true
_G.P2_WIN = false
UserPlayer1.health = 0
return true
end
if UserPlayer2.health <= 0 then --P2 win
_G.P1_WIN = false
_G.P2_WIN = true
UserPlayer2.health = 0
return true
end
return false
end
local max = math.max -- optimisations
function UpdateGame(dt) function UpdateGame(dt)
--Check if anyone has won
if checkWinState() == true then
print("STATE CHNAGED: WIN!")
_G.GAMESTATE = "WIN"
end
--WindField --WindField
World:update(dt) World:update(dt)
local max = math.max
KeyPressTime1 = max(0, KeyPressTime1 - dt) KeyPressTime1 = max(0, KeyPressTime1 - dt)
if KeyPressTime1 <= 0 then if KeyPressTime1 <= 0 then
EnableKeyPress1 = true EnableKeyPress1 = true
@ -13,6 +35,7 @@ function UpdateGame(dt)
if KeyPressTime2 <= 0 then if KeyPressTime2 <= 0 then
EnableKeyPress2 = true EnableKeyPress2 = true
end end
for i, v in ipairs(Bullets1) do for i, v in ipairs(Bullets1) do
v:update(dt) v:update(dt)
if v.y < 0 then --top of screen if v.y < 0 then --top of screen
@ -69,7 +92,10 @@ function UpdateGame(dt)
end end
end end
end end
UserPlayer1:handleKeys("w", "s", "a", "d", dt)
UserPlayer2:handleKeys("up", "down", "left", "right", dt)
UserPlayer1:updateCol()
UserPlayer2:updateCol()
UserPlayer1:update(dt) UserPlayer1:update(dt)
UserPlayer2:update(dt) UserPlayer2:update(dt)
end end

@ -1,44 +1,43 @@
local function button(x,y, w, h, text, selected) local function button(x, y, w, h, text, selected)
--x,y is the top left corner of the button --x,y is the top left corner of the button
local rounding = 30 -- used for rounding the buttons local rounding = 30 -- used for rounding the buttons
if not selected then if not selected then
love.graphics.setColor(love.math.colorFromBytes(41,134,204)) love.graphics.setColor(love.math.colorFromBytes(41, 134, 204))
elseif selected then elseif selected then
love.graphics.setColor(love.math.colorFromBytes(244,67,54)) love.graphics.setColor(love.math.colorFromBytes(244, 67, 54))
end end
-- Draw rectangle -- Draw rectangle
love.graphics.rectangle("line", x, y, w, h, rounding, rounding) love.graphics.rectangle("line", x, y, w, h, rounding, rounding)
-- Get width and height of text -- Get width and height of text
local tw = MenuFont:getWidth(text) local tw = MenuFont:getWidth(text)
local th = MenuFont:getHeight(text) local th = MenuFont:getHeight(text)
-- Calculate position to center the text -- Calculate position to center the text
local textX = x + (w - tw) / 2 local textX = x + (w - tw) / 2
local textY = y + (h - th) / 2 local textY = y + (h - th) / 2
-- Place text inside the rectangle -- Place text inside the rectangle
love.graphics.setFont(MenuFont) love.graphics.setFont(MenuFont)
love.graphics.print(text, textX, textY) love.graphics.print(text, textX, textY)
end end
local function title() local function title()
local height = love.graphics.getHeight() local height = love.graphics.getHeight()
local width = love.graphics.getWidth() local width = love.graphics.getWidth()
love.graphics.setFont(GameFont) love.graphics.setFont(GameFont)
love.graphics.setColor(0.5,1,1) love.graphics.setColor(0.5, 1, 1)
love.graphics.rectangle("fill", 0, 0, width, height) love.graphics.rectangle("fill", 0, 0, width, height)
love.graphics.setColor(0,0,0) love.graphics.setColor(0, 0, 0)
love.graphics.print("MENU", 100,100) love.graphics.print("MENU", 100, 100)
end end
function DrawMenu() function DrawMenu()
local bwidth, bheight = 300, 140 local bwidth, bheight = 300, 140
title() title()
button(100, 200, bwidth, bheight, "Play", MENU_POS == 0 and true or false) button(100, 200, bwidth, bheight, "Play", MENU_POS == 0 and true or false)
button(100, 350, bwidth, bheight, "???", MENU_POS == 1 and true or false) button(100, 350, bwidth, bheight, "???", MENU_POS == 1 and true or false)
button(100, 500, bwidth, bheight, "???", MENU_POS == 2 and true or false) button(100, 500, bwidth, bheight, "???", MENU_POS == 2 and true or false)
button(100, 650, bwidth, bheight, "Quit", MENU_POS == 3 and true or false) button(100, 650, bwidth, bheight, "Quit", MENU_POS == 3 and true or false)
love.graphics.setColor(255,255,255) -- reset colours love.graphics.setColor(255, 255, 255) -- reset colours
end end

@ -1,5 +1,5 @@
function MenuKeyPressed(key) function MenuKeyPressed(key)
if key == 'return' then if key == "return" then
-- 0 Start Game -- 0 Start Game
-- 1 ?? -- 1 ??
-- 2 ??? -- 2 ???
@ -9,17 +9,13 @@ function MenuKeyPressed(key)
_G.GAMESTATE = "GAME" _G.GAMESTATE = "GAME"
print("STATE CHANEGD: GAME!") print("STATE CHANEGD: GAME!")
musicMenu:stop() musicMenu:stop()
elseif MENU_POS == 1 then elseif MENU_POS == 1 then
print("STATE CHANEGD: DUNNO!") print("STATE CHANEGD: DUNNO!")
elseif MENU_POS == 2 then elseif MENU_POS == 2 then
print("STATE CHANEGD: DUNNO!") print("STATE CHANEGD: DUNNO!")
elseif MENU_POS == 3 then elseif MENU_POS == 3 then
love.event.quit() love.event.quit()
end end
end end
if love.keyboard.isDown("up") then if love.keyboard.isDown("up") then
@ -37,5 +33,4 @@ function MenuKeyPressed(key)
_G.MENU_POS = _G.MENU_POS + 1 _G.MENU_POS = _G.MENU_POS + 1
end end
end end
end end

@ -1,2 +1 @@
function UpdateMenu(dt) function UpdateMenu(dt) end
end

@ -1,45 +1,44 @@
local function button(x,y, w, h, text, selected) local function button(x, y, w, h, text, selected)
--x,y is the top left corner of the button --x,y is the top left corner of the button
local rounding = 30 -- used for rounding the buttons local rounding = 30 -- used for rounding the buttons
if not selected then if not selected then
love.graphics.setColor(love.math.colorFromBytes(41,134,204)) love.graphics.setColor(love.math.colorFromBytes(41, 134, 204))
elseif selected then elseif selected then
love.graphics.setColor(love.math.colorFromBytes(244,67,54)) love.graphics.setColor(love.math.colorFromBytes(244, 67, 54))
end end
-- Draw rectangle -- Draw rectangle
love.graphics.rectangle("fill", x, y, w, h, rounding, rounding) love.graphics.rectangle("fill", x, y, w, h, rounding, rounding)
-- Get width and height of text -- Get width and height of text
local tw = MenuFont:getWidth(text) local tw = MenuFont:getWidth(text)
local th = MenuFont:getHeight(text) local th = MenuFont:getHeight(text)
-- Calculate position to center the text -- Calculate position to center the text
local textX = x + (w - tw) / 2 local textX = x + (w - tw) / 2
local textY = y + (h - th) / 2 local textY = y + (h - th) / 2
-- Place text inside the rectangle -- Place text inside the rectangle
love.graphics.setFont(MenuFont) love.graphics.setFont(MenuFont)
love.graphics.setColor(1,1,1) -- reset colours love.graphics.setColor(1, 1, 1) -- reset colours
love.graphics.print(text, textX, textY) love.graphics.print(text, textX, textY)
end end
function DrawPause() function DrawPause()
local opacity = 0.3 local opacity = 0.3
local height = love.graphics.getHeight() local height = love.graphics.getHeight()
local width = love.graphics.getWidth() local width = love.graphics.getWidth()
local bwidth, bheight = 300, 140 local bwidth, bheight = 300, 140
love.graphics.setFont(GameFont) love.graphics.setFont(GameFont)
DrawGame() --Draw a single frame of the game DrawGame() --Draw a single frame of the game
love.graphics.setColor(0.1,0.1,0.1, opacity) --overlay opaque img love.graphics.setColor(0.1, 0.1, 0.1, opacity) --overlay opaque img
love.graphics.rectangle("fill", 0, 0, width, height) love.graphics.rectangle("fill", 0, 0, width, height)
love.graphics.setColor(1,1,1) love.graphics.setColor(1, 1, 1)
love.graphics.print("PAUSED", 100,100) love.graphics.print("PAUSED", 100, 100)
--love.graphics.print("" .. PAUSE_POS, 200,200) --love.graphics.print("" .. PAUSE_POS, 200,200)
button(100, 200, bwidth, bheight, "Return", PAUSE_POS == 0 and true or false) button(100, 200, bwidth, bheight, "Return", PAUSE_POS == 0 and true or false)
button(100, 350, bwidth, bheight, "Menu", PAUSE_POS == 1 and true or false) button(100, 350, bwidth, bheight, "Menu", PAUSE_POS == 1 and true or false)
button(100, 500, bwidth, bheight, "Quit", PAUSE_POS == 2 and true or false) button(100, 500, bwidth, bheight, "Quit", PAUSE_POS == 2 and true or false)
love.graphics.setColor(255,255,255) -- reset colours love.graphics.setColor(255, 255, 255) -- reset colours
end end

@ -1,30 +1,26 @@
function PauseKeyPressed(key) function PauseKeyPressed(key)
if key == 'return' then if key == "return" then
musicBattle:setVolume(0.5) musicBattle:setVolume(0.5)
musicPause:setVolume(0) musicPause:setVolume(0)
-- 0 Return to game -- 0 Return to game
-- 1 Quit -- 1 Quit
if PAUSE_POS == 0 then if PAUSE_POS == 0 then
-- unpause the game -- unpause the game
_G.GAMESTATE = "GAME" _G.GAMESTATE = "GAME"
print("STATE CHANEGD: GAME!") print("STATE CHANEGD: GAME!")
_G.PAUSED = false _G.PAUSED = false
musicBattle:setVolume(0.5) musicBattle:setVolume(0.5)
musicPause:setVolume(0) musicPause:setVolume(0)
elseif PAUSE_POS == 1 then
elseif PAUSE_POS == 1 then _G.GAMESTATE = "MENU"
_G.GAMESTATE = "MENU" print("STATE CHANEGD: MENU!")
print("STATE CHANEGD: MENU!") _G.PAUSED = false
_G.PAUSED = false musicPause:stop()
musicPause:stop() musicBattle:stop()
musicBattle:stop() elseif PAUSE_POS == 2 then
elseif PAUSE_POS == 2 then
love.event.quit() love.event.quit()
end end
end
end
if love.keyboard.isDown("up") then if love.keyboard.isDown("up") then
if _G.PAUSE_POS == 0 then if _G.PAUSE_POS == 0 then

@ -1,2 +1 @@
function UpdatePause(dt) function UpdatePause(dt) end
end

@ -1,3 +1,11 @@
--[[
* Game states:
* - MENU
* - GAME
* - PAUSE
* - WIN
]]
--
GAMESTATE = "MENU" GAMESTATE = "MENU"
MENU_POS = 0 MENU_POS = 0
@ -6,3 +14,7 @@ MENU_MAX = 3 --0 play, 1 ?, 2 ?, 3 quit
PAUSED = false PAUSED = false
PAUSE_POS = 0 PAUSE_POS = 0
PAUSE_MAX = 2 -- 0 resume, 1 menu, 2 quit PAUSE_MAX = 2 -- 0 resume, 1 menu, 2 quit
-- WIN flags for P1 and P2
P1_WIN = false
P2_WIN = false

Binary file not shown.

@ -7,62 +7,53 @@
-- the terms of the MIT license. See LICENSE for details. -- the terms of the MIT license. See LICENSE for details.
-- --
local Object = {} local Object = {}
Object.__index = Object Object.__index = Object
function Object:new() end
function Object:new()
end
function Object:extend() function Object:extend()
local cls = {} local cls = {}
for k, v in pairs(self) do for k, v in pairs(self) do
if k:find("__") == 1 then if k:find("__") == 1 then
cls[k] = v cls[k] = v
end end
end end
cls.__index = cls cls.__index = cls
cls.super = self cls.super = self
setmetatable(cls, self) setmetatable(cls, self)
return cls return cls
end end
function Object:implement(...) function Object:implement(...)
for _, cls in pairs({...}) do for _, cls in pairs({ ... }) do
for k, v in pairs(cls) do for k, v in pairs(cls) do
if self[k] == nil and type(v) == "function" then if self[k] == nil and type(v) == "function" then
self[k] = v self[k] = v
end end
end end
end end
end end
function Object:is(T) function Object:is(T)
local mt = getmetatable(self) local mt = getmetatable(self)
while mt do while mt do
if mt == T then if mt == T then
return true return true
end end
mt = getmetatable(mt) mt = getmetatable(mt)
end end
return false return false
end end
function Object:__tostring() function Object:__tostring()
return "Object" return "Object"
end end
function Object:__call(...) function Object:__call(...)
local obj = setmetatable({}, self) local obj = setmetatable({}, self)
obj:new(...) obj:new(...)
return obj return obj
end end
return Object return Object

@ -23,91 +23,91 @@ local _internal = {}
-- @tparam number line Line number -- @tparam number line Line number
-- @tparam[opt] table info Debug info table -- @tparam[opt] table info Debug info table
function profile.hooker(event, line, info) function profile.hooker(event, line, info)
info = info or debug.getinfo(2, 'fnS') info = info or debug.getinfo(2, "fnS")
local f = info.func local f = info.func
-- ignore the profiler itself -- ignore the profiler itself
if _internal[f] or info.what ~= "Lua" then if _internal[f] or info.what ~= "Lua" then
return return
end end
-- get the function name if available -- get the function name if available
if info.name then if info.name then
_labeled[f] = info.name _labeled[f] = info.name
end end
-- find the line definition -- find the line definition
if not _defined[f] then if not _defined[f] then
_defined[f] = info.short_src..":"..info.linedefined _defined[f] = info.short_src .. ":" .. info.linedefined
_ncalls[f] = 0 _ncalls[f] = 0
_telapsed[f] = 0 _telapsed[f] = 0
end end
if _tcalled[f] then if _tcalled[f] then
local dt = clock() - _tcalled[f] local dt = clock() - _tcalled[f]
_telapsed[f] = _telapsed[f] + dt _telapsed[f] = _telapsed[f] + dt
_tcalled[f] = nil _tcalled[f] = nil
end end
if event == "tail call" then if event == "tail call" then
local prev = debug.getinfo(3, 'fnS') local prev = debug.getinfo(3, "fnS")
profile.hooker("return", line, prev) profile.hooker("return", line, prev)
profile.hooker("call", line, info) profile.hooker("call", line, info)
elseif event == 'call' then elseif event == "call" then
_tcalled[f] = clock() _tcalled[f] = clock()
else else
_ncalls[f] = _ncalls[f] + 1 _ncalls[f] = _ncalls[f] + 1
end end
end end
--- Sets a clock function to be used by the profiler. --- Sets a clock function to be used by the profiler.
-- @tparam function func Clock function that returns a number -- @tparam function func Clock function that returns a number
function profile.setclock(f) function profile.setclock(f)
assert(type(f) == "function", "clock must be a function") assert(type(f) == "function", "clock must be a function")
clock = f clock = f
end end
--- Starts collecting data. --- Starts collecting data.
function profile.start() function profile.start()
if rawget(_G, 'jit') then if rawget(_G, "jit") then
jit.off() jit.off()
jit.flush() jit.flush()
end end
debug.sethook(profile.hooker, "cr") debug.sethook(profile.hooker, "cr")
end end
--- Stops collecting data. --- Stops collecting data.
function profile.stop() function profile.stop()
debug.sethook() debug.sethook()
for f in pairs(_tcalled) do for f in pairs(_tcalled) do
local dt = clock() - _tcalled[f] local dt = clock() - _tcalled[f]
_telapsed[f] = _telapsed[f] + dt _telapsed[f] = _telapsed[f] + dt
_tcalled[f] = nil _tcalled[f] = nil
end end
-- merge closures -- merge closures
local lookup = {} local lookup = {}
for f, d in pairs(_defined) do for f, d in pairs(_defined) do
local id = (_labeled[f] or '?')..d local id = (_labeled[f] or "?") .. d
local f2 = lookup[id] local f2 = lookup[id]
if f2 then if f2 then
_ncalls[f2] = _ncalls[f2] + (_ncalls[f] or 0) _ncalls[f2] = _ncalls[f2] + (_ncalls[f] or 0)
_telapsed[f2] = _telapsed[f2] + (_telapsed[f] or 0) _telapsed[f2] = _telapsed[f2] + (_telapsed[f] or 0)
_defined[f], _labeled[f] = nil, nil _defined[f], _labeled[f] = nil, nil
_ncalls[f], _telapsed[f] = nil, nil _ncalls[f], _telapsed[f] = nil, nil
else else
lookup[id] = f lookup[id] = f
end end
end end
collectgarbage('collect') collectgarbage("collect")
end end
--- Resets all collected data. --- Resets all collected data.
function profile.reset() function profile.reset()
for f in pairs(_ncalls) do for f in pairs(_ncalls) do
_ncalls[f] = 0 _ncalls[f] = 0
end end
for f in pairs(_telapsed) do for f in pairs(_telapsed) do
_telapsed[f] = 0 _telapsed[f] = 0
end end
for f in pairs(_tcalled) do for f in pairs(_tcalled) do
_tcalled[f] = nil _tcalled[f] = nil
end end
collectgarbage('collect') collectgarbage("collect")
end end
--- This is an internal function. --- This is an internal function.
@ -115,11 +115,11 @@ end
-- @tparam function b Second function -- @tparam function b Second function
-- @treturn boolean True if "a" should rank higher than "b" -- @treturn boolean True if "a" should rank higher than "b"
function profile.comp(a, b) function profile.comp(a, b)
local dt = _telapsed[b] - _telapsed[a] local dt = _telapsed[b] - _telapsed[a]
if dt == 0 then if dt == 0 then
return _ncalls[b] < _ncalls[a] return _ncalls[b] < _ncalls[a]
end end
return dt < 0 return dt < 0
end end
--- Generates a report of functions that have been called since the profile was started. --- Generates a report of functions that have been called since the profile was started.
@ -127,26 +127,26 @@ end
-- @tparam[opt] number limit Maximum number of rows -- @tparam[opt] number limit Maximum number of rows
-- @treturn table Table of rows -- @treturn table Table of rows
function profile.query(limit) function profile.query(limit)
local t = {} local t = {}
for f, n in pairs(_ncalls) do for f, n in pairs(_ncalls) do
if n > 0 then if n > 0 then
t[#t + 1] = f t[#t + 1] = f
end end
end end
table.sort(t, profile.comp) table.sort(t, profile.comp)
if limit then if limit then
while #t > limit do while #t > limit do
table.remove(t) table.remove(t)
end end
end end
for i, f in ipairs(t) do for i, f in ipairs(t) do
local dt = 0 local dt = 0
if _tcalled[f] then if _tcalled[f] then
dt = clock() - _tcalled[f] dt = clock() - _tcalled[f]
end end
t[i] = { i, _labeled[f] or '?', _ncalls[f], _telapsed[f] + dt, _defined[f] } t[i] = { i, _labeled[f] or "?", _ncalls[f], _telapsed[f] + dt, _defined[f] }
end end
return t return t
end end
local cols = { 3, 29, 11, 24, 32 } local cols = { 3, 29, 11, 24, 32 }
@ -156,38 +156,40 @@ local cols = { 3, 29, 11, 24, 32 }
-- @tparam[opt] number limit Maximum number of rows -- @tparam[opt] number limit Maximum number of rows
-- @treturn string Text-based profiling report -- @treturn string Text-based profiling report
function profile.report(n) function profile.report(n)
local out = {} local out = {}
local report = profile.query(n) local report = profile.query(n)
for i, row in ipairs(report) do for i, row in ipairs(report) do
for j = 1, 5 do for j = 1, 5 do
local s = row[j] local s = row[j]
local l2 = cols[j] local l2 = cols[j]
s = tostring(s) s = tostring(s)
local l1 = s:len() local l1 = s:len()
if l1 < l2 then if l1 < l2 then
s = s..(' '):rep(l2-l1) s = s .. (" "):rep(l2 - l1)
elseif l1 > l2 then elseif l1 > l2 then
s = s:sub(l1 - l2 + 1, l1) s = s:sub(l1 - l2 + 1, l1)
end end
row[j] = s row[j] = s
end end
out[i] = table.concat(row, ' | ') out[i] = table.concat(row, " | ")
end end
local row = " +-----+-------------------------------+-------------+--------------------------+----------------------------------+ \n" local row =
local col = " | # | Function | Calls | Time | Code | \n" " +-----+-------------------------------+-------------+--------------------------+----------------------------------+ \n"
local sz = row..col..row local col =
if #out > 0 then " | # | Function | Calls | Time | Code | \n"
sz = sz..' | '..table.concat(out, ' | \n | ')..' | \n' local sz = row .. col .. row
end if #out > 0 then
return '\n'..sz..row sz = sz .. " | " .. table.concat(out, " | \n | ") .. " | \n"
end
return "\n" .. sz .. row
end end
-- store all internal profiler functions -- store all internal profiler functions
for _, v in pairs(profile) do for _, v in pairs(profile) do
if type(v) == "function" then if type(v) == "function" then
_internal[v] = true _internal[v] = true
end end
end end
return profile return profile

@ -10,150 +10,179 @@ local module = {}
-- @param sort If "size" will sort by size, or if "id" will sort by id -- @param sort If "size" will sort by size, or if "id" will sort by id
-- @param ids Array with ids of each file -- @param ids Array with ids of each file
-- @param pow2 If true, will force a power of 2 size -- @param pow2 If true, will force a power of 2 size
function module.Atlas( files, sort, ids, pow2 ) function module.Atlas(files, sort, ids, pow2)
local function Node(x, y, w, h)
local function Node(x, y, w, h) return { x = x, y = y, w = w, h = h }
return {x = x, y = y, w = w, h = h} end
end
local function nextpow2(n)
local function nextpow2( n ) local res = 1
local res = 1 while res <= n do
while res <= n do res = res * 2
res = res * 2 end
end return res
return res end
end
local function loadImgs()
local function loadImgs() local images = {}
local images = {} for i = 1, #files do
for i = 1, #files do images[i] = {}
images[i] = {} --images[i].name = files[i]
--images[i].name = files[i] if ids then
if ids then images[i].id = ids[i] end images[i].id = ids[i]
images[i].img = love.graphics.newImage( files[i] ) end
images[i].w = images[i].img:getWidth() images[i].img = love.graphics.newImage(files[i])
images[i].h = images[i].img:getHeight() images[i].w = images[i].img:getWidth()
images[i].area = images[i].w * images[i].h images[i].h = images[i].img:getHeight()
end images[i].area = images[i].w * images[i].h
if sort == "size" or sort == "id" then end
table.sort( images, function( a, b ) return ( a.area > b.area ) end ) if sort == "size" or sort == "id" then
end table.sort(images, function(a, b)
return images return (a.area > b.area)
end end)
end
--TODO: understand this func return images
local function add(root, id, w, h) end
if root.left or root.right then
if root.left then --TODO: understand this func
local node = add(root.left, id, w, h) local function add(root, id, w, h)
if node then return node end if root.left or root.right then
end if root.left then
if root.right then local node = add(root.left, id, w, h)
local node = add(root.right, id, w, h) if node then
if node then return node end return node
end end
return nil end
end if root.right then
local node = add(root.right, id, w, h)
if w > root.w or h > root.h then return nil end if node then
return node
local _w, _h = root.w - w, root.h - h end
end
if _w <= _h then return nil
root.left = Node(root.x + w, root.y, _w, h) end
root.right = Node(root.x, root.y + h, root.w, _h)
else if w > root.w or h > root.h then
root.left = Node(root.x, root.y + h, w, _h) return nil
root.right = Node(root.x + w, root.y, _w, root.h) end
end
local _w, _h = root.w - w, root.h - h
root.w = w
root.h = h if _w <= _h then
root.id = id root.left = Node(root.x + w, root.y, _w, h)
root.right = Node(root.x, root.y + h, root.w, _h)
return root else
end root.left = Node(root.x, root.y + h, w, _h)
root.right = Node(root.x + w, root.y, _w, root.h)
local function unmap(root) end
if not root then return {} end
root.w = w
local tree = {} root.h = h
if root.id then root.id = id
tree[root.id] = {}
tree[root.id].x, tree[root.id].y = root.x, root.y return root
end end
local left = unmap(root.left) local function unmap(root)
local right = unmap(root.right) if not root then
return {}
for k, v in pairs(left) do end
tree[k] = {}
tree[k].x, tree[k].y = v.x, v.y local tree = {}
end if root.id then
for k, v in pairs(right) do tree[root.id] = {}
tree[k] = {} tree[root.id].x, tree[root.id].y = root.x, root.y
tree[k].x, tree[k].y = v.x, v.y end
end
local left = unmap(root.left)
return tree local right = unmap(root.right)
end
for k, v in pairs(left) do
local function bake() tree[k] = {}
local images = loadImgs() tree[k].x, tree[k].y = v.x, v.y
end
local root = {} for k, v in pairs(right) do
local w, h = images[1].w, images[1].h tree[k] = {}
tree[k].x, tree[k].y = v.x, v.y
if pow2 then end
if w % 1 == 0 then w = nextpow2(w) end
if h % 1 == 0 then h = nextpow2(h) end return tree
end end
repeat local function bake()
local node local images = loadImgs()
root = Node(0, 0, w, h) local root = {}
local w, h = images[1].w, images[1].h
for i = 1, #images do
node = add(root, i, images[i].w, images[i].h) if pow2 then
if not node then break end if w % 1 == 0 then
end w = nextpow2(w)
end
if not node then if h % 1 == 0 then
if h <= w then h = nextpow2(h)
if pow2 then h = h * 2 else h = h + 1 end end
else end
if pow2 then w = w * 2 else w = w + 1 end
end repeat
else local node
break
end root = Node(0, 0, w, h)
until false
for i = 1, #images do
local limits = love.graphics.getSystemLimits() node = add(root, i, images[i].w, images[i].h)
if w > limits.texturesize or h > limits.texturesize then if not node then
return "Resulting texture is too large for this system" break
end end
end
local coords = unmap(root)
local map = love.graphics.newCanvas(w, h) if not node then
love.graphics.setCanvas( map ) if h <= w then
-- love.graphics.clear() if pow2 then
h = h * 2
for i = 1, #images do else
love.graphics.draw(images[i].img, coords[i].x, coords[i].y) h = h + 1
if ids then coords[i].id = images[i].id end end
end else
love.graphics.setCanvas() if pow2 then
w = w * 2
if sort == "ids" then else
table.sort( coords, function( a, b ) return ( a.id < b.id ) end ) w = w + 1
end end
end
return { image = map, coords = coords } else
end break
end
return bake() until false
local limits = love.graphics.getSystemLimits()
if w > limits.texturesize or h > limits.texturesize then
return "Resulting texture is too large for this system"
end
local coords = unmap(root)
local map = love.graphics.newCanvas(w, h)
love.graphics.setCanvas(map)
-- love.graphics.clear()
for i = 1, #images do
love.graphics.draw(images[i].img, coords[i].x, coords[i].y)
if ids then
coords[i].id = images[i].id
end
end
love.graphics.setCanvas()
if sort == "ids" then
table.sort(coords, function(a, b)
return (a.id < b.id)
end)
end
return { image = map, coords = coords }
end
return bake()
end end
return module return module

@ -1,4 +1,4 @@
local lg = _G.love.graphics local lg = _G.love.graphics
local graphics = { isCreated = lg and true or false } local graphics = { isCreated = lg and true or false }
function graphics.newSpriteBatch(...) function graphics.newSpriteBatch(...)

@ -5,22 +5,22 @@
-- @license MIT/X11 -- @license MIT/X11
local STI = { local STI = {
_LICENSE = "MIT/X11", _LICENSE = "MIT/X11",
_URL = "https://github.com/karai17/Simple-Tiled-Implementation", _URL = "https://github.com/karai17/Simple-Tiled-Implementation",
_VERSION = "1.2.3.0", _VERSION = "1.2.3.0",
_DESCRIPTION = "Simple Tiled Implementation is a Tiled Map Editor library designed for the *awesome* LÖVE framework.", _DESCRIPTION = "Simple Tiled Implementation is a Tiled Map Editor library designed for the *awesome* LÖVE framework.",
cache = {} cache = {},
} }
STI.__index = STI STI.__index = STI
local love = _G.love local love = _G.love
local cwd = (...):gsub('%.init$', '') .. "." local cwd = (...):gsub("%.init$", "") .. "."
local utils = require(cwd .. "utils") local utils = require(cwd .. "utils")
local ceil = math.ceil local ceil = math.ceil
local floor = math.floor local floor = math.floor
local lg = require(cwd .. "graphics") local lg = require(cwd .. "graphics")
local atlas = require(cwd .. "atlas") local atlas = require(cwd .. "atlas")
local Map = {} local Map = {}
Map.__index = Map Map.__index = Map
local function new(map, plugins, ox, oy) local function new(map, plugins, ox, oy)
@ -31,10 +31,7 @@ local function new(map, plugins, ox, oy)
else else
-- Check for valid map type -- Check for valid map type
local ext = map:sub(-4, -1) local ext = map:sub(-4, -1)
assert(ext == ".lua", string.format( assert(ext == ".lua", string.format("Invalid file type: %s. File must be of type: lua.", ext))
"Invalid file type: %s. File must be of type: lua.",
ext
))
-- Get directory of map -- Get directory of map
dir = map:reverse():find("[/\\]") or "" dir = map:reverse():find("[/\\]") or ""
@ -79,58 +76,58 @@ function Map:init(path, plugins, ox, oy)
end end
self:resize() self:resize()
self.objects = {} self.objects = {}
self.tiles = {} self.tiles = {}
self.tileInstances = {} self.tileInstances = {}
self.offsetx = ox or 0 self.offsetx = ox or 0
self.offsety = oy or 0 self.offsety = oy or 0
self.freeBatchSprites = {} self.freeBatchSprites = {}
setmetatable(self.freeBatchSprites, { __mode = 'k' }) setmetatable(self.freeBatchSprites, { __mode = "k" })
-- Set tiles, images -- Set tiles, images
local gid = 1 local gid = 1
for i, tileset in ipairs(self.tilesets) do for i, tileset in ipairs(self.tilesets) do
assert(not tileset.filename, "STI does not support external Tilesets.\nYou need to embed all Tilesets.") assert(not tileset.filename, "STI does not support external Tilesets.\nYou need to embed all Tilesets.")
if tileset.image then if tileset.image then
-- Cache images -- Cache images
if lg.isCreated then if lg.isCreated then
local formatted_path = utils.format_path(path .. tileset.image) local formatted_path = utils.format_path(path .. tileset.image)
if not STI.cache[formatted_path] then if not STI.cache[formatted_path] then
utils.fix_transparent_color(tileset, formatted_path) utils.fix_transparent_color(tileset, formatted_path)
utils.cache_image(STI, formatted_path, tileset.image) utils.cache_image(STI, formatted_path, tileset.image)
else else
tileset.image = STI.cache[formatted_path] tileset.image = STI.cache[formatted_path]
end end
end end
gid = self:setTiles(i, tileset, gid) gid = self:setTiles(i, tileset, gid)
elseif tileset.tilecount > 0 then elseif tileset.tilecount > 0 then
-- Build atlas for image collection -- Build atlas for image collection
local files, ids = {}, {} local files, ids = {}, {}
for j = 1, #tileset.tiles do for j = 1, #tileset.tiles do
files[ j ] = utils.format_path(path .. tileset.tiles[j].image) files[j] = utils.format_path(path .. tileset.tiles[j].image)
ids[ j ] = tileset.tiles[j].id ids[j] = tileset.tiles[j].id
end end
local map = atlas.Atlas( files, "ids", ids ) local map = atlas.Atlas(files, "ids", ids)
if lg.isCreated then if lg.isCreated then
local formatted_path = utils.format_path(path .. tileset.name) local formatted_path = utils.format_path(path .. tileset.name)
if not STI.cache[formatted_path] then if not STI.cache[formatted_path] then
-- No need to fix transparency color for collections -- No need to fix transparency color for collections
utils.cache_image(STI, formatted_path, map.image) utils.cache_image(STI, formatted_path, map.image)
tileset.image = map.image tileset.image = map.image
else else
tileset.image = STI.cache[formatted_path] tileset.image = STI.cache[formatted_path]
end end
end end
gid = self:setAtlasTiles(i, tileset, map.coords, gid) gid = self:setAtlasTiles(i, tileset, map.coords, gid)
end end
end end
local layers = {} local layers = {}
@ -174,7 +171,7 @@ end
-- @param plugins A list of plugins to load -- @param plugins A list of plugins to load
function Map:loadPlugins(plugins) function Map:loadPlugins(plugins)
for _, plugin in ipairs(plugins) do for _, plugin in ipairs(plugins) do
local pluginModulePath = cwd .. 'plugins.' .. plugin local pluginModulePath = cwd .. "plugins." .. plugin
local ok, pluginModule = pcall(require, pluginModulePath) local ok, pluginModule = pcall(require, pluginModulePath)
if ok then if ok then
for k, func in pairs(pluginModule) do for k, func in pairs(pluginModule) do
@ -192,19 +189,19 @@ end
-- @param gid First Global ID in Tileset -- @param gid First Global ID in Tileset
-- @return number Next Tileset's first Global ID -- @return number Next Tileset's first Global ID
function Map:setTiles(index, tileset, gid) function Map:setTiles(index, tileset, gid)
local quad = lg.newQuad local quad = lg.newQuad
local imageW = tileset.imagewidth local imageW = tileset.imagewidth
local imageH = tileset.imageheight local imageH = tileset.imageheight
local tileW = tileset.tilewidth local tileW = tileset.tilewidth
local tileH = tileset.tileheight local tileH = tileset.tileheight
local margin = tileset.margin local margin = tileset.margin
local spacing = tileset.spacing local spacing = tileset.spacing
local w = utils.get_tiles(imageW, tileW, margin, spacing) local w = utils.get_tiles(imageW, tileW, margin, spacing)
local h = utils.get_tiles(imageH, tileH, margin, spacing) local h = utils.get_tiles(imageH, tileH, margin, spacing)
for y = 1, h do for y = 1, h do
for x = 1, w do for x = 1, w do
local id = gid - tileset.firstgid local id = gid - tileset.firstgid
local quadX = (x - 1) * tileW + margin + (x - 1) * spacing local quadX = (x - 1) * tileW + margin + (x - 1) * spacing
local quadY = (y - 1) * tileH + margin + (y - 1) * spacing local quadY = (y - 1) * tileH + margin + (y - 1) * spacing
local type = "" local type = ""
@ -212,10 +209,10 @@ function Map:setTiles(index, tileset, gid)
for _, tile in pairs(tileset.tiles) do for _, tile in pairs(tileset.tiles) do
if tile.id == id then if tile.id == id then
properties = tile.properties properties = tile.properties
animation = tile.animation animation = tile.animation
objectGroup = tile.objectGroup objectGroup = tile.objectGroup
type = tile.type type = tile.type
if tile.terrain then if tile.terrain then
terrain = {} terrain = {}
@ -228,31 +225,27 @@ function Map:setTiles(index, tileset, gid)
end end
local tile = { local tile = {
id = id, id = id,
gid = gid, gid = gid,
tileset = index, tileset = index,
type = type, type = type,
quad = quad( quad = quad(quadX, quadY, tileW, tileH, imageW, imageH),
quadX, quadY, properties = properties or {},
tileW, tileH, terrain = terrain,
imageW, imageH animation = animation,
),
properties = properties or {},
terrain = terrain,
animation = animation,
objectGroup = objectGroup, objectGroup = objectGroup,
frame = 1, frame = 1,
time = 0, time = 0,
width = tileW, width = tileW,
height = tileH, height = tileH,
sx = 1, sx = 1,
sy = 1, sy = 1,
r = 0, r = 0,
offset = tileset.tileoffset, offset = tileset.tileoffset,
} }
self.tiles[gid] = tile self.tiles[gid] = tile
gid = gid + 1 gid = gid + 1
end end
end end
@ -266,50 +259,46 @@ end
-- @param gid First Global ID in Tileset -- @param gid First Global ID in Tileset
-- @return number Next Tileset's first Global ID -- @return number Next Tileset's first Global ID
function Map:setAtlasTiles(index, tileset, coords, gid) function Map:setAtlasTiles(index, tileset, coords, gid)
local quad = lg.newQuad local quad = lg.newQuad
local imageW = tileset.image:getWidth() local imageW = tileset.image:getWidth()
local imageH = tileset.image:getHeight() local imageH = tileset.image:getHeight()
local firstgid = tileset.firstgid local firstgid = tileset.firstgid
for i = 1, #tileset.tiles do for i = 1, #tileset.tiles do
local tile = tileset.tiles[i] local tile = tileset.tiles[i]
if tile.terrain then if tile.terrain then
terrain = {} terrain = {}
for j = 1, #tile.terrain do for j = 1, #tile.terrain do
terrain[j] = tileset.terrains[tile.terrain[j] + 1] terrain[j] = tileset.terrains[tile.terrain[j] + 1]
end end
end end
local tile = { local tile = {
id = tile.id, id = tile.id,
gid = firstgid + tile.id, gid = firstgid + tile.id,
tileset = index, tileset = index,
class = tile.class, class = tile.class,
quad = quad( quad = quad(coords[i].x, coords[i].y, tile.width, tile.height, imageW, imageH),
coords[i].x, coords[i].y, properties = tile.properties or {},
tile.width, tile.height, terrain = terrain,
imageW, imageH animation = tile.animation,
), objectGroup = tile.objectGroup,
properties = tile.properties or {}, frame = 1,
terrain = terrain, time = 0,
animation = tile.animation, width = tile.width,
objectGroup = tile.objectGroup, height = tile.height,
frame = 1, sx = 1,
time = 0, sy = 1,
width = tile.width, r = 0,
height = tile.height, offset = tileset.tileoffset,
sx = 1, }
sy = 1,
r = 0, -- Be aware that in collections self.tiles can be a sparse array
offset = tileset.tileoffset, self.tiles[tile.gid] = tile
} end
-- Be aware that in collections self.tiles can be a sparse array return gid + #tileset.tiles
self.tiles[tile.gid] = tile
end
return gid + #tileset.tiles
end end
--- Create Layers --- Create Layers
@ -318,13 +307,19 @@ end
function Map:setLayer(layer, path) function Map:setLayer(layer, path)
if layer.encoding then if layer.encoding then
if layer.encoding == "base64" then if layer.encoding == "base64" then
assert(require "ffi", "Compressed maps require LuaJIT FFI.\nPlease Switch your interperator to LuaJIT or your Tile Layer Format to \"CSV\".") assert(
require("ffi"),
'Compressed maps require LuaJIT FFI.\nPlease Switch your interperator to LuaJIT or your Tile Layer Format to "CSV".'
)
local fd = love.data.decode("string", "base64", layer.data) local fd = love.data.decode("string", "base64", layer.data)
if not layer.compression then if not layer.compression then
layer.data = utils.get_decompressed_data(fd) layer.data = utils.get_decompressed_data(fd)
else else
assert(love.data.decompress, "zlib and gzip compression require LOVE 11.0+.\nPlease set your Tile Layer Format to \"Base64 (uncompressed)\" or \"CSV\".") assert(
love.data.decompress,
'zlib and gzip compression require LOVE 11.0+.\nPlease set your Tile Layer Format to "Base64 (uncompressed)" or "CSV".'
)
if layer.compression == "zlib" then if layer.compression == "zlib" then
local data = love.data.decompress("string", "zlib", fd) local data = love.data.decompress("string", "zlib", fd)
@ -339,21 +334,27 @@ function Map:setLayer(layer, path)
end end
end end
layer.x = (layer.x or 0) + layer.offsetx + self.offsetx layer.x = (layer.x or 0) + layer.offsetx + self.offsetx
layer.y = (layer.y or 0) + layer.offsety + self.offsety layer.y = (layer.y or 0) + layer.offsety + self.offsety
layer.update = function() end layer.update = function() end
if layer.type == "tilelayer" then if layer.type == "tilelayer" then
self:setTileData(layer) self:setTileData(layer)
self:setSpriteBatches(layer) self:setSpriteBatches(layer)
layer.draw = function() self:drawTileLayer(layer) end layer.draw = function()
self:drawTileLayer(layer)
end
elseif layer.type == "objectgroup" then elseif layer.type == "objectgroup" then
self:setObjectData(layer) self:setObjectData(layer)
self:setObjectCoordinates(layer) self:setObjectCoordinates(layer)
self:setObjectSpriteBatches(layer) self:setObjectSpriteBatches(layer)
layer.draw = function() self:drawObjectLayer(layer) end layer.draw = function()
self:drawObjectLayer(layer)
end
elseif layer.type == "imagelayer" then elseif layer.type == "imagelayer" then
layer.draw = function() self:drawImageLayer(layer) end layer.draw = function()
self:drawImageLayer(layer)
end
if layer.image ~= "" then if layer.image ~= "" then
local formatted_path = utils.format_path(path .. layer.image) local formatted_path = utils.format_path(path .. layer.image)
@ -361,8 +362,8 @@ function Map:setLayer(layer, path)
utils.cache_image(STI, formatted_path) utils.cache_image(STI, formatted_path)
end end
layer.image = STI.cache[formatted_path] layer.image = STI.cache[formatted_path]
layer.width = layer.image:getWidth() layer.width = layer.image:getWidth()
layer.height = layer.image:getHeight() layer.height = layer.image:getHeight()
end end
end end
@ -380,7 +381,7 @@ function Map:setTileData(layer)
return return
end end
local i = 1 local i = 1
local map = {} local map = {}
for y = 1, layer.height do for y = 1, layer.height do
@ -404,7 +405,7 @@ end
-- @param layer The Object Layer -- @param layer The Object Layer
function Map:setObjectData(layer) function Map:setObjectData(layer)
for _, object in ipairs(layer.objects) do for _, object in ipairs(layer.objects) do
object.layer = layer object.layer = layer
self.objects[object.id] = object self.objects[object.id] = object
end end
end end
@ -413,10 +414,10 @@ end
-- @param layer The Object Layer -- @param layer The Object Layer
function Map:setObjectCoordinates(layer) function Map:setObjectCoordinates(layer)
for _, object in ipairs(layer.objects) do for _, object in ipairs(layer.objects) do
local x = layer.x + object.x local x = layer.x + object.x
local y = layer.y + object.y local y = layer.y + object.y
local w = object.width local w = object.width
local h = object.height local h = object.height
local cos = math.cos(math.rad(object.rotation)) local cos = math.cos(math.rad(object.rotation))
local sin = math.sin(math.rad(object.rotation)) local sin = math.sin(math.rad(object.rotation))
@ -424,10 +425,10 @@ function Map:setObjectCoordinates(layer)
object.rectangle = {} object.rectangle = {}
local vertices = { local vertices = {
{ x=x, y=y }, { x = x, y = y },
{ x=x + w, y=y }, { x = x + w, y = y },
{ x=x + w, y=y + h }, { x = x + w, y = y + h },
{ x=x, y=y + h }, { x = x, y = y + h },
} }
for _, vertex in ipairs(vertices) do for _, vertex in ipairs(vertices) do
@ -444,14 +445,14 @@ function Map:setObjectCoordinates(layer)
end end
elseif object.shape == "polygon" then elseif object.shape == "polygon" then
for _, vertex in ipairs(object.polygon) do for _, vertex in ipairs(object.polygon) do
vertex.x = vertex.x + x vertex.x = vertex.x + x
vertex.y = vertex.y + y vertex.y = vertex.y + y
vertex.x, vertex.y = utils.rotate_vertex(self, vertex, x, y, cos, sin) vertex.x, vertex.y = utils.rotate_vertex(self, vertex, x, y, cos, sin)
end end
elseif object.shape == "polyline" then elseif object.shape == "polyline" then
for _, vertex in ipairs(object.polyline) do for _, vertex in ipairs(object.polyline) do
vertex.x = vertex.x + x vertex.x = vertex.x + x
vertex.y = vertex.y + y vertex.y = vertex.y + y
vertex.x, vertex.y = utils.rotate_vertex(self, vertex, x, y, cos, sin) vertex.x, vertex.y = utils.rotate_vertex(self, vertex, x, y, cos, sin)
end end
end end
@ -527,16 +528,16 @@ end
-- @param number Tile location on Y axis (in tiles) -- @param number Tile location on Y axis (in tiles)
function Map:addNewLayerTile(layer, chunk, tile, x, y) function Map:addNewLayerTile(layer, chunk, tile, x, y)
local tileset = tile.tileset local tileset = tile.tileset
local image = self.tilesets[tile.tileset].image local image = self.tilesets[tile.tileset].image
local batches local batches
local size local size
if chunk then if chunk then
batches = chunk.batches batches = chunk.batches
size = chunk.width * chunk.height size = chunk.width * chunk.height
else else
batches = layer.batches batches = layer.batches
size = layer.width * layer.height size = layer.width * layer.height
end end
batches[tileset] = batches[tileset] or lg.newSpriteBatch(image, size) batches[tileset] = batches[tileset] or lg.newSpriteBatch(image, size)
@ -547,11 +548,11 @@ function Map:addNewLayerTile(layer, chunk, tile, x, y)
local instance = { local instance = {
layer = layer, layer = layer,
chunk = chunk, chunk = chunk,
gid = tile.gid, gid = tile.gid,
x = tileX, x = tileX,
y = tileY, y = tileY,
r = tile.r, r = tile.r,
oy = 0 oy = 0,
} }
-- NOTE: STI can run headless so it is not guaranteed that a batch exists. -- NOTE: STI can run headless so it is not guaranteed that a batch exists.
@ -575,10 +576,10 @@ function Map:set_batches(layer, chunk)
local offsetX = chunk and chunk.x or 0 local offsetX = chunk and chunk.x or 0
local offsetY = chunk and chunk.y or 0 local offsetY = chunk and chunk.y or 0
local startX = 1 local startX = 1
local startY = 1 local startY = 1
local endX = chunk and chunk.width or layer.width local endX = chunk and chunk.width or layer.width
local endY = chunk and chunk.height or layer.height local endY = chunk and chunk.height or layer.height
local incrementX = 1 local incrementX = 1
local incrementY = 1 local incrementY = 1
@ -683,7 +684,7 @@ end
-- @param layer The Object Layer -- @param layer The Object Layer
function Map:setObjectSpriteBatches(layer) function Map:setObjectSpriteBatches(layer)
local newBatch = lg.newSpriteBatch local newBatch = lg.newSpriteBatch
local batches = {} local batches = {}
if layer.draworder == "topdown" then if layer.draworder == "topdown" then
table.sort(layer.objects, function(a, b) table.sort(layer.objects, function(a, b)
@ -693,13 +694,13 @@ function Map:setObjectSpriteBatches(layer)
for _, object in ipairs(layer.objects) do for _, object in ipairs(layer.objects) do
if object.gid then if object.gid then
local tile = self.tiles[object.gid] or self:setFlippedGID(object.gid) local tile = self.tiles[object.gid] or self:setFlippedGID(object.gid)
local tileset = tile.tileset local tileset = tile.tileset
local image = self.tilesets[tileset].image local image = self.tilesets[tileset].image
batches[tileset] = batches[tileset] or newBatch(image) batches[tileset] = batches[tileset] or newBatch(image)
local sx = object.width / tile.width local sx = object.width / tile.width
local sy = object.height / tile.height local sy = object.height / tile.height
-- Tiled rotates around bottom left corner, where love2D rotates around top left corner -- Tiled rotates around bottom left corner, where love2D rotates around top left corner
@ -731,14 +732,14 @@ function Map:setObjectSpriteBatches(layer)
end end
local instance = { local instance = {
id = batch:add(tile.quad, tileX, tileY, tileR, tile.sx * sx, tile.sy * sy, ox, oy), id = batch:add(tile.quad, tileX, tileY, tileR, tile.sx * sx, tile.sy * sy, ox, oy),
batch = batch, batch = batch,
layer = layer, layer = layer,
gid = tile.gid, gid = tile.gid,
x = tileX, x = tileX,
y = tileY - oy, y = tileY - oy,
r = tileR, r = tileR,
oy = oy oy = oy,
} }
self.tileInstances[tile.gid] = self.tileInstances[tile.gid] or {} self.tileInstances[tile.gid] = self.tileInstances[tile.gid] or {}
@ -756,12 +757,12 @@ end
function Map:addCustomLayer(name, index) function Map:addCustomLayer(name, index)
index = index or #self.layers + 1 index = index or #self.layers + 1
local layer = { local layer = {
type = "customlayer", type = "customlayer",
name = name, name = name,
visible = true, visible = true,
opacity = 1, opacity = 1,
properties = {}, properties = {},
} }
function layer.draw() end function layer.draw() end
function layer.update() end function layer.update() end
@ -778,16 +779,16 @@ end
function Map:convertToCustomLayer(index) function Map:convertToCustomLayer(index)
local layer = assert(self.layers[index], "Layer not found: " .. index) local layer = assert(self.layers[index], "Layer not found: " .. index)
layer.type = "customlayer" layer.type = "customlayer"
layer.x = nil layer.x = nil
layer.y = nil layer.y = nil
layer.width = nil layer.width = nil
layer.height = nil layer.height = nil
layer.encoding = nil layer.encoding = nil
layer.data = nil layer.data = nil
layer.chunks = nil layer.chunks = nil
layer.objects = nil layer.objects = nil
layer.image = nil layer.image = nil
function layer.draw() end function layer.draw() end
function layer.update() end function layer.update() end
@ -862,16 +863,19 @@ function Map:update(dt)
tile.time = tile.time + dt * 1000 tile.time = tile.time + dt * 1000
while tile.time > tonumber(tile.animation[tile.frame].duration) do while tile.time > tonumber(tile.animation[tile.frame].duration) do
update = true update = true
tile.time = tile.time - tonumber(tile.animation[tile.frame].duration) tile.time = tile.time - tonumber(tile.animation[tile.frame].duration)
tile.frame = tile.frame + 1 tile.frame = tile.frame + 1
if tile.frame > #tile.animation then tile.frame = 1 end if tile.frame > #tile.animation then
tile.frame = 1
end
end end
if update and self.tileInstances[tile.gid] then if update and self.tileInstances[tile.gid] then
for _, j in pairs(self.tileInstances[tile.gid]) do for _, j in pairs(self.tileInstances[tile.gid]) do
local t = self.tiles[tonumber(tile.animation[tile.frame].tileid) + self.tilesets[tile.tileset].firstgid] local t =
self.tiles[tonumber(tile.animation[tile.frame].tileid) + self.tilesets[tile.tileset].firstgid]
j.batch:set(j.id, t.quad, j.x, j.y, j.r, tile.sx, tile.sy, 0, j.oy) j.batch:set(j.id, t.quad, j.x, j.y, j.r, tile.sx, tile.sy, 0, j.oy)
end end
end end
@ -948,18 +952,18 @@ end
--- Draw an individual Layer --- Draw an individual Layer
-- @param layer The Layer to draw -- @param layer The Layer to draw
function Map.drawLayer(_, layer) function Map.drawLayer(_, layer)
local r,g,b,a = lg.getColor() local r, g, b, a = lg.getColor()
-- if the layer has a tintcolor set -- if the layer has a tintcolor set
if layer.tintcolor then if layer.tintcolor then
r, g, b, a = unpack(layer.tintcolor) r, g, b, a = unpack(layer.tintcolor)
a = a or 255 -- alpha may not be specified a = a or 255 -- alpha may not be specified
lg.setColor(r/255, g/255, b/255, a/255) -- Tiled uses 0-255 lg.setColor(r / 255, g / 255, b / 255, a / 255) -- Tiled uses 0-255
-- if a tintcolor is not given just use the current color -- if a tintcolor is not given just use the current color
else else
lg.setColor(r, g, b, a * layer.opacity) lg.setColor(r, g, b, a * layer.opacity)
end end
layer:draw() layer:draw()
lg.setColor(r,g,b,a) lg.setColor(r, g, b, a)
end end
--- Default draw function for Tile Layers --- Default draw function for Tile Layers
@ -996,10 +1000,10 @@ function Map:drawObjectLayer(layer)
assert(layer.type == "objectgroup", "Invalid layer type: " .. layer.type .. ". Layer must be of type: objectgroup") assert(layer.type == "objectgroup", "Invalid layer type: " .. layer.type .. ". Layer must be of type: objectgroup")
local line = { 160, 160, 160, 255 * layer.opacity } local line = { 160, 160, 160, 255 * layer.opacity }
local fill = { 160, 160, 160, 255 * layer.opacity * 0.5 } local fill = { 160, 160, 160, 255 * layer.opacity * 0.5 }
local r,g,b,a = lg.getColor() local r, g, b, a = lg.getColor()
local reset = { r, g, b, a * layer.opacity } local reset = { r, g, b, a * layer.opacity }
local function sortVertices(obj) local function sortVertices(obj)
local vertex = {} local vertex = {}
@ -1058,7 +1062,7 @@ function Map:drawObjectLayer(layer)
for _, batch in pairs(layer.batches) do for _, batch in pairs(layer.batches) do
lg.draw(batch, 0, 0) lg.draw(batch, 0, 0)
end end
lg.setColor(r,g,b,a) lg.setColor(r, g, b, a)
end end
--- Default draw function for Image Layers --- Default draw function for Image Layers
@ -1118,51 +1122,51 @@ end
-- @param gid The flagged Global ID -- @param gid The flagged Global ID
-- @return table Flipped Tile -- @return table Flipped Tile
function Map:setFlippedGID(gid) function Map:setFlippedGID(gid)
local bit31 = 2147483648 local bit31 = 2147483648
local bit30 = 1073741824 local bit30 = 1073741824
local bit29 = 536870912 local bit29 = 536870912
local flipX = false local flipX = false
local flipY = false local flipY = false
local flipD = false local flipD = false
local realgid = gid local realgid = gid
if realgid >= bit31 then if realgid >= bit31 then
realgid = realgid - bit31 realgid = realgid - bit31
flipX = not flipX flipX = not flipX
end end
if realgid >= bit30 then if realgid >= bit30 then
realgid = realgid - bit30 realgid = realgid - bit30
flipY = not flipY flipY = not flipY
end end
if realgid >= bit29 then if realgid >= bit29 then
realgid = realgid - bit29 realgid = realgid - bit29
flipD = not flipD flipD = not flipD
end end
local tile = self.tiles[realgid] local tile = self.tiles[realgid]
local data = { local data = {
id = tile.id, id = tile.id,
gid = gid, gid = gid,
tileset = tile.tileset, tileset = tile.tileset,
frame = tile.frame, frame = tile.frame,
time = tile.time, time = tile.time,
width = tile.width, width = tile.width,
height = tile.height, height = tile.height,
offset = tile.offset, offset = tile.offset,
quad = tile.quad, quad = tile.quad,
properties = tile.properties, properties = tile.properties,
terrain = tile.terrain, terrain = tile.terrain,
animation = tile.animation, animation = tile.animation,
sx = tile.sx, sx = tile.sx,
sy = tile.sy, sy = tile.sy,
r = tile.r, r = tile.r,
} }
if flipX then if flipX then
if flipY and flipD then if flipY and flipD then
data.r = math.rad(-90) data.r = math.rad(-90)
data.sy = -1 data.sy = -1
elseif flipY then elseif flipY then
data.sx = -1 data.sx = -1
@ -1179,7 +1183,7 @@ function Map:setFlippedGID(gid)
data.sy = -1 data.sy = -1
end end
elseif flipD then elseif flipD then
data.r = math.rad(90) data.r = math.rad(90)
data.sy = -1 data.sy = -1
end end
@ -1284,22 +1288,9 @@ function Map:swapTile(instance, tile)
-- Update sprite batch -- Update sprite batch
if instance.batch then if instance.batch then
if tile then if tile then
instance.batch:set( instance.batch:set(instance.id, tile.quad, instance.x, instance.y, tile.r, tile.sx, tile.sy)
instance.id,
tile.quad,
instance.x,
instance.y,
tile.r,
tile.sx,
tile.sy
)
else else
instance.batch:set( instance.batch:set(instance.id, instance.x, instance.y, 0, 0)
instance.id,
instance.x,
instance.y,
0,
0)
self.freeBatchSprites[instance.batch] = self.freeBatchSprites[instance.batch] or {} self.freeBatchSprites[instance.batch] = self.freeBatchSprites[instance.batch] or {}
table.insert(self.freeBatchSprites[instance.batch], instance) table.insert(self.freeBatchSprites[instance.batch], instance)
@ -1329,12 +1320,12 @@ function Map:swapTile(instance, tile)
newInstance.layer = instance.layer newInstance.layer = instance.layer
newInstance.batch = instance.batch newInstance.batch = instance.batch
newInstance.id = instance.id newInstance.id = instance.id
newInstance.gid = tile.gid or 0 newInstance.gid = tile.gid or 0
newInstance.x = instance.x newInstance.x = instance.x
newInstance.y = instance.y newInstance.y = instance.y
newInstance.r = tile.r or 0 newInstance.r = tile.r or 0
newInstance.oy = tile.r ~= 0 and tile.height or 0 newInstance.oy = tile.r ~= 0 and tile.height or 0
table.insert(self.tileInstances[tile.gid], newInstance) table.insert(self.tileInstances[tile.gid], newInstance)
end end
end end
@ -1344,35 +1335,26 @@ end
-- @param y The Y axis location of the point (in tiles) -- @param y The Y axis location of the point (in tiles)
-- @return number The X axis location of the point (in pixels) -- @return number The X axis location of the point (in pixels)
-- @return number The Y axis location of the point (in pixels) -- @return number The Y axis location of the point (in pixels)
function Map:convertTileToPixel(x,y) function Map:convertTileToPixel(x, y)
if self.orientation == "orthogonal" then if self.orientation == "orthogonal" then
local tileW = self.tilewidth local tileW = self.tilewidth
local tileH = self.tileheight local tileH = self.tileheight
return return x * tileW, y * tileH
x * tileW,
y * tileH
elseif self.orientation == "isometric" then elseif self.orientation == "isometric" then
local mapH = self.height local mapH = self.height
local tileW = self.tilewidth local tileW = self.tilewidth
local tileH = self.tileheight local tileH = self.tileheight
local offsetX = mapH * tileW / 2 local offsetX = mapH * tileW / 2
return return (x - y) * tileW / 2 + offsetX, (x + y) * tileH / 2
(x - y) * tileW / 2 + offsetX, elseif self.orientation == "staggered" or self.orientation == "hexagonal" then
(x + y) * tileH / 2 local tileW = self.tilewidth
elseif self.orientation == "staggered" or local tileH = self.tileheight
self.orientation == "hexagonal" then
local tileW = self.tilewidth
local tileH = self.tileheight
local sideLen = self.hexsidelength or 0 local sideLen = self.hexsidelength or 0
if self.staggeraxis == "x" then if self.staggeraxis == "x" then
return return x * tileW, ceil(y) * (tileH + sideLen) + (ceil(y) % 2 == 0 and tileH or 0)
x * tileW,
ceil(y) * (tileH + sideLen) + (ceil(y) % 2 == 0 and tileH or 0)
else else
return return ceil(x) * (tileW + sideLen) + (ceil(x) % 2 == 0 and tileW or 0), y * tileH
ceil(x) * (tileW + sideLen) + (ceil(x) % 2 == 0 and tileW or 0),
y * tileH
end end
end end
end end
@ -1386,20 +1368,16 @@ function Map:convertPixelToTile(x, y)
if self.orientation == "orthogonal" then if self.orientation == "orthogonal" then
local tileW = self.tilewidth local tileW = self.tilewidth
local tileH = self.tileheight local tileH = self.tileheight
return return x / tileW, y / tileH
x / tileW,
y / tileH
elseif self.orientation == "isometric" then elseif self.orientation == "isometric" then
local mapH = self.height local mapH = self.height
local tileW = self.tilewidth local tileW = self.tilewidth
local tileH = self.tileheight local tileH = self.tileheight
local offsetX = mapH * tileW / 2 local offsetX = mapH * tileW / 2
return return y / tileH + (x - offsetX) / tileW, y / tileH - (x - offsetX) / tileW
y / tileH + (x - offsetX) / tileW,
y / tileH - (x - offsetX) / tileW
elseif self.orientation == "staggered" then elseif self.orientation == "staggered" then
local staggerX = self.staggeraxis == "x" local staggerX = self.staggeraxis == "x"
local even = self.staggerindex == "even" local even = self.staggerindex == "even"
local function topLeft(x, y) local function topLeft(x, y)
if staggerX then if staggerX then
@ -1474,48 +1452,48 @@ function Map:convertPixelToTile(x, y)
y = y - (even and tileH / 2 or 0) y = y - (even and tileH / 2 or 0)
end end
local halfH = tileH / 2 local halfH = tileH / 2
local ratio = tileH / tileW local ratio = tileH / tileW
local referenceX = ceil(x / tileW) local referenceX = ceil(x / tileW)
local referenceY = ceil(y / tileH) local referenceY = ceil(y / tileH)
local relativeX = x - referenceX * tileW local relativeX = x - referenceX * tileW
local relativeY = y - referenceY * tileH local relativeY = y - referenceY * tileH
if (halfH - relativeX * ratio > relativeY) then if halfH - relativeX * ratio > relativeY then
return topLeft(referenceX, referenceY) return topLeft(referenceX, referenceY)
elseif (-halfH + relativeX * ratio > relativeY) then elseif -halfH + relativeX * ratio > relativeY then
return topRight(referenceX, referenceY) return topRight(referenceX, referenceY)
elseif (halfH + relativeX * ratio < relativeY) then elseif halfH + relativeX * ratio < relativeY then
return bottomLeft(referenceX, referenceY) return bottomLeft(referenceX, referenceY)
elseif (halfH * 3 - relativeX * ratio < relativeY) then elseif halfH * 3 - relativeX * ratio < relativeY then
return bottomRight(referenceX, referenceY) return bottomRight(referenceX, referenceY)
end end
return referenceX, referenceY return referenceX, referenceY
elseif self.orientation == "hexagonal" then elseif self.orientation == "hexagonal" then
local staggerX = self.staggeraxis == "x" local staggerX = self.staggeraxis == "x"
local even = self.staggerindex == "even" local even = self.staggerindex == "even"
local tileW = self.tilewidth local tileW = self.tilewidth
local tileH = self.tileheight local tileH = self.tileheight
local sideLenX = 0 local sideLenX = 0
local sideLenY = 0 local sideLenY = 0
local colW = tileW / 2 local colW = tileW / 2
local rowH = tileH / 2 local rowH = tileH / 2
if staggerX then if staggerX then
sideLenX = self.hexsidelength sideLenX = self.hexsidelength
x = x - (even and tileW or (tileW - sideLenX) / 2) x = x - (even and tileW or (tileW - sideLenX) / 2)
colW = colW - (colW - sideLenX / 2) / 2 colW = colW - (colW - sideLenX / 2) / 2
else else
sideLenY = self.hexsidelength sideLenY = self.hexsidelength
y = y - (even and tileH or (tileH - sideLenY) / 2) y = y - (even and tileH or (tileH - sideLenY) / 2)
rowH = rowH - (rowH - sideLenY / 2) / 2 rowH = rowH - (rowH - sideLenY / 2) / 2
end end
local referenceX = ceil(x) / (colW * 2) local referenceX = ceil(x) / (colW * 2)
local referenceY = ceil(y) / (rowH * 2) local referenceY = ceil(y) / (rowH * 2)
-- If in staggered line, then shift reference by 0.5 of other axes -- If in staggered line, then shift reference by 0.5 of other axes
if staggerX then if staggerX then
if (floor(referenceX) % 2 == 0) == even then if (floor(referenceX) % 2 == 0) == even then
referenceY = referenceY - 0.5 referenceY = referenceY - 0.5
@ -1526,31 +1504,31 @@ function Map:convertPixelToTile(x, y)
end end
end end
local relativeX = x - referenceX * colW * 2 local relativeX = x - referenceX * colW * 2
local relativeY = y - referenceY * rowH * 2 local relativeY = y - referenceY * rowH * 2
local centers local centers
if staggerX then if staggerX then
local left = sideLenX / 2 local left = sideLenX / 2
local centerX = left + colW local centerX = left + colW
local centerY = tileH / 2 local centerY = tileH / 2
centers = { centers = {
{ x = left, y = centerY }, { x = left, y = centerY },
{ x = centerX, y = centerY - rowH }, { x = centerX, y = centerY - rowH },
{ x = centerX, y = centerY + rowH }, { x = centerX, y = centerY + rowH },
{ x = centerX + colW, y = centerY }, { x = centerX + colW, y = centerY },
} }
else else
local top = sideLenY / 2 local top = sideLenY / 2
local centerX = tileW / 2 local centerX = tileW / 2
local centerY = top + rowH local centerY = top + rowH
centers = { centers = {
{ x = centerX, y = top }, { x = centerX, y = top },
{ x = centerX - colW, y = centerY }, { x = centerX - colW, y = centerY },
{ x = centerX + colW, y = centerY }, { x = centerX + colW, y = centerY },
{ x = centerX, y = centerY + rowH } { x = centerX, y = centerY + rowH },
} }
end end
@ -1571,24 +1549,22 @@ function Map:convertPixelToTile(x, y)
end end
local offsetsStaggerX = { local offsetsStaggerX = {
{ x = 1, y = 1 }, { x = 1, y = 1 },
{ x = 2, y = 0 }, { x = 2, y = 0 },
{ x = 2, y = 1 }, { x = 2, y = 1 },
{ x = 3, y = 1 }, { x = 3, y = 1 },
} }
local offsetsStaggerY = { local offsetsStaggerY = {
{ x = 1, y = 1 }, { x = 1, y = 1 },
{ x = 0, y = 2 }, { x = 0, y = 2 },
{ x = 1, y = 2 }, { x = 1, y = 2 },
{ x = 1, y = 3 }, { x = 1, y = 3 },
} }
local offsets = staggerX and offsetsStaggerX or offsetsStaggerY local offsets = staggerX and offsetsStaggerX or offsetsStaggerY
return return referenceX + offsets[nearest].x, referenceY + offsets[nearest].y
referenceX + offsets[nearest].x,
referenceY + offsets[nearest].y
end end
end end

@ -4,14 +4,14 @@
-- @copyright 2019 -- @copyright 2019
-- @license MIT/X11 -- @license MIT/X11
local love = _G.love local love = _G.love
local utils = require((...):gsub('plugins.box2d', 'utils')) local utils = require((...):gsub("plugins.box2d", "utils"))
local lg = require((...):gsub('plugins.box2d', 'graphics')) local lg = require((...):gsub("plugins.box2d", "graphics"))
return { return {
box2d_LICENSE = "MIT/X11", box2d_LICENSE = "MIT/X11",
box2d_URL = "https://github.com/karai17/Simple-Tiled-Implementation", box2d_URL = "https://github.com/karai17/Simple-Tiled-Implementation",
box2d_VERSION = "2.3.2.7", box2d_VERSION = "2.3.2.7",
box2d_DESCRIPTION = "Box2D hooks for STI.", box2d_DESCRIPTION = "Box2D hooks for STI.",
--- Initialize Box2D physics world. --- Initialize Box2D physics world.
@ -19,7 +19,7 @@ return {
box2d_init = function(map, world) box2d_init = function(map, world)
assert(love.physics, "To use the Box2D plugin, please enable the love.physics module.") assert(love.physics, "To use the Box2D plugin, please enable the love.physics module.")
local body = love.physics.newBody(world, map.offsetx, map.offsety) local body = love.physics.newBody(world, map.offsetx, map.offsety)
local collision = { local collision = {
body = body, body = body,
} }
@ -40,32 +40,32 @@ return {
local currentBody = body local currentBody = body
--dynamic are objects/players etc. --dynamic are objects/players etc.
if userdata.properties.dynamic == true then if userdata.properties.dynamic == true then
currentBody = love.physics.newBody(world, map.offsetx, map.offsety, 'dynamic') currentBody = love.physics.newBody(world, map.offsetx, map.offsety, "dynamic")
-- static means it shouldn't move. Things like walls/ground. -- static means it shouldn't move. Things like walls/ground.
elseif userdata.properties.static == true then elseif userdata.properties.static == true then
currentBody = love.physics.newBody(world, map.offsetx, map.offsety, 'static') currentBody = love.physics.newBody(world, map.offsetx, map.offsety, "static")
-- kinematic means that the object is static in the game world but effects other bodies -- kinematic means that the object is static in the game world but effects other bodies
elseif userdata.properties.kinematic == true then elseif userdata.properties.kinematic == true then
currentBody = love.physics.newBody(world, map.offsetx, map.offsety, 'kinematic') currentBody = love.physics.newBody(world, map.offsetx, map.offsety, "kinematic")
end end
local fixture = love.physics.newFixture(currentBody, shape) local fixture = love.physics.newFixture(currentBody, shape)
fixture:setUserData(userdata) fixture:setUserData(userdata)
-- Set some custom properties from userdata (or use default set by box2d) -- Set some custom properties from userdata (or use default set by box2d)
fixture:setFriction(userdata.properties.friction or 0.2) fixture:setFriction(userdata.properties.friction or 0.2)
fixture:setRestitution(userdata.properties.restitution or 0.0) fixture:setRestitution(userdata.properties.restitution or 0.0)
fixture:setSensor(userdata.properties.sensor or false) fixture:setSensor(userdata.properties.sensor or false)
fixture:setFilterData( fixture:setFilterData(
userdata.properties.categories or 1, userdata.properties.categories or 1,
userdata.properties.mask or 65535, userdata.properties.mask or 65535,
userdata.properties.group or 0 userdata.properties.group or 0
) )
local obj = { local obj = {
object = object, object = object,
body = currentBody, body = currentBody,
shape = shape, shape = shape,
fixture = fixture, fixture = fixture,
} }
@ -84,33 +84,33 @@ return {
local function calculateObjectPosition(object, tile) local function calculateObjectPosition(object, tile)
local o = { local o = {
shape = object.shape, shape = object.shape,
x = (object.dx or object.x) + map.offsetx, x = (object.dx or object.x) + map.offsetx,
y = (object.dy or object.y) + map.offsety, y = (object.dy or object.y) + map.offsety,
w = object.width, w = object.width,
h = object.height, h = object.height,
polygon = object.polygon or object.polyline or object.ellipse or object.rectangle polygon = object.polygon or object.polyline or object.ellipse or object.rectangle,
} }
local userdata = { local userdata = {
object = o, object = o,
properties = object.properties properties = object.properties,
} }
o.r = object.rotation or 0 o.r = object.rotation or 0
if o.shape == "rectangle" then if o.shape == "rectangle" then
local cos = math.cos(math.rad(o.r)) local cos = math.cos(math.rad(o.r))
local sin = math.sin(math.rad(o.r)) local sin = math.sin(math.rad(o.r))
local oy = 0 local oy = 0
if object.gid then if object.gid then
local tileset = map.tilesets[map.tiles[object.gid].tileset] local tileset = map.tilesets[map.tiles[object.gid].tileset]
local lid = object.gid - tileset.firstgid local lid = object.gid - tileset.firstgid
local t = {} local t = {}
-- This fixes a height issue -- This fixes a height issue
o.y = o.y + map.tiles[object.gid].offset.y o.y = o.y + map.tiles[object.gid].offset.y
oy = o.h oy = o.h
for _, tt in ipairs(tileset.tiles) do for _, tt in ipairs(tileset.tiles) do
if tt.id == lid then if tt.id == lid then
@ -133,10 +133,10 @@ return {
end end
o.polygon = { o.polygon = {
{ x=o.x+0, y=o.y+0 }, { x = o.x + 0, y = o.y + 0 },
{ x=o.x+o.w, y=o.y+0 }, { x = o.x + o.w, y = o.y + 0 },
{ x=o.x+o.w, y=o.y+o.h }, { x = o.x + o.w, y = o.y + o.h },
{ x=o.x+0, y=o.y+o.h } { x = o.x + 0, y = o.y + o.h },
} }
for _, vertex in ipairs(o.polygon) do for _, vertex in ipairs(o.polygon) do
@ -149,7 +149,7 @@ return {
if not o.polygon then if not o.polygon then
o.polygon = utils.convert_ellipse_to_polygon(o.x, o.y, o.w, o.h) o.polygon = utils.convert_ellipse_to_polygon(o.x, o.y, o.w, o.h)
end end
local vertices = getPolygonVertices(o) local vertices = getPolygonVertices(o)
local triangles = love.math.triangulate(vertices) local triangles = love.math.triangulate(vertices)
for _, triangle in ipairs(triangles) do for _, triangle in ipairs(triangles) do
@ -167,7 +167,7 @@ return {
end end
end end
local vertices = getPolygonVertices(o) local vertices = getPolygonVertices(o)
local triangles = love.math.triangulate(vertices) local triangles = love.math.triangulate(vertices)
for _, triangle in ipairs(triangles) do for _, triangle in ipairs(triangles) do
@ -197,12 +197,12 @@ return {
-- Every instance of a tile -- Every instance of a tile
if tile.properties.collidable == true then if tile.properties.collidable == true then
local object = { local object = {
shape = "rectangle", shape = "rectangle",
x = instance.x, x = instance.x,
y = instance.y, y = instance.y,
width = map.tilewidth, width = map.tilewidth,
height = map.tileheight, height = map.tileheight,
properties = tile.properties properties = tile.properties,
} }
calculateObjectPosition(object, instance) calculateObjectPosition(object, instance)
@ -222,12 +222,12 @@ return {
for _, instance in ipairs(tiles) do for _, instance in ipairs(tiles) do
if instance.layer == layer then if instance.layer == layer then
local object = { local object = {
shape = "rectangle", shape = "rectangle",
x = instance.x, x = instance.x,
y = instance.y, y = instance.y,
width = tileset.tilewidth, width = tileset.tilewidth,
height = tileset.tileheight, height = tileset.tileheight,
properties = tile.properties properties = tile.properties,
} }
calculateObjectPosition(object, instance) calculateObjectPosition(object, instance)
@ -240,12 +240,12 @@ return {
end end
elseif layer.type == "imagelayer" then elseif layer.type == "imagelayer" then
local object = { local object = {
shape = "rectangle", shape = "rectangle",
x = layer.x or 0, x = layer.x or 0,
y = layer.y or 0, y = layer.y or 0,
width = layer.width, width = layer.width,
height = layer.height, height = layer.height,
properties = layer.properties properties = layer.properties,
} }
calculateObjectPosition(object) calculateObjectPosition(object)
@ -295,7 +295,7 @@ return {
lg.translate(math.floor(tx or 0), math.floor(ty or 0)) lg.translate(math.floor(tx or 0), math.floor(ty or 0))
for _, obj in ipairs(collision) do for _, obj in ipairs(collision) do
local points = {obj.body:getWorldPoints(obj.shape:getPoints())} local points = { obj.body:getWorldPoints(obj.shape:getPoints()) }
local shape_type = obj.shape:getType() local shape_type = obj.shape:getType()
if shape_type == "edge" or shape_type == "chain" then if shape_type == "edge" or shape_type == "chain" then
@ -303,12 +303,12 @@ return {
elseif shape_type == "polygon" then elseif shape_type == "polygon" then
love.graphics.polygon("line", points) love.graphics.polygon("line", points)
else else
error("sti box2d plugin does not support "..shape_type.." shapes") error("sti box2d plugin does not support " .. shape_type .. " shapes")
end end
end end
lg.pop() lg.pop()
end end,
} }
--- Custom Properties in Tiled are used to tell this plugin what to do. --- Custom Properties in Tiled are used to tell this plugin what to do.

@ -4,13 +4,13 @@
-- @copyright 2019 -- @copyright 2019
-- @license MIT/X11 -- @license MIT/X11
local lg = require((...):gsub('plugins.bump', 'graphics')) local lg = require((...):gsub("plugins.bump", "graphics"))
return { return {
bump_LICENSE = "MIT/X11", bump_LICENSE = "MIT/X11",
bump_URL = "https://github.com/karai17/Simple-Tiled-Implementation", bump_URL = "https://github.com/karai17/Simple-Tiled-Implementation",
bump_VERSION = "3.1.7.1", bump_VERSION = "3.1.7.1",
bump_DESCRIPTION = "Bump hooks for STI.", bump_DESCRIPTION = "Bump hooks for STI.",
--- Adds each collidable tile to the Bump world. --- Adds each collidable tile to the Bump world.
-- @param world The Bump world to add objects to. -- @param world The Bump world to add objects to.
@ -29,15 +29,14 @@ return {
for _, object in ipairs(tile.objectGroup.objects) do for _, object in ipairs(tile.objectGroup.objects) do
if object.properties.collidable == true then if object.properties.collidable == true then
local t = { local t = {
name = object.name, name = object.name,
type = object.type, type = object.type,
x = instance.x + map.offsetx + object.x, x = instance.x + map.offsetx + object.x,
y = instance.y + map.offsety + object.y, y = instance.y + map.offsety + object.y,
width = object.width, width = object.width,
height = object.height, height = object.height,
layer = instance.layer, layer = instance.layer,
properties = object.properties properties = object.properties,
} }
world:add(t, t.x, t.y, t.width, t.height) world:add(t, t.x, t.y, t.width, t.height)
@ -49,13 +48,13 @@ return {
-- Every instance of a tile -- Every instance of a tile
if tile.properties and tile.properties.collidable == true then if tile.properties and tile.properties.collidable == true then
local t = { local t = {
x = instance.x + map.offsetx, x = instance.x + map.offsetx,
y = instance.y + map.offsety, y = instance.y + map.offsety,
width = map.tilewidth, width = map.tilewidth,
height = map.tileheight, height = map.tileheight,
layer = instance.layer, layer = instance.layer,
type = tile.type, type = tile.type,
properties = tile.properties properties = tile.properties,
} }
world:add(t, t.x, t.y, t.width, t.height) world:add(t, t.x, t.y, t.width, t.height)
@ -72,19 +71,18 @@ return {
if layer.type == "tilelayer" then if layer.type == "tilelayer" then
for y, tiles in ipairs(layer.data) do for y, tiles in ipairs(layer.data) do
for x, tile in pairs(tiles) do for x, tile in pairs(tiles) do
if tile.objectGroup then if tile.objectGroup then
for _, object in ipairs(tile.objectGroup.objects) do for _, object in ipairs(tile.objectGroup.objects) do
if object.properties.collidable == true then if object.properties.collidable == true then
local t = { local t = {
name = object.name, name = object.name,
type = object.type, type = object.type,
x = ((x-1) * map.tilewidth + tile.offset.x + map.offsetx) + object.x, x = ((x - 1) * map.tilewidth + tile.offset.x + map.offsetx) + object.x,
y = ((y-1) * map.tileheight + tile.offset.y + map.offsety) + object.y, y = ((y - 1) * map.tileheight + tile.offset.y + map.offsety) + object.y,
width = object.width, width = object.width,
height = object.height, height = object.height,
layer = layer, layer = layer,
properties = object.properties properties = object.properties,
} }
world:add(t, t.x, t.y, t.width, t.height) world:add(t, t.x, t.y, t.width, t.height)
@ -93,15 +91,14 @@ return {
end end
end end
local t = { local t = {
x = (x-1) * map.tilewidth + tile.offset.x + map.offsetx, x = (x - 1) * map.tilewidth + tile.offset.x + map.offsetx,
y = (y-1) * map.tileheight + tile.offset.y + map.offsety, y = (y - 1) * map.tileheight + tile.offset.y + map.offsety,
width = tile.width, width = tile.width,
height = tile.height, height = tile.height,
layer = layer, layer = layer,
type = tile.type, type = tile.type,
properties = tile.properties properties = tile.properties,
} }
world:add(t, t.x, t.y, t.width, t.height) world:add(t, t.x, t.y, t.width, t.height)
@ -112,23 +109,23 @@ return {
world:add(layer, layer.x, layer.y, layer.width, layer.height) world:add(layer, layer.x, layer.y, layer.width, layer.height)
table.insert(collidables, layer) table.insert(collidables, layer)
end end
end end
-- individual collidable objects in a layer that is not "collidable" -- individual collidable objects in a layer that is not "collidable"
-- or whole collidable objects layer -- or whole collidable objects layer
if layer.type == "objectgroup" then if layer.type == "objectgroup" then
for _, obj in ipairs(layer.objects) do for _, obj in ipairs(layer.objects) do
if layer.properties.collidable == true or obj.properties.collidable == true then if layer.properties.collidable == true or obj.properties.collidable == true then
if obj.shape == "rectangle" then if obj.shape == "rectangle" then
local t = { local t = {
name = obj.name, name = obj.name,
type = obj.type, type = obj.type,
x = obj.x + map.offsetx, x = obj.x + map.offsetx,
y = obj.y + map.offsety, y = obj.y + map.offsety,
width = obj.width, width = obj.width,
height = obj.height, height = obj.height,
layer = layer, layer = layer,
properties = obj.properties properties = obj.properties,
} }
if obj.gid then if obj.gid then
@ -143,7 +140,7 @@ return {
end end
end end
map.bump_world = world map.bump_world = world
map.bump_collidables = collidables map.bump_collidables = collidables
end, end,
@ -157,11 +154,7 @@ return {
for i = #collidables, 1, -1 do for i = #collidables, 1, -1 do
local obj = collidables[i] local obj = collidables[i]
if obj.layer == layer if obj.layer == layer and (layer.properties.collidable == true or obj.properties.collidable == true) then
and (
layer.properties.collidable == true
or obj.properties.collidable == true
) then
map.bump_world:remove(obj) map.bump_world:remove(obj)
table.remove(collidables, i) table.remove(collidables, i)
end end
@ -185,7 +178,7 @@ return {
end end
lg.pop() lg.pop()
end end,
} }
--- Custom Properties in Tiled are used to tell this plugin what to do. --- Custom Properties in Tiled are used to tell this plugin what to do.

@ -3,19 +3,21 @@ local utils = {}
-- https://github.com/stevedonovan/Penlight/blob/master/lua/pl/path.lua#L286 -- https://github.com/stevedonovan/Penlight/blob/master/lua/pl/path.lua#L286
function utils.format_path(path) function utils.format_path(path)
local np_gen1,np_gen2 = '[^SEP]+SEP%.%.SEP?','SEP+%.?SEP' local np_gen1, np_gen2 = "[^SEP]+SEP%.%.SEP?", "SEP+%.?SEP"
local np_pat1, np_pat2 = np_gen1:gsub('SEP','/'), np_gen2:gsub('SEP','/') local np_pat1, np_pat2 = np_gen1:gsub("SEP", "/"), np_gen2:gsub("SEP", "/")
local k local k
repeat -- /./ -> / repeat -- /./ -> /
path,k = path:gsub(np_pat2,'/',1) path, k = path:gsub(np_pat2, "/", 1)
until k == 0 until k == 0
repeat -- A/../ -> (empty) repeat -- A/../ -> (empty)
path,k = path:gsub(np_pat1,'',1) path, k = path:gsub(np_pat1, "", 1)
until k == 0 until k == 0
if path == '' then path = '.' end if path == "" then
path = "."
end
return path return path
end end
@ -25,8 +27,12 @@ function utils.compensate(tile, tileX, tileY, tileW, tileH)
local compx = 0 local compx = 0
local compy = 0 local compy = 0
if tile.sx < 0 then compx = tileW end if tile.sx < 0 then
if tile.sy < 0 then compy = tileH end compx = tileW
end
if tile.sy < 0 then
compy = tileH
end
if tile.r > 0 then if tile.r > 0 then
tileX = tileX + tileH - compy tileX = tileX + tileH - compy
@ -51,13 +57,17 @@ end
-- We just don't know. -- We just don't know.
function utils.get_tiles(imageW, tileW, margin, spacing) function utils.get_tiles(imageW, tileW, margin, spacing)
imageW = imageW - margin imageW = imageW - margin
local n = 0 local n = 0
while imageW >= tileW do while imageW >= tileW do
imageW = imageW - tileW imageW = imageW - tileW
if n ~= 0 then imageW = imageW - spacing end if n ~= 0 then
if imageW >= 0 then n = n + 1 end imageW = imageW - spacing
end
if imageW >= 0 then
n = n + 1
end
end end
return n return n
@ -65,8 +75,8 @@ end
-- Decompress tile layer data -- Decompress tile layer data
function utils.get_decompressed_data(data) function utils.get_decompressed_data(data)
local ffi = require "ffi" local ffi = require("ffi")
local d = {} local d = {}
local decoded = ffi.cast("uint32_t*", data) local decoded = ffi.cast("uint32_t*", data)
for i = 0, data:len() / ffi.sizeof("uint32_t") do for i = 0, data:len() / ffi.sizeof("uint32_t") do
@ -79,8 +89,8 @@ end
-- Convert a Tiled ellipse object to a LOVE polygon -- Convert a Tiled ellipse object to a LOVE polygon
function utils.convert_ellipse_to_polygon(x, y, w, h, max_segments) function utils.convert_ellipse_to_polygon(x, y, w, h, max_segments)
local ceil = math.ceil local ceil = math.ceil
local cos = math.cos local cos = math.cos
local sin = math.sin local sin = math.sin
local function calc_segments(segments) local function calc_segments(segments)
local function vdist(a, b) local function vdist(a, b)
@ -95,7 +105,7 @@ function utils.convert_ellipse_to_polygon(x, y, w, h, max_segments)
segments = segments or 64 segments = segments or 64
local vertices = {} local vertices = {}
local v = { 1, 2, ceil(segments/4-1), ceil(segments/4) } local v = { 1, 2, ceil(segments / 4 - 1), ceil(segments / 4) }
local m local m
if love and love.physics then if love and love.physics then
@ -106,8 +116,8 @@ function utils.convert_ellipse_to_polygon(x, y, w, h, max_segments)
for _, i in ipairs(v) do for _, i in ipairs(v) do
local angle = (i / segments) * math.pi * 2 local angle = (i / segments) * math.pi * 2
local px = x + w / 2 + cos(angle) * w / 2 local px = x + w / 2 + cos(angle) * w / 2
local py = y + h / 2 + sin(angle) * h / 2 local py = y + h / 2 + sin(angle) * h / 2
table.insert(vertices, { x = px / m, y = py / m }) table.insert(vertices, { x = px / m, y = py / m })
end end
@ -117,7 +127,7 @@ function utils.convert_ellipse_to_polygon(x, y, w, h, max_segments)
-- Box2D threshold -- Box2D threshold
if dist1 < 0.0025 or dist2 < 0.0025 then if dist1 < 0.0025 or dist2 < 0.0025 then
return calc_segments(segments-2) return calc_segments(segments - 2)
end end
return segments return segments
@ -130,8 +140,8 @@ function utils.convert_ellipse_to_polygon(x, y, w, h, max_segments)
for i = 0, segments do for i = 0, segments do
local angle = (i / segments) * math.pi * 2 local angle = (i / segments) * math.pi * 2
local px = x + w / 2 + cos(angle) * w / 2 local px = x + w / 2 + cos(angle) * w / 2
local py = y + h / 2 + sin(angle) * h / 2 local py = y + h / 2 + sin(angle) * h / 2
table.insert(vertices, { x = px, y = py }) table.insert(vertices, { x = px, y = py })
end end
@ -141,30 +151,26 @@ end
function utils.rotate_vertex(map, vertex, x, y, cos, sin, oy) function utils.rotate_vertex(map, vertex, x, y, cos, sin, oy)
if map.orientation == "isometric" then if map.orientation == "isometric" then
x, y = utils.convert_isometric_to_screen(map, x, y) x, y = utils.convert_isometric_to_screen(map, x, y)
vertex.x, vertex.y = utils.convert_isometric_to_screen(map, vertex.x, vertex.y) vertex.x, vertex.y = utils.convert_isometric_to_screen(map, vertex.x, vertex.y)
end end
vertex.x = vertex.x - x vertex.x = vertex.x - x
vertex.y = vertex.y - y vertex.y = vertex.y - y
return return x + cos * vertex.x - sin * vertex.y, y + sin * vertex.x + cos * vertex.y - (oy or 0)
x + cos * vertex.x - sin * vertex.y,
y + sin * vertex.x + cos * vertex.y - (oy or 0)
end end
--- Project isometric position to cartesian position --- Project isometric position to cartesian position
function utils.convert_isometric_to_screen(map, x, y) function utils.convert_isometric_to_screen(map, x, y)
local mapW = map.width local mapW = map.width
local tileW = map.tilewidth local tileW = map.tilewidth
local tileH = map.tileheight local tileH = map.tileheight
local tileX = x / tileH local tileX = x / tileH
local tileY = y / tileH local tileY = y / tileH
local offsetX = mapW * tileW / 2 local offsetX = mapW * tileW / 2
return return (tileX - tileY) * tileW / 2 + offsetX, (tileX + tileY) * tileH / 2
(tileX - tileY) * tileW / 2 + offsetX,
(tileX + tileY) * tileH / 2
end end
function utils.hex_to_color(hex) function utils.hex_to_color(hex)
@ -175,16 +181,14 @@ function utils.hex_to_color(hex)
return { return {
r = tonumber(hex:sub(1, 2), 16) / 255, r = tonumber(hex:sub(1, 2), 16) / 255,
g = tonumber(hex:sub(3, 4), 16) / 255, g = tonumber(hex:sub(3, 4), 16) / 255,
b = tonumber(hex:sub(5, 6), 16) / 255 b = tonumber(hex:sub(5, 6), 16) / 255,
} }
end end
function utils.pixel_function(_, _, r, g, b, a) function utils.pixel_function(_, _, r, g, b, a)
local mask = utils._TC local mask = utils._TC
if r == mask.r and if r == mask.r and g == mask.g and b == mask.b then
g == mask.g and
b == mask.b then
return r, g, b, 0 return r, g, b, 0
end end
@ -205,7 +209,7 @@ end
function utils.deepCopy(t) function utils.deepCopy(t)
local copy = {} local copy = {}
for k,v in pairs(t) do for k, v in pairs(t) do
if type(v) == "table" then if type(v) == "table" then
v = utils.deepCopy(v) v = utils.deepCopy(v)
end end

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,10 +1,14 @@
require 'constants' require("constants")
function love.run() function love.run()
if love.load then love.load(love.arg.parseGameArguments(arg), arg) end if love.load then
love.load(love.arg.parseGameArguments(arg), arg)
end
-- We don't want the first frame's dt to include time taken by love.load. -- We don't want the first frame's dt to include time taken by love.load.
if love.timer then love.timer.step() end if love.timer then
love.timer.step()
end
local dt = 0 local dt = 0
@ -13,32 +17,40 @@ function love.run()
-- Process events. -- Process events.
if love.event then if love.event then
love.event.pump() love.event.pump()
for name, a,b,c,d,e,f in love.event.poll() do for name, a, b, c, d, e, f in love.event.poll() do
if name == "quit" then if name == "quit" then
if not love.quit or not love.quit() then if not love.quit or not love.quit() then
return a or 0 return a or 0
end end
end end
love.handlers[name](a,b,c,d,e,f) love.handlers[name](a, b, c, d, e, f)
end end
end end
-- Update dt, as we'll be passing it to update -- Update dt, as we'll be passing it to update
if love.timer then dt = love.timer.step() end if love.timer then
dt = love.timer.step()
end
-- Call update and draw -- Call update and draw
if love.update then love.update(dt) end -- will pass 0 if love.timer is disabled if love.update then
love.update(dt)
end -- will pass 0 if love.timer is disabled
if love.graphics and love.graphics.isActive() then if love.graphics and love.graphics.isActive() then
love.graphics.origin() love.graphics.origin()
love.graphics.clear(love.graphics.getBackgroundColor()) love.graphics.clear(love.graphics.getBackgroundColor())
if love.draw then love.draw() end if love.draw then
love.draw()
end
love.graphics.present() love.graphics.present()
end end
if love.timer then love.timer.sleep(0.001) end if love.timer then
love.timer.sleep(0.001)
end
end end
end end
@ -112,12 +124,11 @@ function love.load()
musicStory = love.audio.newSource("music/story.mp3", "stream") musicStory = love.audio.newSource("music/story.mp3", "stream")
musicPause = musicBattle:clone() musicPause = musicBattle:clone()
musicPause:setFilter{ musicPause:setFilter({
type = 'lowpass', type = "lowpass",
volume = 0.3, volume = 0.7,
highgain = 0.4, highgain = 0.4,
} })
end end
function love.keypressed(key) function love.keypressed(key)
@ -130,7 +141,6 @@ function love.keypressed(key)
if _G.GAMESTATE == "GAME" then if _G.GAMESTATE == "GAME" then
GameKeyPressed(key) GameKeyPressed(key)
end end
end end
function love.update(dt) function love.update(dt)
@ -162,6 +172,11 @@ function love.update(dt)
love.audio.play(musicPause) love.audio.play(musicPause)
end end
end end
if _G.GAMESTATE == "WIN" then
print(P1_WIN)
print(P2_WIN)
love.event.quit()
end
end end
function love.draw() function love.draw()
@ -179,5 +194,4 @@ function love.draw()
love.graphics.print("" .. GAMESTATE, 200, 200) love.graphics.print("" .. GAMESTATE, 200, 200)
end end
end end
end end

@ -47,79 +47,53 @@ function Player:shoot(bulletSpeed)
return newBullet return newBullet
end end
function handleKeys(dt) function Player:handleKeys(up, down, left, right, dt)
self.vx, self.vy = 0, 0 --reset every frame
if love.keyboard.isDown(up) then
self.vx = cos(self.rotation) * (self.speed * dt)
self.vy = sin(self.rotation) * (self.speed * dt)
elseif love.keyboard.isDown(down) then
self.vx = cos(self.rotation) * (self.speed * dt) * -1
self.vy = sin(self.rotation) * (self.speed * dt) * -1
elseif love.keyboard.isDown(left) then
self.rotation = self.rotation - (self.rotSpeed * dt)
elseif love.keyboard.isDown(right) then
self.rotation = self.rotation + (self.rotSpeed * dt)
end
self.collider:setLinearVelocity(self.vx, self.vy)
end
function Player:updateCol()
if self.p == 1 then
self.x = self.collider:getX()
self.y = self.collider:getY()
elseif self.p == 2 then
self.x = self.collider:getX()
self.y = self.collider:getY()
end
end end
-- Update method for the Player class -- Update method for the Player class
function Player:update(dt) function Player:update(dt)
if _G.GAMESTATE == "GAME" then local bulletSpeed = 20000
self.vx = 0
self.vy = 0 if EnableKeyPress1 == true and self.p == 1 then
local bulletSpeed = 20000 if love.keyboard.isDown("space") then
local newBullet = self:shoot(bulletSpeed)
if self.p == 1 then table.insert(Bullets1, newBullet)
-- Handle player 1 controls KeyPressTime1 = KeyDelay1
if love.keyboard.isDown("w") then EnableKeyPress1 = false
self.vx = cos(self.rotation) * (self.speed * dt) end
self.vy = sin(self.rotation) * (self.speed * dt) end
elseif love.keyboard.isDown("s") then
self.vx = cos(self.rotation) * (self.speed * dt) * -1
self.vy = sin(self.rotation) * (self.speed * dt) * -1
elseif love.keyboard.isDown("a") then
self.rotation = self.rotation - (self.rotSpeed * dt)
elseif love.keyboard.isDown("d") then
self.rotation = self.rotation + (self.rotSpeed * dt)
end
self.collider:setLinearVelocity(self.vx, self.vy)
-- Check for collision with walls
if self.collider:enter("Wall") then
print("Player 1 collided with wall")
end
if EnableKeyPress1 == true and GAMESTATE == "GAME" then
if love.keyboard.isDown("space") then
local newBullet = self:shoot(bulletSpeed)
table.insert(Bullets1, newBullet)
KeyPressTime1 = KeyDelay1
EnableKeyPress1 = false
end
end
self.x = self.collider:getX()
self.y = self.collider:getY()
elseif self.p == 2 then
-- Handle player 2 controls
if love.keyboard.isDown("up") then
self.vx = cos(self.rotation) * (self.speed * dt)
self.vy = sin(self.rotation) * (self.speed * dt)
elseif love.keyboard.isDown("down") then
self.vx = cos(self.rotation) * (self.speed * dt) * -1
self.vy = sin(self.rotation) * (self.speed * dt) * -1
elseif love.keyboard.isDown("left") then
self.rotation = self.rotation - (self.rotSpeed * dt)
elseif love.keyboard.isDown("right") then
self.rotation = self.rotation + (self.rotSpeed * dt)
end
self.collider:setLinearVelocity(self.vx, self.vy)
-- Check for collision with walls
if self.collider:enter("Wall") then
print("Player 2 collided with wall")
end
if EnableKeyPress2 == true then if EnableKeyPress2 == true and self.p == 2 then
if love.keyboard.isDown("return") then if love.keyboard.isDown("return") then
local newBullet = self:shoot(bulletSpeed) local newBullet = self:shoot(bulletSpeed)
table.insert(Bullets2, newBullet) table.insert(Bullets2, newBullet)
KeyPressTime2 = KeyDelay2 KeyPressTime2 = KeyDelay2
EnableKeyPress2 = false EnableKeyPress2 = false
end
end
end end
self.x = self.collider:getX()
self.y = self.collider:getY()
end end
end end

Loading…
Cancel
Save