Compare commits

...
51 Commits
Author SHA1 Message Date
Simon Kellet 8d756beb1b removed 2024-08-06 18:16:45 +01:00
Simon Kellet 86d33a7fc5 nearly there 2024-08-06 18:16:14 +01:00
Simon Kellet 65f4ee3473 wip 2024-08-06 17:39:14 +01:00
Simon Kellet e13114a736 power up colliders for both players 2024-08-06 17:39:09 +01:00
Simon Kellet 451d710326 escape key on pause 2024-08-02 17:27:23 +01:00
Simon Kellet 585fccf59a flips 2024-08-02 17:27:13 +01:00
Simon Kellet 3290d704e3 less prints 2024-08-02 17:27:09 +01:00
Simon Kellet 7b553d9758 formatting 2024-08-02 17:26:50 +01:00
Simon Kellet e9e3731a0b new window size 2024-08-02 17:26:43 +01:00
Simon Kellet ed9265939c scale conts 2024-08-02 17:26:35 +01:00
Simon Kellet 826ef98f19 no longer needed 2024-08-02 17:26:29 +01:00
Simon Kellet db3559b8c6 player scaling 2024-08-02 17:26:22 +01:00
Simon Kellet 88faf2538b scaling 2024-08-02 17:26:14 +01:00
Simon Kellet 7252c3cd2c scaling now works? yay? 2024-08-02 17:01:21 +01:00
Simon Kellet 7da12d3035 added mute 2024-07-31 20:37:25 +01:00
Simon Kellet ebf9369ba5 fixed game logix 2024-07-31 20:37:17 +01:00
Simon Kellet f6be8b2a16 removed btton func 2024-07-31 20:36:53 +01:00
Simon Kellet beb4c28a70 removed button func 2024-07-31 20:36:47 +01:00
Simon Kellet 2d22a50447 added mute 2024-07-31 20:36:29 +01:00
Simon Kellet d059017989 fix win 2024-07-31 20:36:20 +01:00
Simon Kellet 49a57a6e5d better bouncing finally 2024-07-31 20:36:10 +01:00
Simon Kellet f5770cd4e0 ops 2024-07-31 20:35:55 +01:00
Simon Kellet 49633072ac reset wind 2024-07-31 20:35:49 +01:00
Simon Kellet 7af90632fd added truncate method 2024-07-31 20:35:42 +01:00
Simon Kellet e47799650a added start of gui lib 2024-07-31 15:20:12 +01:00
Simon Kellet 8440be2ab1 better movement 2024-07-24 16:19:18 +01:00
Simon Kellet df4184eec4 moved stuff out of love.load 2024-07-24 15:58:44 +01:00
Simon Kellet e8a124fa63 bullet bounce count 2024-07-24 15:58:32 +01:00
Simon Kellet 78b4379143 debug keys 2024-07-24 15:58:04 +01:00
Simon Kellet b8106bc1aa deletes bullets after bouncing so many times 2024-07-24 15:57:59 +01:00
Simon Kellet f8d71bb27d moved 2024-07-24 15:57:43 +01:00
Simon Kellet 7016961609 restart doesnt stop battle music 2024-07-24 15:57:37 +01:00
Simon Kellet 95502bc429 added map 3 2024-07-24 15:57:13 +01:00
Simon Kellet f689632a92 better wall init and clearing 2024-07-22 23:30:19 +01:00
Simon Kellet da8bb7d083 removed unused music stops 2024-07-22 23:30:08 +01:00
Simon Kellet 0a25d11ac5 hitbox now circle and slower going backwards 2024-07-22 23:29:55 +01:00
Simon Kellet 71d1f6e929 changed 2024-07-22 23:29:16 +01:00
Simon Kellet a392755844 global tracker of current level 2024-07-22 23:29:09 +01:00
Simon Kellet f4d3969a1f new map for testing 2024-07-22 23:29:00 +01:00
Simon Kellet 2cd9f263e6 walls now properly get destoryed 2024-07-22 23:28:53 +01:00
Simon Kellet ff40a5507b draws score 2024-07-22 23:28:46 +01:00
Simon Kellet 26398f52b5 fixed wins 2024-07-22 23:28:36 +01:00
Simon Kellet 38826d0cd8 debug keys 2024-07-22 23:28:26 +01:00
Simon Kellet 9e968b9390 done for tonight 2024-07-21 21:24:12 +01:00
Simon Kellet cdc0f35f22 handling win states and moving stuff to be global 2024-07-21 19:48:02 +01:00
Simon Kellet e83ee4ec64 there is now a win screen 2024-07-21 19:47:41 +01:00
Simon Kellet 7b68420027 maps now clear their Wall tables before making new ones 2024-07-21 19:47:18 +01:00
Simon Kellet 5f915f617e added restarting functions 2024-07-21 19:46:59 +01:00
Simon Kellet 6049054a26 removed windows build, got it wrong lol 2024-07-21 18:08:12 +01:00
Simon Kellet 99b420cc7f format and stuff 2024-07-21 18:07:07 +01:00
Simon Kellet 53aa6d698d changes 2024-07-21 13:47:33 +01:00
41 changed files with 4697 additions and 3232 deletions
+2 -1
View File
@@ -1,2 +1,3 @@
.DS_Store .DS_Store
game.love *.love
*.exe
+19 -6
View File
@@ -6,15 +6,18 @@ end
local function drawHealth() local function drawHealth()
love.graphics.setFont(GameFont) love.graphics.setFont(GameFont)
local height = love.graphics.getHeight() local height = love.graphics.getHeight() / _G.Y_SCALE
local width = love.graphics.getWidth() local width = love.graphics.getWidth() / _G.X_SCALE
love.graphics.print("" .. UserPlayer1.health, 5, 5) love.graphics.print("P1:" .. UserPlayer1.health, 5, 5)
love.graphics.print("" .. UserPlayer2.health, width - 70, height - 95) love.graphics.print("P2:" .. UserPlayer2.health, width - 200, height - 95)
end end
function DrawGame() function DrawGame()
--STI local curWidth, curHeight = love.graphics.getDimensions()
GameMap:draw() love.graphics.scale(_G.X_SCALE, _G.Y_SCALE)
GameMap:draw(0, 0, _G.X_SCALE, _G.Y_SCALE)
GameMap:resize(curWidth / _G.X_SCALE, curHeight / _G.Y_SCALE)
-- WindField -- WindField
if DebugFlag then if DebugFlag then
@@ -22,6 +25,7 @@ function DrawGame()
drawFPS() drawFPS()
end end
-- Bullets
for _, v in ipairs(Bullets1) do for _, v in ipairs(Bullets1) do
v:draw() v:draw()
end end
@@ -29,9 +33,18 @@ function DrawGame()
v:draw() v:draw()
end end
-- PowerUps
for _, v in ipairs(PowerUps) do
v:draw()
end
UserPlayer1:draw() UserPlayer1:draw()
UserPlayer2:draw() UserPlayer2:draw()
--Draw Health --Draw Health
--TODO: make this nicer looking
drawHealth() drawHealth()
--TODO: draw running score
--drawScore()
end end
+41 -6
View File
@@ -1,11 +1,15 @@
function GameKeyPressed(key) function GameKeyPressed(key)
if key == "escape" then if key == "escape" then
musicBattle:setVolume(0) if not MUTED then
musicPause:setVolume(0.5) musicBattle:setVolume(0)
musicPause:setVolume(0.6)
else
musicBattle:setVolume(0)
musicPause:setVolume(0)
end
_G.GAMESTATE = "PAUSE" _G.GAMESTATE = "PAUSE"
print("STATE CHANEGD: PAUSED!") --print("STATE CHANEGD: PAUSED!")
_G.PAUSED = true _G.PAUSED = true
end end
@@ -13,9 +17,40 @@ function GameKeyPressed(key)
DebugFlag = not DebugFlag DebugFlag = not DebugFlag
end end
--[[
if key == "r" and not _G.PAUSED then if key == "r" and not _G.PAUSED then
RestartGame()
_G.GAMESTATE = "GAME"
love.load() love.load()
end end
]]--
if key == "m" then
_G.MUTED = not _G.MUTED
-- Need to set the battle music to mute
if _G.MUTED then
musicBattle:setVolume(0)
else
musicBattle:setVolume(0.5)
end
end
if DebugFlag and key == "1" then
--UserPlayer1.speed = 50000
--print("player1 speed increased!")
end
if DebugFlag and key == "2" then
_G.CUR_LEVEL = 2
RestartGame()
love.load()
end
if DebugFlag and key == "3" then
_G.CUR_LEVEL = 3
RestartGame()
love.load()
end
if key == "p" then
testP = PowerUp("speed", 300, 300, "assets/powerup.jpeg", 10)
table.insert(PowerUps, testP)
end
end end
+107 -15
View File
@@ -1,9 +1,32 @@
local function checkLossState()
-- Check P1's health
if UserPlayer1.health <= 0 then --P1 Lost, P2 Win
_G.P2_COUNT = _G.P2_COUNT + 1
_G.P1_WIN = false
_G.P2_WIN = true
return true
end
if UserPlayer2.health <= 0 then --P2 Lost, P1 Win
_G.P1_COUNT = _G.P1_COUNT + 1
_G.P1_WIN = true
_G.P2_WIN = false
return true
end
return false
end
local max = math.max -- optimisations
function UpdateGame(dt) function UpdateGame(dt)
--Check if anyone has won
if checkLossState() == 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,8 +36,18 @@ function UpdateGame(dt)
if KeyPressTime2 <= 0 then if KeyPressTime2 <= 0 then
EnableKeyPress2 = true EnableKeyPress2 = true
end end
-- Update Bullets1
for i, v in ipairs(Bullets1) do for i, v in ipairs(Bullets1) do
v:update(dt) v:update(dt)
-- Check bounce count
if v.bounce >= _G.BULLETS_BOUNCE_MAX then
table.remove(Bullets1, i)
v.collider:destroy()
end
-- Handle screen edges
if v.y < 0 then --top of screen if v.y < 0 then --top of screen
table.remove(Bullets1, i) table.remove(Bullets1, i)
v.collider:destroy() v.collider:destroy()
@@ -22,8 +55,20 @@ function UpdateGame(dt)
table.remove(Bullets1, i) table.remove(Bullets1, i)
v.collider:destroy() v.collider:destroy()
end end
-- Hit player2
if v.collider:enter("Player2") then if v.collider:enter("Player2") then
print("Player1 hit Player2!") --print("Player1 hit Player2!")
table.remove(Bullets1, i)
v.collider:destroy()
if UserPlayer2.health > 0 then
UserPlayer2.health = UserPlayer2.health - 1
end
end
-- Hit player1
if v.collider:enter("Player1") then
--print("Player 1 hit themselves!")
table.remove(Bullets1, i) table.remove(Bullets1, i)
v.collider:destroy() v.collider:destroy()
if UserPlayer1.health > 0 then if UserPlayer1.health > 0 then
@@ -31,18 +76,24 @@ function UpdateGame(dt)
end end
end end
if v.collider:enter("Player1") then --Hit another bullet
print("Player 1 hit themselves!") if v.collider:enter("Bullet1") then
table.remove(Bullets1, i) table.remove(Bullets1, i)
v.collider:destroy() v.collider:destroy()
if UserPlayer1.health > 0 then
UserPlayer1.health = UserPlayer1.health - 1
end
end end
end end
-- Update Bullets2
for i, v in ipairs(Bullets2) do for i, v in ipairs(Bullets2) do
v:update(dt) v:update(dt)
-- Check bounce count
if v.bounce >= _G.BULLETS_BOUNCE_MAX then
table.remove(Bullets2, i)
v.collider:destroy()
end
-- Handle screen edges
if v.y < 0 then --top of screen if v.y < 0 then --top of screen
table.remove(Bullets2, i) table.remove(Bullets2, i)
v.collider:destroy() v.collider:destroy()
@@ -51,25 +102,66 @@ function UpdateGame(dt)
v.collider:destroy() v.collider:destroy()
end end
-- Hit player1
if v.collider:enter("Player1") then if v.collider:enter("Player1") then
print("Player2 hit Player1!") --print("Player2 hit Player1!")
table.remove(Bullets2, i)
v.collider:destroy()
if UserPlayer1.health > 0 then
UserPlayer1.health = UserPlayer1.health - 1
end
end
-- Hit player2
if v.collider:enter("Player2") then
--print("Player 2 hit themselves!")
table.remove(Bullets2, i) table.remove(Bullets2, i)
v.collider:destroy() v.collider:destroy()
if UserPlayer2.health > 0 then if UserPlayer2.health > 0 then
UserPlayer2.health = UserPlayer2.health - 1 UserPlayer2.health = UserPlayer2.health - 1
end end
end end
if v.collider:enter("Player2") then
print("Player 2 hit themselves!") --Hit another bullet
if v.collider:enter("Bullet2") then
table.remove(Bullets2, i) table.remove(Bullets2, i)
v.collider:destroy() v.collider:destroy()
if UserPlayer2.health > 0 then
UserPlayer2.health = UserPlayer2.health - 1
end
end end
end end
-- PowerUp updates
for i, v in ipairs(PowerUps) do
v:update(dt)
if v.collider:enter("Player1") then
UserPlayer1:getPowerUp(v)
UserPlayer1:powerup()
table.remove(PowerUps, i)
v.collider:destroy()
end
if v.collider:enter("Player2") then
UserPlayer2:getPowerUp(v)
UserPlayer2:powerup()
table.remove(PowerUps, i)
v.collider:destroy()
end
end
--PowerUp timer to place
PUTimeToPlace = PUTimeToPlace - dt
--print(PUTimeToPlace)
if PUTimeToPlace <= 0 then
local w, h = love.graphics.getDimensions()
local ranx = love.math.random(30, w)
local rany = love.math.random(100, h)
local newPU = PowerUp("speed", ranx, rany, "assets/powerup.jpeg", 10)
table.insert(PowerUps, newPU)
PUTimeToPlace = _G.PU_TIMER --reset
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
+13 -37
View File
@@ -1,44 +1,20 @@
local function button(x,y, w, h, text, selected)
--x,y is the top left corner of the button
local rounding = 30 -- used for rounding the buttons
if not selected then
love.graphics.setColor(love.math.colorFromBytes(41,134,204))
elseif selected then
love.graphics.setColor(love.math.colorFromBytes(244,67,54))
end
-- Draw rectangle
love.graphics.rectangle("line", x, y, w, h, rounding, rounding)
-- Get width and height of text
local tw = MenuFont:getWidth(text)
local th = MenuFont:getHeight(text)
-- Calculate position to center the text
local textX = x + (w - tw) / 2
local textY = y + (h - th) / 2
-- Place text inside the rectangle
love.graphics.setFont(MenuFont)
love.graphics.print(text, textX, textY)
end
local function title() local function title()
local height = love.graphics.getHeight() local height = love.graphics.getHeight() / _G.Y_SCALE
local width = love.graphics.getWidth() local width = love.graphics.getWidth() / _G.X_SCALE
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("Tanks-A-Lot", 100, 100)
end end
function DrawMenu() function DrawMenu()
local bwidth, bheight = 300, 140 local bwidth, bheight = 300 * _G.X_SCALE, 140 * _G.Y_SCALE
title() title()
button(100, 200, bwidth, bheight, "Play", MENU_POS == 0 and true or false) GUI:newButton(100, 200, bwidth, bheight, "Play", MENU_POS == 0 and true or false)
button(100, 350, bwidth, bheight, "???", MENU_POS == 1 and true or false) GUI:newButton(100, 350, bwidth, bheight, "???", MENU_POS == 1 and true or false)
button(100, 500, bwidth, bheight, "???", MENU_POS == 2 and true or false) GUI:newButton(100, 500, bwidth, bheight, "???", MENU_POS == 2 and true or false)
button(100, 650, bwidth, bheight, "Quit", MENU_POS == 3 and true or false) GUI:newButton(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
+21 -8
View File
@@ -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 ???
@@ -7,19 +7,15 @@ function MenuKeyPressed(key)
if MENU_POS == 0 then if MENU_POS == 0 then
--Change state to GAME! --Change state to GAME!
_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
@@ -38,4 +34,21 @@ function MenuKeyPressed(key)
end end
end end
if key == "r" then
musicBattle:stop()
musicMenu:stop()
musicPause:stop()
_G.GAMESTATE = "MENU"
love.load()
end
if key == "m" then
MUTED = not MUTED
if MUTED then
musicMenu:setVolume(0)
else
musicMenu:setVolume(0.5)
end
end
end end
+1 -2
View File
@@ -1,2 +1 @@
function UpdateMenu(dt) function UpdateMenu(dt) end
end
+15 -39
View File
@@ -1,45 +1,21 @@
local function button(x,y, w, h, text, selected)
--x,y is the top left corner of the button
local rounding = 30 -- used for rounding the buttons
if not selected then
love.graphics.setColor(love.math.colorFromBytes(41,134,204))
elseif selected then
love.graphics.setColor(love.math.colorFromBytes(244,67,54))
end
-- Draw rectangle
love.graphics.rectangle("fill", x, y, w, h, rounding, rounding)
-- Get width and height of text
local tw = MenuFont:getWidth(text)
local th = MenuFont:getHeight(text)
-- Calculate position to center the text
local textX = x + (w - tw) / 2
local textY = y + (h - th) / 2
-- Place text inside the rectangle
love.graphics.setFont(MenuFont)
love.graphics.setColor(1,1,1) -- reset colours
love.graphics.print(text, textX, textY)
end
function DrawPause() function DrawPause()
local opacity = 0.3 local opacity = 0.3
local height = love.graphics.getHeight() local height = love.graphics.getHeight() / _G.Y_SCALE
local width = love.graphics.getWidth() local width = love.graphics.getWidth() / _G.X_SCALE
local bwidth, bheight = 300, 140 local bwidth, bheight = 300 * _G.X_SCALE, 140 * _G.Y_SCALE
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) GUI:newButton(100, 200, bwidth, bheight, "Back", PAUSE_POS == 0 and true or false)
button(100, 350, bwidth, bheight, "Menu", PAUSE_POS == 1 and true or false) GUI:newButton(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) GUI:newButton(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
+41 -22
View File
@@ -1,30 +1,49 @@
function PauseKeyPressed(key) function PauseKeyPressed(key)
if key == 'return' then if key == "escape" then
musicBattle:setVolume(0.5) -- quickly return to the game
musicPause:setVolume(0) if not _G.MUTED then
-- 0 Return to game
-- 1 Quit
if PAUSE_POS == 0 then
-- unpause the game
_G.GAMESTATE = "GAME"
print("STATE CHANEGD: GAME!")
_G.PAUSED = false
musicBattle:setVolume(0.5) musicBattle:setVolume(0.5)
musicPause:setVolume(0) musicPause:setVolume(0)
else
musicBattle:setVolume(0)
musicPause:setVolume(0)
end
_G.GAMESTATE = "GAME"
end
elseif PAUSE_POS == 1 then if key == "return" then
_G.GAMESTATE = "MENU" -- quickly return to the game
print("STATE CHANEGD: MENU!") if not _G.MUTED then
_G.PAUSED = false musicBattle:setVolume(0.5)
musicPause:stop() musicPause:setVolume(0)
musicBattle:stop() else
musicBattle:setVolume(0)
elseif PAUSE_POS == 2 then musicPause:setVolume(0)
end
-- 0 Return to game
-- 1 Quit
if PAUSE_POS == 0 then
-- unpause the game
_G.GAMESTATE = "GAME"
--print("STATE CHANEGD: GAME!")
_G.PAUSED = false
if not MUTED then
musicBattle:setVolume(0.5)
musicPause:setVolume(0)
else
musicBattle:setVolume(0)
musicPause:setVolume(0)
end
elseif PAUSE_POS == 1 then
_G.GAMESTATE = "MENU"
--print("STATE CHANEGD: MENU!")
_G.PAUSED = false
musicPause:stop()
musicBattle:stop()
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
View File
@@ -1,2 +1 @@
function UpdatePause(dt) function UpdatePause(dt) end
end
+39
View File
@@ -0,0 +1,39 @@
local function winner()
local width = love.graphics.getWidth() / _G.X_SCALE
local height = love.graphics.getHeight() / _G.Y_SCALE
local opacity = 0.3
local s = ""
if _G.P1_WIN then
s = "P1 Win! R - Restart"
end
if _G.P2_WIN then
s = "P2 Win! R - Restart"
end
if _G.P1_WIN or _G.P2_WIN then
-- Overlay
DrawGame() --Draw a single frame of the game
love.graphics.setColor(0.1, 0.1, 0.1, opacity) --overlay opaque img
love.graphics.rectangle("fill", 0, 0, width, height)
-- Who won text
local sw, sh = MenuFont:getWidth(s), GameFont:getHeight(s)
local centreX = width / 2
local centreY = height / 2
love.graphics.setFont(MenuFont)
love.graphics.setColor(1, 1, 1) -- white
love.graphics.print(s, centreX - sw / 2, centreY - sh / 2) -- who won
love.graphics.print(
"" .. _G.P1_COUNT .. ":" .. "" .. _G.P2_COUNT,
(centreX - sw / 2),
(centreY - sh / 2) - sh / 1.5
) -- score
end
end
function DrawWin()
winner()
love.graphics.setColor(255, 255, 255) -- reset colours
end
+1
View File
@@ -0,0 +1 @@
function UpdateWin(dt) end
+7
View File
@@ -0,0 +1,7 @@
function WinKeyPressed(key)
if key == "r" then
RestartGame()
_G.GAMESTATE = "GAME"
love.load()
end
end
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

-6
View File
@@ -1,6 +0,0 @@
#!/bin/bash
set -xe
love=/Applications/love.app/Contents/MacOS/love
cat $love ./../game.love >./tanksalot.exe
Regular → Executable
+64 -23
View File
@@ -1,7 +1,9 @@
Bullet = Object:extend() Bullet = Object:extend()
cos = math.cos local pi = math.pi
sin = math.sin --optimisation local cos = math.cos
pi = math.pi local sin = math.sin
local atan = math.atan
local deg = math.deg
function Bullet:new(x, y, p, speed, rotation) function Bullet:new(x, y, p, speed, rotation)
self.image = love.graphics.newImage("assets/bullet.png") self.image = love.graphics.newImage("assets/bullet.png")
@@ -20,9 +22,13 @@ function Bullet:new(x, y, p, speed, rotation)
self.originY = self.height / 2 self.originY = self.height / 2
self.collider = World:newCircleCollider(x, y, 10) self.collider = World:newCircleCollider(x, y, 10)
--self.collider = World:newRectangleCollider(x, y, 10, 10)
--self.collider:setType("")
self.collider:setFixedRotation(true) self.collider:setFixedRotation(true)
self.collider:setPosition(self.x, self.y) self.collider:setPosition(self.x, self.y)
self.bounce = 0 -- how many times this bullet has bounced
if self.p == 1 then if self.p == 1 then
self.collider:setCollisionClass("Bullet1") self.collider:setCollisionClass("Bullet1")
elseif self.p == 2 then elseif self.p == 2 then
@@ -31,35 +37,70 @@ function Bullet:new(x, y, p, speed, rotation)
end end
function Bullet:update(dt) function Bullet:update(dt)
--If a bullet hits a wall, make it bounce off the wall and change its rotation -- Calculate the velocity
if self.p == 1 then local dx = math.cos(self.rotation) * self.speed * dt
if self.collider:enter("Wall") then local dy = math.sin(self.rotation) * self.speed * dt
--calculate normal of the wall
--calculate the angle of reflection
local angle = (math.atan2(dx, dy))
--get normal of the wall without using getNormal()
----TODO: fix this -- Check for collisions
if self.collider:enter("Wall") then
self.bounce = self.bounce + 1
--set the new angle -- Get the collision normal
self.rotation = angle local collision_data = self.collider:getEnterCollisionData("Wall")
self.collider:setAngle(self.rotation) local contact = collision_data.contact
end local normal_x, normal_y = contact:getNormal()
dx = cos(self.rotation) * self.speed * dt
dy = sin(self.rotation) * self.speed * dt -- Debug print to verify normal values
self.collider:setLinearVelocity(dx, dy) --print("---------------------------------")
--print("Collision detected!")
--print("Normal X:", normal_x, "Normal Y:", normal_y)
--print("Initial Velocity X:", dx, "Initial Velocity Y:", dy)
--print("Initial Angle: ", self.rotation)
-- Reflect the velocity using the normal
local dot_product = dx * normal_x + dy * normal_y
dx = dx - 2 * dot_product * normal_x
dy = dy - 2 * dot_product * normal_y
--print("################################")
-- Debug print to verify reflected velocity
--print("Reflected Velocity X:", dx, "Reflected Velocity Y:", dy)
self.rotation = deg(atan(dy, dx))
-- Update the rotation based on the new velocity direction
--self.rotation = deg(atan(dy, dx))
--print("Reflected Angle (radians):", self.rotation)
--print("Reflected Angle (degrees):", self.rotation)
--print("---------------------------------")
end end
if self.p == 2 then -- Set the linear velocity of the collider
local dx = cos(self.rotation) * self.speed * dt self.collider:setLinearVelocity(dx, dy)
local dy = sin(self.rotation) * self.speed * dt
self.collider:setLinearVelocity(dx, dy)
end
-- Update position
self.x = self.collider:getX() self.x = self.collider:getX()
self.y = self.collider:getY() self.y = self.collider:getY()
end end
--[[
function Bullet:update(dt)
local normal_x, normal_y = 0, 0
local dx, dy = 0, 0
if self.p == 1 or self.p == 2 then
if self.collider:enter("Wall") then
self.collider:setLinearVelocity(dx, dy)
else
dx = cos(self.rotation) * self.speed * dt
dy = sin(self.rotation) * self.speed * dt
self.collider:setLinearVelocity(dx, dy)
end
end
-- Update position
self.x = self.collider:getX()
self.y = self.collider:getY()
end
]]
function Bullet:draw() function Bullet:draw()
for _, _ in ipairs(Bullets1) do for _, _ in ipairs(Bullets1) do
love.graphics.draw( love.graphics.draw(
View File
+5
View File
@@ -1,7 +1,12 @@
--Config file for the game --Config file for the game
function love.conf(t) function love.conf(t)
--t.window.width = 1366
--t.window.height = 768
t.window.width = 1600 t.window.width = 1600
t.window.height = 960 t.window.height = 960
t.window.title = "Tanks-A-Lot" t.window.title = "Tanks-A-Lot"
t.window.resizable = true
t.version = "11.5" t.version = "11.5"
end end
+46
View File
@@ -1,8 +1,54 @@
-- WINDOW SCALE
-- Used to scale the game up or down
-- (scales STI world map and Walls in the game! )
-- (see debug for more)
X_SCALE = 1
Y_SCALE = 1
-- TILE SCALE
-- Since this game is put together rather badly
-- the game world is 1600x960
GAME_WORLD_DIM_WIDTH = 1600
GAME_WORLD_DIM_HEIGHT = 960
--[[
* Game states:
* - MENU
* - GAME
* - PAUSE
* - WIN
]]
--
GAMESTATE = "MENU" GAMESTATE = "MENU"
-- Mute for game
MUTED = false
MENU_POS = 0 MENU_POS = 0
MENU_MAX = 3 --0 play, 1 ?, 2 ?, 3 quit 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
BULLETS_MAX = 10 -- MAX amount of bullets a player can shoot
BULLETS_BOUNCE_MAX = 10 -- MAX amount of bounces before exploding!
BULLETS_LIFETIME = 50 --TODO: impl. lifetime for a bullet!
-- Power up timer
PU_TIMER = 10
-- WIN flags for P1 and P2
P1_WIN = false
P2_WIN = false
-- Default speeds for bullets and player
DEFAULT_P_SPEED = 12000
DEFAULT_B_SPEED = 22000
-- WIN counts!
P1_COUNT = 0
P2_COUNT = 0
-- Current Level
CUR_LEVEL = 1
BIN
View File
Binary file not shown.
+43
View File
@@ -0,0 +1,43 @@
GUI = Object:extend()
function GUI:new() end
function GUI:newButton(x, y, w, h, text, selected)
love.graphics.setColor(255, 255, 255) -- reset colours
--x,y is the top left corner of the button
local rounding = 30 -- used for rounding the buttons
local xoff = x + 10
local yoff = y - 10
local textX, textY = 0, 0
-- Get width and height of text
local tw = MenuFont:getWidth(text)
local th = MenuFont:getHeight(text)
love.graphics.setFont(MenuFont)
if not selected then
love.graphics.setColor(love.math.colorFromBytes(41, 134, 204))
love.graphics.rectangle("fill", x, y, w, h, rounding, rounding)
-- Calculate position to center the text
textX = x + (w - tw) / 2
textY = y + (h - th) / 2
-- Place text inside the rectangle
love.graphics.setColor(0, 0, 0)
love.graphics.print(text, textX, textY)
elseif selected then
-- If selected, raise the button and draw a shadow
love.graphics.setColor(love.math.colorFromBytes(0, 0, 0))
love.graphics.rectangle("fill", x, y, w, h, rounding, rounding) -- shadow
love.graphics.setColor(love.math.colorFromBytes(244, 67, 54))
love.graphics.rectangle("fill", xoff, yoff, w, h, rounding, rounding) -- button offset
-- Calculate position to center the text
textX = xoff + (w - tw) / 2
textY = yoff + (h - th) / 2
-- Place text inside the rectangle
love.graphics.setColor(1, 1, 1)
love.graphics.print(text, textX, textY)
end
end
+30 -39
View File
@@ -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
-193
View File
@@ -1,193 +0,0 @@
local clock = os.clock
--- Simple profiler written in Lua.
-- @module profile
-- @alias profile
local profile = {}
-- function labels
local _labeled = {}
-- function definitions
local _defined = {}
-- time of last call
local _tcalled = {}
-- total execution time
local _telapsed = {}
-- number of calls
local _ncalls = {}
-- list of internal profiler functions
local _internal = {}
--- This is an internal function.
-- @tparam string event Event type
-- @tparam number line Line number
-- @tparam[opt] table info Debug info table
function profile.hooker(event, line, info)
info = info or debug.getinfo(2, 'fnS')
local f = info.func
-- ignore the profiler itself
if _internal[f] or info.what ~= "Lua" then
return
end
-- get the function name if available
if info.name then
_labeled[f] = info.name
end
-- find the line definition
if not _defined[f] then
_defined[f] = info.short_src..":"..info.linedefined
_ncalls[f] = 0
_telapsed[f] = 0
end
if _tcalled[f] then
local dt = clock() - _tcalled[f]
_telapsed[f] = _telapsed[f] + dt
_tcalled[f] = nil
end
if event == "tail call" then
local prev = debug.getinfo(3, 'fnS')
profile.hooker("return", line, prev)
profile.hooker("call", line, info)
elseif event == 'call' then
_tcalled[f] = clock()
else
_ncalls[f] = _ncalls[f] + 1
end
end
--- Sets a clock function to be used by the profiler.
-- @tparam function func Clock function that returns a number
function profile.setclock(f)
assert(type(f) == "function", "clock must be a function")
clock = f
end
--- Starts collecting data.
function profile.start()
if rawget(_G, 'jit') then
jit.off()
jit.flush()
end
debug.sethook(profile.hooker, "cr")
end
--- Stops collecting data.
function profile.stop()
debug.sethook()
for f in pairs(_tcalled) do
local dt = clock() - _tcalled[f]
_telapsed[f] = _telapsed[f] + dt
_tcalled[f] = nil
end
-- merge closures
local lookup = {}
for f, d in pairs(_defined) do
local id = (_labeled[f] or '?')..d
local f2 = lookup[id]
if f2 then
_ncalls[f2] = _ncalls[f2] + (_ncalls[f] or 0)
_telapsed[f2] = _telapsed[f2] + (_telapsed[f] or 0)
_defined[f], _labeled[f] = nil, nil
_ncalls[f], _telapsed[f] = nil, nil
else
lookup[id] = f
end
end
collectgarbage('collect')
end
--- Resets all collected data.
function profile.reset()
for f in pairs(_ncalls) do
_ncalls[f] = 0
end
for f in pairs(_telapsed) do
_telapsed[f] = 0
end
for f in pairs(_tcalled) do
_tcalled[f] = nil
end
collectgarbage('collect')
end
--- This is an internal function.
-- @tparam function a First function
-- @tparam function b Second function
-- @treturn boolean True if "a" should rank higher than "b"
function profile.comp(a, b)
local dt = _telapsed[b] - _telapsed[a]
if dt == 0 then
return _ncalls[b] < _ncalls[a]
end
return dt < 0
end
--- Generates a report of functions that have been called since the profile was started.
-- Returns the report as a numeric table of rows containing the rank, function label, number of calls, total execution time and source code line number.
-- @tparam[opt] number limit Maximum number of rows
-- @treturn table Table of rows
function profile.query(limit)
local t = {}
for f, n in pairs(_ncalls) do
if n > 0 then
t[#t + 1] = f
end
end
table.sort(t, profile.comp)
if limit then
while #t > limit do
table.remove(t)
end
end
for i, f in ipairs(t) do
local dt = 0
if _tcalled[f] then
dt = clock() - _tcalled[f]
end
t[i] = { i, _labeled[f] or '?', _ncalls[f], _telapsed[f] + dt, _defined[f] }
end
return t
end
local cols = { 3, 29, 11, 24, 32 }
--- Generates a text report of functions that have been called since the profile was started.
-- Returns the report as a string that can be printed to the console.
-- @tparam[opt] number limit Maximum number of rows
-- @treturn string Text-based profiling report
function profile.report(n)
local out = {}
local report = profile.query(n)
for i, row in ipairs(report) do
for j = 1, 5 do
local s = row[j]
local l2 = cols[j]
s = tostring(s)
local l1 = s:len()
if l1 < l2 then
s = s..(' '):rep(l2-l1)
elseif l1 > l2 then
s = s:sub(l1 - l2 + 1, l1)
end
row[j] = s
end
out[i] = table.concat(row, ' | ')
end
local row = " +-----+-------------------------------+-------------+--------------------------+----------------------------------+ \n"
local col = " | # | Function | Calls | Time | Code | \n"
local sz = row..col..row
if #out > 0 then
sz = sz..' | '..table.concat(out, ' | \n | ')..' | \n'
end
return '\n'..sz..row
end
-- store all internal profiler functions
for _, v in pairs(profile) do
if type(v) == "function" then
_internal[v] = true
end
end
return profile
+147 -118
View File
@@ -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)
return { x = x, y = y, w = w, h = h }
end
local function Node(x, y, w, h) local function nextpow2(n)
return {x = x, y = y, w = w, h = h} local res = 1
end while res <= n do
res = res * 2
end
return res
end
local function nextpow2( n ) local function loadImgs()
local res = 1 local images = {}
while res <= n do for i = 1, #files do
res = res * 2 images[i] = {}
end --images[i].name = files[i]
return res if ids then
end images[i].id = ids[i]
end
images[i].img = love.graphics.newImage(files[i])
images[i].w = images[i].img:getWidth()
images[i].h = images[i].img:getHeight()
images[i].area = images[i].w * images[i].h
end
if sort == "size" or sort == "id" then
table.sort(images, function(a, b)
return (a.area > b.area)
end)
end
return images
end
local function loadImgs() --TODO: understand this func
local images = {} local function add(root, id, w, h)
for i = 1, #files do if root.left or root.right then
images[i] = {} if root.left then
--images[i].name = files[i] local node = add(root.left, id, w, h)
if ids then images[i].id = ids[i] end if node then
images[i].img = love.graphics.newImage( files[i] ) return node
images[i].w = images[i].img:getWidth() end
images[i].h = images[i].img:getHeight() end
images[i].area = images[i].w * images[i].h if root.right then
end local node = add(root.right, id, w, h)
if sort == "size" or sort == "id" then if node then
table.sort( images, function( a, b ) return ( a.area > b.area ) end ) return node
end end
return images end
end return nil
end
--TODO: understand this func if w > root.w or h > root.h then
local function add(root, id, w, h) return nil
if root.left or root.right then end
if root.left then
local node = add(root.left, id, w, h)
if node then return node end
end
if root.right then
local node = add(root.right, id, w, h)
if node then return node end
end
return nil
end
if w > root.w or h > root.h then return nil end local _w, _h = root.w - w, root.h - h
local _w, _h = root.w - w, root.h - h if _w <= _h then
root.left = Node(root.x + w, root.y, _w, h)
root.right = Node(root.x, root.y + h, root.w, _h)
else
root.left = Node(root.x, root.y + h, w, _h)
root.right = Node(root.x + w, root.y, _w, root.h)
end
if _w <= _h then root.w = w
root.left = Node(root.x + w, root.y, _w, h) root.h = h
root.right = Node(root.x, root.y + h, root.w, _h) root.id = id
else
root.left = Node(root.x, root.y + h, w, _h)
root.right = Node(root.x + w, root.y, _w, root.h)
end
root.w = w return root
root.h = h end
root.id = id
return root local function unmap(root)
end if not root then
return {}
end
local function unmap(root) local tree = {}
if not root then return {} end if root.id then
tree[root.id] = {}
tree[root.id].x, tree[root.id].y = root.x, root.y
end
local tree = {} local left = unmap(root.left)
if root.id then local right = unmap(root.right)
tree[root.id] = {}
tree[root.id].x, tree[root.id].y = root.x, root.y
end
local left = unmap(root.left) for k, v in pairs(left) do
local right = unmap(root.right) tree[k] = {}
tree[k].x, tree[k].y = v.x, v.y
end
for k, v in pairs(right) do
tree[k] = {}
tree[k].x, tree[k].y = v.x, v.y
end
for k, v in pairs(left) do return tree
tree[k] = {} end
tree[k].x, tree[k].y = v.x, v.y
end
for k, v in pairs(right) do
tree[k] = {}
tree[k].x, tree[k].y = v.x, v.y
end
return tree local function bake()
end local images = loadImgs()
local function bake() local root = {}
local images = loadImgs() local w, h = images[1].w, images[1].h
local root = {} if pow2 then
local w, h = images[1].w, images[1].h if w % 1 == 0 then
w = nextpow2(w)
end
if h % 1 == 0 then
h = nextpow2(h)
end
end
if pow2 then repeat
if w % 1 == 0 then w = nextpow2(w) end local node
if h % 1 == 0 then h = nextpow2(h) end
end
repeat root = Node(0, 0, w, h)
local node
root = Node(0, 0, w, h) for i = 1, #images do
node = add(root, i, images[i].w, images[i].h)
if not node then
break
end
end
for i = 1, #images do if not node then
node = add(root, i, images[i].w, images[i].h) if h <= w then
if not node then break end if pow2 then
end h = h * 2
else
h = h + 1
end
else
if pow2 then
w = w * 2
else
w = w + 1
end
end
else
break
end
until false
if not node then local limits = love.graphics.getSystemLimits()
if h <= w then if w > limits.texturesize or h > limits.texturesize then
if pow2 then h = h * 2 else h = h + 1 end return "Resulting texture is too large for this system"
else end
if pow2 then w = w * 2 else w = w + 1 end
end
else
break
end
until false
local limits = love.graphics.getSystemLimits() local coords = unmap(root)
if w > limits.texturesize or h > limits.texturesize then local map = love.graphics.newCanvas(w, h)
return "Resulting texture is too large for this system" love.graphics.setCanvas(map)
end -- love.graphics.clear()
local coords = unmap(root) for i = 1, #images do
local map = love.graphics.newCanvas(w, h) love.graphics.draw(images[i].img, coords[i].x, coords[i].y)
love.graphics.setCanvas( map ) if ids then
-- love.graphics.clear() coords[i].id = images[i].id
end
end
love.graphics.setCanvas()
for i = 1, #images do if sort == "ids" then
love.graphics.draw(images[i].img, coords[i].x, coords[i].y) table.sort(coords, function(a, b)
if ids then coords[i].id = images[i].id end return (a.id < b.id)
end end)
love.graphics.setCanvas() end
if sort == "ids" then return { image = map, coords = coords }
table.sort( coords, function( a, b ) return ( a.id < b.id ) end ) end
end
return { image = map, coords = coords } return bake()
end
return bake()
end end
return module return module
+1 -1
View File
@@ -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(...)
+286 -310
View File
@@ -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,
offset = tileset.tileoffset,
}
-- Be aware that in collections self.tiles can be a sparse array -- Be aware that in collections self.tiles can be a sparse array
self.tiles[tile.gid] = tile self.tiles[tile.gid] = tile
end end
return gid + #tileset.tiles 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
+57 -57
View File
@@ -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.
+48 -55
View File
@@ -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.
+41 -37
View File
@@ -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
+899 -692
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+116 -83
View File
@@ -1,10 +1,69 @@
require 'constants' Object = require("libs/classic")
require("constants")
WF = require("libs/windfield")
STI = require("libs/sti")
World = WF.newWorld(0, 0) --no gravity
--World:setQueryDebugDrawing(true) -- Draws the area of a query for 10 frames
World:addCollisionClass("Player1")
World:addCollisionClass("Bullet1")
World:addCollisionClass("Player2")
World:addCollisionClass("Bullet2")
World:addCollisionClass("Wall")
World:addCollisionClass("PowerUp")
require("gui")
require("powerups/powerup")
require("powerups/speed")
require("restart")
require("truncate")
require("player")
require("bullet")
require("mapsloader")
require("Game/UpdateGame")
require("Menu/UpdateMenu")
require("Pause/UpdatePause")
require("Win/UpdateWin")
require("Game/DrawGame")
require("Menu/DrawMenu")
require("Pause/DrawPause")
require("Win/DrawWin")
require("Game/GameKeyPressed")
require("Menu/MenuKeyPressed")
require("Pause/PauseKeyPressed")
require("Win/WinKeyPressed")
--Fonts used in the game
GameFont = love.graphics.newFont("assets/Daydream.ttf", 60)
DebugFont = love.graphics.newFont("assets/Daydream.ttf", 12)
MenuFont = love.graphics.newFont("assets/Daydream.ttf", 45)
Walls = {}
-- Music streaming
musicMenu = love.audio.newSource("music/menu.mp3", "stream") or nil
musicBattle = love.audio.newSource("music/battle.mp3", "stream") or nil
--musicStory = love.audio.newSource("music/story.mp3", "stream") or nil
musicPause = musicBattle:clone()
musicPause:setFilter({
type = "lowpass",
volume = 0.7,
highgain = 0.4,
})
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,111 +72,83 @@ 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
function love.resized()
--TOD0: fix scaling!
end
function love.load() function love.load()
Object = require("libs/classic") -- Set a random seed
require("player") love.math.setRandomSeed(love.timer.getTime())
require("bullet") -- Figure out the X_SCALE and Y_SCALE
local curWidth, curHeight = love.graphics.getDimensions()
_G.X_SCALE = truncate(curWidth / GAME_WORLD_DIM_WIDTH, 3)
_G.Y_SCALE = truncate(curHeight / GAME_WORLD_DIM_HEIGHT, 3)
WF = require("libs/windfield") --Game values (reset after each load)
STI = require("libs/sti")
require("Game/UpdateGame")
require("Menu/UpdateMenu")
require("Pause/UpdatePause")
require("Game/DrawGame")
require("Menu/DrawMenu")
require("Pause/DrawPause")
require("Game/GameKeyPressed")
require("Menu/MenuKeyPressed")
require("Pause/PauseKeyPressed")
require("mapsloader")
--WindField
World = WF.newWorld(0, 0) --no gravity
World:setQueryDebugDrawing(true) -- Draws the area of a query for 10 frames
World:addCollisionClass("Player1")
World:addCollisionClass("Bullet1")
World:addCollisionClass("Player2")
World:addCollisionClass("Bullet2")
World:addCollisionClass("Wall")
World:addCollisionClass("New") -- Used to make sure the bullet doesn't collide with the player that shot it
--STI Map
loadMap(1)
--Fonts used in the game
GameFont = love.graphics.newFont("assets/Daydream.ttf", 60)
DebugFont = love.graphics.newFont("assets/Daydream.ttf", 12)
MenuFont = love.graphics.newFont("assets/Daydream.ttf", 45)
--Game consts
HEALTH = 3 HEALTH = 3
DELAY = 0.5 P1_DELAY = 0.5
MAX = 6 --MAX number of bullets| P2_DELAY = 0.5
--Bullet lists --Bullet lists
Bullets1 = {} Bullets1 = {}
Bullets2 = {} Bullets2 = {}
--PowerUp stuff
PowerUps = {}
PUTimeToPlace = _G.PU_TIMER
DebugFlag = false DebugFlag = false
EnableKeyPress1 = true EnableKeyPress1 = true
KeyPressTime1 = 0 KeyPressTime1 = 0
KeyDelay1 = DELAY KeyDelay1 = P1_DELAY
EnableKeyPress2 = true EnableKeyPress2 = true
KeyPressTime2 = 0 KeyPressTime2 = 0
KeyDelay2 = DELAY KeyDelay2 = P2_DELAY
local playerSpeed = 12000 --TODO: two player speeds for upgrades
UserPlayer1 = Player(1, 1000, 100, HEALTH, "assets/player1.png", playerSpeed) UserPlayer1 = Player(1, 1000, 100, HEALTH, "assets/player1.png", 12000)
UserPlayer2 = Player(2, 200, 300, HEALTH, "assets/player2.png", playerSpeed) UserPlayer2 = Player(2, 200, 300, HEALTH, "assets/player2.png", 12000)
-- Music streaming
musicMenu = love.audio.newSource("music/menu.mp3", "stream")
musicBattle = love.audio.newSource("music/battle.mp3", "stream")
musicStory = love.audio.newSource("music/story.mp3", "stream")
musicPause = musicBattle:clone()
musicPause:setFilter{
type = 'lowpass',
volume = 0.3,
highgain = 0.4,
}
--STI Map loading
LoadMap(_G.CUR_LEVEL)
end end
function love.keypressed(key) function love.keypressed(key)
@@ -130,14 +161,16 @@ function love.keypressed(key)
if _G.GAMESTATE == "GAME" then if _G.GAMESTATE == "GAME" then
GameKeyPressed(key) GameKeyPressed(key)
end end
if _G.GAMESTATE == "WIN" then
WinKeyPressed(key)
end
end end
function love.update(dt) function love.update(dt)
if _G.GAMESTATE == "MENU" then if _G.GAMESTATE == "MENU" then
UpdateMenu(dt) UpdateMenu(dt)
-- Handle music -- Handle music
if not musicMenu:isPlaying() then if not musicMenu:isPlaying() and not _G.MUTED then
musicMenu:setVolume(0.5) musicMenu:setVolume(0.5)
love.audio.play(musicMenu) love.audio.play(musicMenu)
end end
@@ -145,9 +178,9 @@ function love.update(dt)
if _G.GAMESTATE == "PAUSE" then if _G.GAMESTATE == "PAUSE" then
UpdatePause(dt) UpdatePause(dt)
-- Handle music -- Handle music
if not musicPause:isPlaying() then if not musicPause:isPlaying() and not _G.MUTED then
--musicBattle:setVolume(0) musicBattle:setVolume(0)
--musicPause:setVolume(0.5) musicPause:setVolume(0.5)
love.audio.play(musicBattle) love.audio.play(musicBattle)
love.audio.play(musicPause) love.audio.play(musicPause)
end end
@@ -155,13 +188,16 @@ function love.update(dt)
if _G.GAMESTATE == "GAME" then if _G.GAMESTATE == "GAME" then
UpdateGame(dt) UpdateGame(dt)
-- Handle music -- Handle music
if not musicBattle:isPlaying() then if not musicBattle:isPlaying() and not _G.MUTED then
--musicBattle:setVolume(0.5) musicBattle:setVolume(0.5)
--musicPause:setVolume(0) musicPause:setVolume(0)
love.audio.play(musicBattle) love.audio.play(musicBattle)
love.audio.play(musicPause) love.audio.play(musicPause)
end end
end end
if _G.GAMESTATE == "WIN" then
UpdateWin(dt)
end
end end
function love.draw() function love.draw()
@@ -173,11 +209,8 @@ function love.draw()
end end
if _G.GAMESTATE == "GAME" then if _G.GAMESTATE == "GAME" then
DrawGame() DrawGame()
if DebugFlag then
love.graphics.setFont(DebugFont)
love.graphics.print("Debug Mode", 1200, 850)
love.graphics.print("" .. GAMESTATE, 200, 200)
end
end end
if _G.GAMESTATE == "WIN" then
DrawWin()
end
end end
+290
View File
@@ -0,0 +1,290 @@
return {
version = "1.10",
luaversion = "5.1",
tiledversion = "1.11.0",
class = "",
orientation = "orthogonal",
renderorder = "right-down",
width = 25,
height = 15,
tilewidth = 64,
tileheight = 64,
nextlayerid = 4,
nextobjectid = 16,
properties = {},
tilesets = {
{
name = "floor",
firstgid = 1,
class = "",
tilewidth = 64,
tileheight = 64,
spacing = 0,
margin = 0,
columns = 9,
image = "../assets/tileset.png",
imagewidth = 576,
imageheight = 384,
objectalignment = "unspecified",
tilerendersize = "tile",
fillmode = "stretch",
tileoffset = {
x = 0,
y = 0
},
grid = {
orientation = "orthogonal",
width = 64,
height = 64
},
properties = {},
wangsets = {},
tilecount = 54,
tiles = {}
}
},
layers = {
{
type = "tilelayer",
x = 0,
y = 0,
width = 25,
height = 15,
id = 1,
name = "floor",
class = "",
visible = true,
opacity = 1,
offsetx = 0,
offsety = 0,
parallaxx = 1,
parallaxy = 1,
properties = {},
encoding = "lua",
data = {
1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3,
10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12,
10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12,
10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12,
10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12,
10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12,
10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12,
10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12,
10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12,
10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12,
10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12,
10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12,
10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12,
10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12,
19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21
}
},
{
type = "tilelayer",
x = 0,
y = 0,
width = 25,
height = 15,
id = 2,
name = "inner walls",
class = "",
visible = true,
opacity = 1,
offsetx = 0,
offsety = 0,
parallaxx = 1,
parallaxy = 1,
properties = {},
encoding = "lua",
data = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 29, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 28, 29, 29, 29, 29, 29, 30, 0, 0, 37, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 37, 38, 38, 38, 38, 38, 39, 0, 0, 46, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 46, 47, 38, 38, 38, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 37, 38, 39, 0, 0, 0, 0, 28, 29, 30, 0, 0, 0, 0, 28, 29, 30, 0, 0, 0, 0,
0, 0, 0, 0, 37, 38, 39, 0, 0, 0, 0, 37, 38, 39, 0, 0, 0, 0, 37, 38, 39, 0, 0, 0, 0,
0, 0, 0, 0, 37, 38, 39, 0, 0, 0, 0, 37, 38, 39, 0, 0, 0, 0, 37, 38, 39, 0, 0, 0, 0,
0, 0, 0, 0, 37, 38, 39, 0, 0, 0, 0, 37, 38, 39, 0, 0, 0, 0, 37, 38, 39, 0, 0, 0, 0,
0, 0, 0, 0, 46, 47, 48, 0, 0, 0, 0, 46, 47, 48, 0, 0, 0, 0, 37, 38, 39, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 29, 38, 38, 38, 29, 30, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 29, 30, 0, 0, 37, 38, 38, 38, 38, 38, 39, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 38, 39, 0, 0, 46, 47, 47, 47, 47, 47, 48, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}
},
{
type = "objectgroup",
draworder = "topdown",
id = 3,
name = "Walls",
class = "",
visible = false,
opacity = 1,
offsetx = 0,
offsety = 0,
parallaxx = 1,
parallaxy = 1,
properties = {},
objects = {
{
id = 1,
name = "",
type = "",
shape = "rectangle",
x = 128,
y = 128,
width = 448,
height = 192,
rotation = 0,
visible = true,
properties = {}
},
{
id = 2,
name = "",
type = "",
shape = "rectangle",
x = 256,
y = 320,
width = 192,
height = 320,
rotation = 0,
visible = true,
properties = {}
},
{
id = 3,
name = "",
type = "",
shape = "rectangle",
x = 704,
y = 80,
width = 192,
height = 176,
rotation = 0,
visible = true,
properties = {}
},
{
id = 4,
name = "",
type = "",
shape = "rectangle",
x = 704,
y = 320,
width = 192,
height = 320,
rotation = 0,
visible = true,
properties = {}
},
{
id = 5,
name = "",
type = "",
shape = "rectangle",
x = 704,
y = 704,
width = 192,
height = 192,
rotation = 0,
visible = true,
properties = {}
},
{
id = 6,
name = "",
type = "",
shape = "rectangle",
x = 1024,
y = 640,
width = 448,
height = 192,
rotation = 0,
visible = true,
properties = {}
},
{
id = 7,
name = "",
type = "",
shape = "rectangle",
x = 1152,
y = 320,
width = 192,
height = 320,
rotation = 0,
visible = true,
properties = {}
},
{
id = 9,
name = "",
type = "",
shape = "rectangle",
x = 0,
y = 0,
width = 1184,
height = 16,
rotation = 0,
visible = true,
properties = {}
},
{
id = 10,
name = "",
type = "",
shape = "rectangle",
x = 1184,
y = 0,
width = 416,
height = 16,
rotation = 0,
visible = true,
properties = {}
},
{
id = 11,
name = "",
type = "",
shape = "rectangle",
x = 1584,
y = 0,
width = 16,
height = 960,
rotation = 0,
visible = true,
properties = {}
},
{
id = 12,
name = "",
type = "",
shape = "rectangle",
x = 0,
y = 944,
width = 1600,
height = 16,
rotation = 0,
visible = true,
properties = {}
},
{
id = 13,
name = "",
type = "",
shape = "rectangle",
x = 0,
y = 0,
width = 16,
height = 960,
rotation = 0,
visible = true,
properties = {}
}
}
}
}
}
+61
View File
@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="25" height="15" tilewidth="64" tileheight="64" infinite="0" nextlayerid="4" nextobjectid="16">
<editorsettings>
<export target="map2.lua" format="lua"/>
</editorsettings>
<tileset firstgid="1" name="floor" tilewidth="64" tileheight="64" tilecount="54" columns="9">
<image source="../assets/tileset.png" width="576" height="384"/>
</tileset>
<layer id="1" name="floor" width="25" height="15">
<data encoding="csv">
1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,
10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,
10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,
10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,
10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,
10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,
10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,
10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,
10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,
10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,
10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,
10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,
10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,
10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,
19,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,21
</data>
</layer>
<layer id="2" name="inner walls" width="25" height="15">
<data encoding="csv">
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,28,29,30,0,0,0,0,0,0,0,0,0,0,0,
0,0,28,29,29,29,29,29,30,0,0,37,38,39,0,0,0,0,0,0,0,0,0,0,0,
0,0,37,38,38,38,38,38,39,0,0,46,47,48,0,0,0,0,0,0,0,0,0,0,0,
0,0,46,47,38,38,38,47,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,37,38,39,0,0,0,0,28,29,30,0,0,0,0,28,29,30,0,0,0,0,
0,0,0,0,37,38,39,0,0,0,0,37,38,39,0,0,0,0,37,38,39,0,0,0,0,
0,0,0,0,37,38,39,0,0,0,0,37,38,39,0,0,0,0,37,38,39,0,0,0,0,
0,0,0,0,37,38,39,0,0,0,0,37,38,39,0,0,0,0,37,38,39,0,0,0,0,
0,0,0,0,46,47,48,0,0,0,0,46,47,48,0,0,0,0,37,38,39,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,29,38,38,38,29,30,0,0,
0,0,0,0,0,0,0,0,0,0,0,28,29,30,0,0,37,38,38,38,38,38,39,0,0,
0,0,0,0,0,0,0,0,0,0,0,37,38,39,0,0,46,47,47,47,47,47,48,0,0,
0,0,0,0,0,0,0,0,0,0,0,46,47,48,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
</data>
</layer>
<objectgroup id="3" name="Walls" visible="0">
<object id="1" x="128" y="128" width="448" height="192"/>
<object id="2" x="256" y="320" width="192" height="320"/>
<object id="3" x="704" y="80" width="192" height="176"/>
<object id="4" x="704" y="320" width="192" height="320"/>
<object id="5" x="704" y="704" width="192" height="192"/>
<object id="6" x="1024" y="640" width="448" height="192"/>
<object id="7" x="1152" y="320" width="192" height="320"/>
<object id="9" x="0" y="0" width="1184" height="16"/>
<object id="10" x="1184" y="0" width="416" height="16"/>
<object id="11" x="1584" y="0" width="16" height="960"/>
<object id="12" x="0" y="944" width="1600" height="16"/>
<object id="13" x="0" y="0" width="16" height="960"/>
</objectgroup>
</map>
+368
View File
@@ -0,0 +1,368 @@
return {
version = "1.10",
luaversion = "5.1",
tiledversion = "1.11.0",
class = "",
orientation = "orthogonal",
renderorder = "right-down",
width = 25,
height = 15,
tilewidth = 64,
tileheight = 64,
nextlayerid = 4,
nextobjectid = 23,
properties = {},
tilesets = {
{
name = "tileset",
firstgid = 1,
class = "",
tilewidth = 64,
tileheight = 64,
spacing = 0,
margin = 0,
columns = 9,
image = "../assets/tileset.png",
imagewidth = 576,
imageheight = 384,
objectalignment = "unspecified",
tilerendersize = "tile",
fillmode = "stretch",
tileoffset = {
x = 0,
y = 0
},
grid = {
orientation = "orthogonal",
width = 64,
height = 64
},
properties = {},
wangsets = {},
tilecount = 54,
tiles = {}
}
},
layers = {
{
type = "tilelayer",
x = 0,
y = 0,
width = 25,
height = 15,
id = 1,
name = "floor",
class = "",
visible = true,
opacity = 1,
offsetx = 0,
offsety = 0,
parallaxx = 1,
parallaxy = 1,
properties = {},
encoding = "lua",
data = {
1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3,
10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12,
10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12,
10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12,
10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12,
10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12,
10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12,
10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12,
10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12,
10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12,
10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12,
10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12,
10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12,
10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12,
19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21
}
},
{
type = "tilelayer",
x = 0,
y = 0,
width = 25,
height = 15,
id = 2,
name = "inner walls",
class = "",
visible = true,
opacity = 1,
offsetx = 0,
offsety = 0,
parallaxx = 1,
parallaxy = 1,
properties = {},
encoding = "lua",
data = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 33, 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, 31, 0, 0, 0,
0, 42, 43, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 34, 35, 54, 40, 0, 0, 0,
0, 51, 52, 53, 0, 0, 0, 0, 0, 31, 31, 31, 0, 0, 0, 0, 0, 42, 43, 44, 54, 11, 0, 0, 0,
0, 0, 0, 0, 0, 0, 11, 11, 11, 40, 40, 40, 0, 0, 0, 0, 0, 51, 52, 53, 31, 11, 0, 0, 0,
0, 0, 0, 0, 0, 0, 32, 32, 32, 33, 34, 35, 31, 31, 0, 0, 0, 54, 54, 31, 40, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 41, 41, 41, 42, 43, 44, 40, 40, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 52, 53, 32, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 33, 34, 34, 34, 35, 0, 0, 0, 0, 41, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 42, 43, 43, 43, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, 54, 54, 0, 0, 0, 0,
0, 0, 0, 42, 43, 43, 43, 44, 0, 0, 0, 0, 0, 0, 0, 33, 34, 34, 34, 34, 35, 0, 0, 0, 0,
0, 0, 0, 51, 52, 52, 52, 53, 0, 0, 0, 0, 0, 0, 0, 42, 43, 43, 43, 43, 44, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 52, 52, 52, 52, 53, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}
},
{
type = "objectgroup",
draworder = "topdown",
id = 3,
name = "Walls",
class = "",
visible = false,
opacity = 1,
offsetx = 0,
offsety = 0,
parallaxx = 1,
parallaxy = 1,
properties = {},
objects = {
{
id = 1,
name = "",
type = "",
shape = "rectangle",
x = 0,
y = 0,
width = 1600,
height = 16,
rotation = 0,
visible = true,
properties = {}
},
{
id = 2,
name = "",
type = "",
shape = "rectangle",
x = 1584,
y = 0,
width = 16,
height = 960,
rotation = 0,
visible = true,
properties = {}
},
{
id = 3,
name = "",
type = "",
shape = "rectangle",
x = 0,
y = 944,
width = 1600,
height = 16,
rotation = 0,
visible = true,
properties = {}
},
{
id = 4,
name = "",
type = "",
shape = "rectangle",
x = 0,
y = 0,
width = 16,
height = 960,
rotation = 0,
visible = true,
properties = {}
},
{
id = 5,
name = "",
type = "",
shape = "rectangle",
x = 112,
y = 64,
width = 96,
height = 192,
rotation = 0,
visible = true,
properties = {}
},
{
id = 6,
name = "",
type = "",
shape = "rectangle",
x = 400,
y = 368,
width = 160,
height = 64,
rotation = 0,
visible = true,
properties = {}
},
{
id = 7,
name = "",
type = "",
shape = "rectangle",
x = 576,
y = 208,
width = 192,
height = 96,
rotation = 0,
visible = true,
properties = {}
},
{
id = 8,
name = "",
type = "",
shape = "rectangle",
x = 608,
y = 336,
width = 128,
height = 160,
rotation = 0,
visible = true,
properties = {}
},
{
id = 10,
name = "",
type = "",
shape = "rectangle",
x = 768,
y = 336,
width = 128,
height = 96,
rotation = 0,
visible = true,
properties = {}
},
{
id = 11,
name = "",
type = "",
shape = "rectangle",
x = 768,
y = 496,
width = 128,
height = 64,
rotation = 0,
visible = true,
properties = {}
},
{
id = 13,
name = "",
type = "",
shape = "rectangle",
x = 240,
y = 528,
width = 224,
height = 224,
rotation = 0,
visible = true,
properties = {}
},
{
id = 14,
name = "",
type = "",
shape = "rectangle",
x = 1008,
y = 656,
width = 272,
height = 144,
rotation = 0,
visible = true,
properties = {}
},
{
id = 15,
name = "",
type = "",
shape = "rectangle",
x = 1168,
y = 592,
width = 160,
height = 32,
rotation = 0,
visible = true,
properties = {}
},
{
id = 16,
name = "",
type = "",
shape = "rectangle",
x = 1120,
y = 144,
width = 128,
height = 160,
rotation = 0,
visible = true,
properties = {}
},
{
id = 17,
name = "",
type = "",
shape = "rectangle",
x = 1104,
y = 336,
width = 96,
height = 32,
rotation = 0,
visible = true,
properties = {}
},
{
id = 19,
name = "",
type = "",
shape = "rectangle",
x = 1216,
y = 336,
width = 64,
height = 96,
rotation = 0,
visible = true,
properties = {}
},
{
id = 20,
name = "",
type = "",
shape = "rectangle",
x = 1280,
y = 80,
width = 64,
height = 288,
rotation = 0,
visible = true,
properties = {}
},
{
id = 22,
name = "",
type = "",
shape = "rectangle",
x = 1344,
y = 80,
width = 64,
height = 96,
rotation = 0,
visible = true,
properties = {}
}
}
}
}
}
+67
View File
@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="25" height="15" tilewidth="64" tileheight="64" infinite="0" nextlayerid="4" nextobjectid="23">
<editorsettings>
<export target="map3.lua" format="lua"/>
</editorsettings>
<tileset firstgid="1" name="tileset" tilewidth="64" tileheight="64" tilecount="54" columns="9">
<image source="../assets/tileset.png" width="576" height="384"/>
</tileset>
<layer id="1" name="floor" width="25" height="15">
<data encoding="csv">
1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,
10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,
10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,
10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,
10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,
10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,
10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,
10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,
10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,
10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,
10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,
10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,
10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,
10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,
19,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,21
</data>
</layer>
<layer id="2" name="inner walls" width="25" height="15">
<data encoding="csv">
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,33,34,35,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,54,31,0,0,0,
0,42,43,44,0,0,0,0,0,0,0,0,0,0,0,0,0,33,34,35,54,40,0,0,0,
0,51,52,53,0,0,0,0,0,31,31,31,0,0,0,0,0,42,43,44,54,11,0,0,0,
0,0,0,0,0,0,11,11,11,40,40,40,0,0,0,0,0,51,52,53,31,11,0,0,0,
0,0,0,0,0,0,32,32,32,33,34,35,31,31,0,0,0,54,54,31,40,0,0,0,0,
0,0,0,0,0,0,41,41,41,42,43,44,40,40,0,0,0,0,0,40,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,51,52,53,32,32,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,33,34,34,34,35,0,0,0,0,41,41,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,42,43,43,43,44,0,0,0,0,0,0,0,0,0,0,54,54,54,0,0,0,0,
0,0,0,42,43,43,43,44,0,0,0,0,0,0,0,33,34,34,34,34,35,0,0,0,0,
0,0,0,51,52,52,52,53,0,0,0,0,0,0,0,42,43,43,43,43,44,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,51,52,52,52,52,53,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
</data>
</layer>
<objectgroup id="3" name="Walls" visible="0">
<object id="1" x="0" y="0" width="1600" height="16"/>
<object id="2" x="1584" y="0" width="16" height="960"/>
<object id="3" x="0" y="944" width="1600" height="16"/>
<object id="4" x="0" y="0" width="16" height="960"/>
<object id="5" x="112" y="64" width="96" height="192"/>
<object id="6" x="400" y="368" width="160" height="64"/>
<object id="7" x="576" y="208" width="192" height="96"/>
<object id="8" x="608" y="336" width="128" height="160"/>
<object id="10" x="768" y="336" width="128" height="96"/>
<object id="11" x="768" y="496" width="128" height="64"/>
<object id="13" x="240" y="528" width="224" height="224"/>
<object id="14" x="1008" y="656" width="272" height="144"/>
<object id="15" x="1168" y="592" width="160" height="32"/>
<object id="16" x="1120" y="144" width="128" height="160"/>
<object id="17" x="1104" y="336" width="96" height="32"/>
<object id="19" x="1216" y="336" width="64" height="96"/>
<object id="20" x="1280" y="80" width="64" height="288"/>
<object id="22" x="1344" y="80" width="64" height="96"/>
</objectgroup>
</map>
+3 -1
View File
@@ -1,4 +1,4 @@
function loadMap(lvl) function LoadMap(lvl)
local mapfilelocation = "maps/" local mapfilelocation = "maps/"
local extention = ".lua" local extention = ".lua"
local mapname = mapfilelocation .. "map" .. lvl .. extention local mapname = mapfilelocation .. "map" .. lvl .. extention
@@ -8,6 +8,8 @@ function loadMap(lvl)
if GameMap.layers["Walls"] then if GameMap.layers["Walls"] then
for _, obj in ipairs(GameMap.layers["Walls"].objects) do for _, obj in ipairs(GameMap.layers["Walls"].objects) do
local wall = World:newRectangleCollider(obj.x, obj.y, obj.width, obj.height) local wall = World:newRectangleCollider(obj.x, obj.y, obj.width, obj.height)
-- local wall =
-- World:newRectangleCollider(obj.x * _G.X_SCALE, obj.y * _G.Y_SCALE, obj.width * _G.X_SCALE, obj.height * _G.Y_SCALE)
wall:setType("static") wall:setType("static")
table.insert(Walls, wall) table.insert(Walls, wall)
Walls[#Walls]:setCollisionClass("Wall") Walls[#Walls]:setCollisionClass("Wall")
+94 -78
View File
@@ -1,21 +1,28 @@
Player = Object:extend() Player = Object:extend()
cos = math.cos local cos = math.cos
sin = math.sin --optimisation local sin = math.sin --optimisation
local max = math.max --optimisation
-- Constructor for the Player class -- Constructor for the Player class
function Player:new(p, x, y, health, image, speed, max) function Player:new(p, x, y, health, image, speed)
self.p = p self.p = p
self.image = love.graphics.newImage(image) self.image = love.graphics.newImage(image)
self.x = x self.x = x
self.y = y self.y = y
self.health = health self.health = health
self.speed = speed self.speed = speed
self.max = max self.bulletSpeed = _G.DEFAULT_B_SPEED
self.width = self.image:getWidth() self.width = self.image:getWidth()
self.height = self.image:getHeight() self.height = self.image:getHeight()
--Power up flag
self.PUName = ""
self.PUTime = 0
self.PUOn = false
-- Collision Stuff -- Collision Stuff
self.collider = World:newRectangleCollider(x, y, 64, 64) --self.collider = World:newRectangleCollider(x, y, 50, 62)
self.collider = World:newCircleCollider(x, y, 24 * X_SCALE)
self.collider:setFixedRotation(true) self.collider:setFixedRotation(true)
if self.p == 1 then if self.p == 1 then
@@ -26,7 +33,9 @@ function Player:new(p, x, y, health, image, speed, max)
-- Rotation Stuff -- Rotation Stuff
self.rotation = math.rad(90) self.rotation = math.rad(90)
self.rotSpeed = 2 self.rotSpeed = 3
--self.scaleX = 1 * _G.X_SCALE
--self.scaleY = 1 * _G.Y_SCALE
self.scaleX = 1 self.scaleX = 1
self.scaleY = 1 self.scaleY = 1
self.originX = self.width / 2 self.originX = self.width / 2
@@ -35,91 +44,98 @@ function Player:new(p, x, y, health, image, speed, max)
--Velocity --Velocity
self.vx = 0 self.vx = 0
self.vy = 0 self.vy = 0
-- Bullets shot
self.shot = 0
end end
-- Method to handle shooting -- Method to handle shooting
function Player:shoot(bulletSpeed) function Player:shoot(bulletSpeed)
local offsetX = cos(self.rotation) * self.width * 1.5 if self.shot <= 10 then
local offsetY = sin(self.rotation) * self.height * 1.5 self.shot = self.shot + 1
local bulletX = self.x + offsetX local offsetX = cos(self.rotation) * self.width * 1.5
local bulletY = self.y + offsetY local offsetY = sin(self.rotation) * self.height * 1.5
local newBullet = Bullet(bulletX, bulletY, self.p, bulletSpeed, self.rotation) local bulletX = self.x + offsetX
return newBullet local bulletY = self.y + offsetY
local newBullet = Bullet(bulletX, bulletY, self.p, bulletSpeed, self.rotation)
return newBullet
else
return nil
end
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)
end
if love.keyboard.isDown(down) then
self.vx = cos(self.rotation) * (self.speed / 2 * dt) * -1
self.vy = sin(self.rotation) * (self.speed / 2 * dt) * -1
end
if love.keyboard.isDown(left) then
self.rotation = self.rotation - (self.rotSpeed * dt)
end
if 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
function Player:getPowerUp(powerup)
self.PUName = powerup.name
self.PUTime = powerup.time
end
function Player:powerup()
self.PUOn = true
if self.PUName == "speed" then
--print("" .. self.PUName .. " for " .. self.PUTime)
self.speed = self.speed * 2.5
self.rotSpeed = self.rotSpeed * 1.5
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 if self.PUOn then
self.vx = 0 self.PUTime = self.PUTime - dt
self.vy = 0
local bulletSpeed = 20000
if self.p == 1 then if max(0, self.PUTime) <= 0 then
-- Handle player 1 controls -- Reset the player
if love.keyboard.isDown("w") then self.PUName = "none"
self.vx = cos(self.rotation) * (self.speed * dt) self.PUTime = 0
self.vy = sin(self.rotation) * (self.speed * dt) self.PUOn = false
elseif love.keyboard.isDown("s") then self.speed = _G.DEFAULT_P_SPEED
self.vx = cos(self.rotation) * (self.speed * dt) * -1 end
self.vy = sin(self.rotation) * (self.speed * dt) * -1 end
elseif love.keyboard.isDown("a") then if EnableKeyPress1 == true and self.p == 1 then
self.rotation = self.rotation - (self.rotSpeed * dt) if love.keyboard.isDown("space") then
elseif love.keyboard.isDown("d") then local newBullet = self:shoot(self.bulletSpeed)
self.rotation = self.rotation + (self.rotSpeed * dt) table.insert(Bullets1, newBullet)
end KeyPressTime1 = KeyDelay1
EnableKeyPress1 = false
end
end
self.collider:setLinearVelocity(self.vx, self.vy) if EnableKeyPress2 == true and self.p == 2 then
if love.keyboard.isDown("return") then
-- Check for collision with walls local newBullet = self:shoot(self.bulletSpeed)
if self.collider:enter("Wall") then table.insert(Bullets2, newBullet)
print("Player 1 collided with wall") KeyPressTime2 = KeyDelay2
end EnableKeyPress2 = false
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 love.keyboard.isDown("return") then
local newBullet = self:shoot(bulletSpeed)
table.insert(Bullets2, newBullet)
KeyPressTime2 = KeyDelay2
EnableKeyPress2 = false
end
end
end end
self.x = self.collider:getX()
self.y = self.collider:getY()
end end
end end
+70
View File
@@ -0,0 +1,70 @@
PowerUp = Object:extend()
-- PowerUp is the super class for all power-ups
-- found in the game
function PowerUp:new(name, x, y, image, time, lifetime)
self.name = name
self.x = x
self.y = y
self.image = love.graphics.newImage(image)
self.time = time
self.lifetime = lifetime
self.width = self.image:getWidth()
self.height = self.image:getHeight()
self.rotation = 1
self.scaleX = 1
self.scaleY = 1
self.originX = self.width / 2
self.originY = self.height / 2
-- Collider
self.collider = World:newRectangleCollider(x, y, 20, 20)
self.collider:setCollisionClass("PowerUp")
self.collider:setType("static")
self.collider:setPosition(self.x, self.y)
end
-- TODO: clean up colliosn on reset
-- make image draw
-- more stuff
-- see you later
function PowerUp:apply(player) end
function PowerUp:remove(player) end
function PowerUp:update(dt)
--check if the power up is past its lifetime
--spinnnnnn
self.rotation = self.rotation + 1.5 * dt
--grown and shrink
--[[
if self.scaleX >= 1.0 then
self.scaleX = self.scaleX - 0.2 * dt
elseif self.scaleX <= 1.8 then
self.scaleX = self.scaleX + 0.2 * dt
end
]]
self.x = self.collider:getX()
self.y = self.collider:getY()
end
function PowerUp:draw()
for _, _ in ipairs(PowerUps) do
love.graphics.draw(
self.image,
self.x,
self.y,
self.rotation,
self.scaleX,
self.scaleY,
self.originX,
self.originY
)
end
end
+81
View File
@@ -0,0 +1,81 @@
-- Functions to handle restarting
-- all objects
-- Used in map switching and restarting!
function ClearWalls(walls)
for i = #walls, 1, -1 do
walls[i]:destroy()
end
end
function ClearPowerUps(powerup)
for i, v in ipairs(powerup) do
v.collider:destroy()
end
end
function StopAllMusic()
-- TODO: maybe find a way
-- to find all 'streaming'
-- sounds and then stop them all!
musicBattle:stop()
musicMenu:stop()
musicPause:stop()
--musicStory:stop() -- Unused
end
function ClearPlayerCollision()
UserPlayer1.collider:destroy()
UserPlayer2.collider:destroy()
end
function ClearBullets(bullets)
for i, v in ipairs(bullets) do
v.collider:destroy()
end
end
local function setNewLevelFromRandom(count)
local level = math.random(1, count)
_G.CUR_LEVEL = level
end
local function getLevelCount()
local levelcount = 0
local suf = ".lua"
local files = love.filesystem.getDirectoryItems("maps/")
for _, file in ipairs(files) do
if string.find(file, suf) then
levelcount = levelcount + 1
--print(k .. ". " .. file) --outputs something like "1. main.lua"
end
end
return levelcount
end
function RestartGame()
setNewLevelFromRandom(getLevelCount())
--reset wins
_G.P1_WIN = false
_G.P2_WIN = false
-- Stop the music
--StopAllMusic()
-- Clear the players collision
ClearPlayerCollision()
-- Work through and delete all bullets
ClearBullets(Bullets1)
ClearBullets(Bullets2)
--Clear Walls
ClearWalls(Walls)
--ClearPowerUps
ClearPowerUps(PowerUps)
-- Done!
end
+6
View File
@@ -0,0 +1,6 @@
function truncate(number, decdigits)
number = number * (10 ^ decdigits)
number = math.floor(number)
number = number / (10 ^ decdigits)
return number
end