Develop #4
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -63,6 +63,7 @@ function bell.load(game, cam)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function bell.update(dt, game, cam)
|
function bell.update(dt, game, cam)
|
||||||
|
if game.bells_enable then
|
||||||
-- Update cam position
|
-- Update cam position
|
||||||
cam_x, cam_y = cam.gcam:getVisible()
|
cam_x, cam_y = cam.gcam:getVisible()
|
||||||
-- Ani bells
|
-- Ani bells
|
||||||
@@ -80,7 +81,6 @@ function bell.update(dt, game, cam)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- Check collisions
|
-- Check collisions
|
||||||
if game.bells_enable then
|
|
||||||
for key, bell in pairs(bells) do
|
for key, bell in pairs(bells) do
|
||||||
for key, collision in pairs(bell.collisions) do
|
for key, collision in pairs(bell.collisions) do
|
||||||
for shape, delta in pairs(HC.collisions(bell.collisions[key])) do
|
for shape, delta in pairs(HC.collisions(bell.collisions[key])) do
|
||||||
@@ -91,7 +91,6 @@ function bell.update(dt, game, cam)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
for key, bell in pairs(bells) do
|
for key, bell in pairs(bells) do
|
||||||
for key, collision in pairs(bell.collisions) do
|
for key, collision in pairs(bell.collisions) do
|
||||||
for shape, delta in pairs(HC.collisions(bell.collisions[key])) do
|
for shape, delta in pairs(HC.collisions(bell.collisions[key])) do
|
||||||
@@ -159,6 +158,7 @@ function bell.update(dt, game, cam)
|
|||||||
game.bells_enable = false
|
game.bells_enable = false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function bell.draw(game)
|
function bell.draw(game)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ function game.load()
|
|||||||
game.canvas = { x = width / 2, y= 0, width = canvas_width, height = canvas_height }
|
game.canvas = { x = width / 2, y= 0, width = canvas_width, height = canvas_height }
|
||||||
game.level = 1
|
game.level = 1
|
||||||
game.end_level = 6
|
game.end_level = 6
|
||||||
|
game.start_screen = true
|
||||||
|
|
||||||
love.window.setMode(game.window.width, game.window.height)
|
love.window.setMode(game.window.width, game.window.height)
|
||||||
|
|
||||||
@@ -18,12 +19,12 @@ function game.load()
|
|||||||
local gravity = 2
|
local gravity = 2
|
||||||
love.physics.setMeter(world_meter) -- Height earth in meters
|
love.physics.setMeter(world_meter) -- Height earth in meters
|
||||||
game.world = love.physics.newWorld(0, gravity * world_meter, true) -- Make earth
|
game.world = love.physics.newWorld(0, gravity * world_meter, true) -- Make earth
|
||||||
|
game.status = 1
|
||||||
|
|
||||||
-- Bells
|
-- Bells
|
||||||
game.bells_enable = false
|
game.bells_enable = false
|
||||||
|
|
||||||
game.music = love.audio.newSource("assets/audio/music/theme.mp3")
|
game.music = love.audio.newSource("assets/audio/music/theme_biblia.wav")
|
||||||
game:playMusic()
|
|
||||||
|
|
||||||
game.stress = false
|
game.stress = false
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,25 @@
|
|||||||
require 'assets/scripts/vendor/MessageInABottle'
|
require 'assets/scripts/vendor/MessageInABottle'
|
||||||
|
|
||||||
local messages = {}
|
local messages = {}
|
||||||
local duration = 30
|
messages.active = true
|
||||||
|
|
||||||
function messages.load()
|
function messages.load()
|
||||||
ocean = Ocean:new()
|
ocean = Ocean:new()
|
||||||
end
|
end
|
||||||
|
|
||||||
function messages.update(dt)
|
function messages.update(dt, game)
|
||||||
ocean:update(dt)
|
ocean:update(dt)
|
||||||
|
if game.status == 1 and messages.active then
|
||||||
|
messages.new_message('welcome', 10)
|
||||||
|
messages.active = false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function messages.draw()
|
function messages.draw()
|
||||||
ocean:draw()
|
ocean:draw()
|
||||||
end
|
end
|
||||||
|
|
||||||
function messages.new_message(cap)
|
function messages.new_message(cap, time)
|
||||||
local texts = {}
|
local texts = {}
|
||||||
texts.welcome = "I must make decision. I won’t leave this room until I’ve decided to kill my girlfriend or not. How has it come to this? I’ve got little time. Her life is teetering through my fingers."
|
texts.welcome = "I must make decision. I won’t leave this room until I’ve decided to kill my girlfriend or not. How has it come to this? I’ve got little time. Her life is teetering through my fingers."
|
||||||
texts.cap1preview="She’s gorgeous in this picture. My mother has given me more than I’ll ever be able to give her back. Not only did she give me the gift of life, but a reason to go on. Her lessons and strong character have made me become the man I am now. What I most want in this world is for her to be proud of me. Proud of my work and my partner. But a bitch had to screw it all up."
|
texts.cap1preview="She’s gorgeous in this picture. My mother has given me more than I’ll ever be able to give her back. Not only did she give me the gift of life, but a reason to go on. Her lessons and strong character have made me become the man I am now. What I most want in this world is for her to be proud of me. Proud of my work and my partner. But a bitch had to screw it all up."
|
||||||
@@ -25,7 +29,7 @@ function messages.new_message(cap)
|
|||||||
texts.cap4stage="I love this song. I remember now why she bought this one. It was our song. A hidden apology for me. Maybe I got too carried away. After all, she’s not religious, she’d never said grace. She hadn’t even seen how it’s done. She did what anybody would have done: sit down and start to eat. Poor one. I shouldn’t have accepted the album, her tears were more than enough. She meant no harm. But I did…and now I must kill her. I must do it before she starts telling lies about me and harms my family's reputation. I can't allow this to happen. I'm not gay. I'm not sick. I'm not using this key. I'll go out that door and I'll do her in. No more memories, I've made up my mind."
|
texts.cap4stage="I love this song. I remember now why she bought this one. It was our song. A hidden apology for me. Maybe I got too carried away. After all, she’s not religious, she’d never said grace. She hadn’t even seen how it’s done. She did what anybody would have done: sit down and start to eat. Poor one. I shouldn’t have accepted the album, her tears were more than enough. She meant no harm. But I did…and now I must kill her. I must do it before she starts telling lies about me and harms my family's reputation. I can't allow this to happen. I'm not gay. I'm not sick. I'm not using this key. I'll go out that door and I'll do her in. No more memories, I've made up my mind."
|
||||||
texts.endbad="Die, bitch."
|
texts.endbad="Die, bitch."
|
||||||
texts.endgood="My bra. It's so uncomfortable. I've always hated wearing it. It makes my breasts hurt. On our first secret anniversary he bought me an outfit. He's got me. He's always helped me grow as a person. To break ties. Like the one I'm in now. Telling my mother I'm a woman who's into other...women. And that the Lord justs wants me to be happy. I've got to be strong. 2 Corinthians 12:10 That is why, for Christ's sake, I delight in weaknesses, in insults, in hardships, in persecutions, in difficulties. For when I am weak, then I am strong uAs strong as she made me. She laughed at me in front of my friends, but to help me overcome my shyness. She said I was a nutter to help me overcome my issues, to make me realise the obsessions I’d inherited from my mother. Brute when I wasn’t tolerant with others. And I just got upset…like a moron. A part of my soul still belongs to her. Thanks my love."
|
texts.endgood="My bra. It's so uncomfortable. I've always hated wearing it. It makes my breasts hurt. On our first secret anniversary he bought me an outfit. He's got me. He's always helped me grow as a person. To break ties. Like the one I'm in now. Telling my mother I'm a woman who's into other...women. And that the Lord justs wants me to be happy. I've got to be strong. 2 Corinthians 12:10 That is why, for Christ's sake, I delight in weaknesses, in insults, in hardships, in persecutions, in difficulties. For when I am weak, then I am strong uAs strong as she made me. She laughed at me in front of my friends, but to help me overcome my shyness. She said I was a nutter to help me overcome my issues, to make me realise the obsessions I’d inherited from my mother. Brute when I wasn’t tolerant with others. And I just got upset…like a moron. A part of my soul still belongs to her. Thanks my love."
|
||||||
local bottle = TimeBottle:new(cap, texts['' .. cap], duration)
|
local bottle = TimeBottle:new(cap, texts['' .. cap], time)
|
||||||
bottle:setX(30)
|
bottle:setX(30)
|
||||||
bottle:setY(500)
|
bottle:setY(500)
|
||||||
bottle:setWidth(1220)
|
bottle:setWidth(1220)
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
local start = {}
|
||||||
|
|
||||||
|
function start.load(game)
|
||||||
|
start.img = love.graphics.newImage('assets/sprites/menu/start.jpg')
|
||||||
|
start.music = love.audio.newSource("assets/audio/music/main_theme_menu.mp3")
|
||||||
|
start.music:play()
|
||||||
|
start.status = 1
|
||||||
|
game:stopMusic()
|
||||||
|
end
|
||||||
|
|
||||||
|
function start.update(dt, game)
|
||||||
|
if game.status == start.status then
|
||||||
|
game:stopMusic()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function start.draw(game)
|
||||||
|
if game.status == start.status then
|
||||||
|
love.graphics.draw(start.img, 0, 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function start.mousepressed(game)
|
||||||
|
local mos_x, mos_y = love.mouse.getPosition()
|
||||||
|
if game.status == start.status then
|
||||||
|
if mos_x > 411 and mos_x < 578 and mos_y > 400 and mos_y < 479 then
|
||||||
|
game.status = start.status + 1
|
||||||
|
start.music:stop()
|
||||||
|
game:playMusic()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return start
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 59 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 17 KiB |
@@ -1,44 +0,0 @@
|
|||||||
local game = require '../assets/scripts/game'
|
|
||||||
local stages = require '../assets/scripts/stages'
|
|
||||||
local controls = require '../assets/scripts/controls'
|
|
||||||
local bells = require '../assets/scripts/bells'
|
|
||||||
local camera = require '../assets/scripts/camera'
|
|
||||||
local stress = require '../assets/scripts/stress'
|
|
||||||
local messages = require '../assets/scripts/messages'
|
|
||||||
|
|
||||||
-- LOAD
|
|
||||||
function love.load()
|
|
||||||
game.load()
|
|
||||||
camera.load(game)
|
|
||||||
stages.load(game, camera)
|
|
||||||
stress.load(game, camera)
|
|
||||||
bells.load(game, camera)
|
|
||||||
controls.load(game)
|
|
||||||
messages.load(game)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- UPDATE
|
|
||||||
function love.update(dt)
|
|
||||||
--require('assets/scripts/vendor/lovebird').update()
|
|
||||||
game.world:update(dt)
|
|
||||||
game.update(dt)
|
|
||||||
camera.update(game)
|
|
||||||
stages.update(dt, game, camera)
|
|
||||||
stress.update(dt, game, camera)
|
|
||||||
bells.update(dt, game, camera)
|
|
||||||
controls.update(dt, game, camera)
|
|
||||||
messages.update(dt)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- DRAW
|
|
||||||
function love.draw()
|
|
||||||
camera.gcam:draw(
|
|
||||||
function(l,t,w,h)
|
|
||||||
stages.draw()
|
|
||||||
stress.draw()
|
|
||||||
bells.draw(game)
|
|
||||||
end
|
|
||||||
)
|
|
||||||
controls.draw()
|
|
||||||
messages.draw()
|
|
||||||
end
|
|
||||||
Vendored
-456
@@ -1,456 +0,0 @@
|
|||||||
--[[
|
|
||||||
ProFi v1.3, by Luke Perkin 2012. MIT Licence http://www.opensource.org/licenses/mit-license.php.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
ProFi = require 'ProFi'
|
|
||||||
ProFi:start()
|
|
||||||
some_function()
|
|
||||||
another_function()
|
|
||||||
coroutine.resume( some_coroutine )
|
|
||||||
ProFi:stop()
|
|
||||||
ProFi:writeReport( 'MyProfilingReport.txt' )
|
|
||||||
|
|
||||||
API:
|
|
||||||
*Arguments are specified as: type/name/default.
|
|
||||||
ProFi:start( string/once/nil )
|
|
||||||
ProFi:stop()
|
|
||||||
ProFi:checkMemory( number/interval/0, string/note/'' )
|
|
||||||
ProFi:writeReport( string/filename/'ProFi.txt' )
|
|
||||||
ProFi:reset()
|
|
||||||
ProFi:setHookCount( number/hookCount/0 )
|
|
||||||
ProFi:setGetTimeMethod( function/getTimeMethod/os.clock )
|
|
||||||
ProFi:setInspect( string/methodName, number/levels/1 )
|
|
||||||
]]
|
|
||||||
|
|
||||||
-----------------------
|
|
||||||
-- Locals:
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
local ProFi = {}
|
|
||||||
local onDebugHook, sortByDurationDesc, sortByCallCount, getTime
|
|
||||||
local DEFAULT_DEBUG_HOOK_COUNT = 0
|
|
||||||
local FORMAT_HEADER_LINE = "| %-50s: %-40s: %-20s: %-12s: %-12s: %-12s|\n"
|
|
||||||
local FORMAT_OUTPUT_LINE = "| %s: %-12s: %-12s: %-12s|\n"
|
|
||||||
local FORMAT_INSPECTION_LINE = "> %s: %-12s\n"
|
|
||||||
local FORMAT_TOTALTIME_LINE = "| TOTAL TIME = %f\n"
|
|
||||||
local FORMAT_MEMORY_LINE = "| %-20s: %-16s: %-16s| %s\n"
|
|
||||||
local FORMAT_HIGH_MEMORY_LINE = "H %-20s: %-16s: %-16sH %s\n"
|
|
||||||
local FORMAT_LOW_MEMORY_LINE = "L %-20s: %-16s: %-16sL %s\n"
|
|
||||||
local FORMAT_TITLE = "%-50.50s: %-40.40s: %-20s"
|
|
||||||
local FORMAT_LINENUM = "%4i"
|
|
||||||
local FORMAT_TIME = "%04.3f"
|
|
||||||
local FORMAT_RELATIVE = "%03.2f%%"
|
|
||||||
local FORMAT_COUNT = "%7i"
|
|
||||||
local FORMAT_KBYTES = "%7i Kbytes"
|
|
||||||
local FORMAT_MBYTES = "%7.1f Mbytes"
|
|
||||||
local FORMAT_MEMORY_HEADER1 = "\n=== HIGH & LOW MEMORY USAGE ===============================\n"
|
|
||||||
local FORMAT_MEMORY_HEADER2 = "=== MEMORY USAGE ==========================================\n"
|
|
||||||
local FORMAT_BANNER = [[
|
|
||||||
###############################################################################################################
|
|
||||||
##### ProFi, a lua profiler. This profile was generated on: %s
|
|
||||||
##### ProFi is created by Luke Perkin 2012 under the MIT Licence, www.locofilm.co.uk
|
|
||||||
##### Version 1.3. Get the most recent version at this gist: https://gist.github.com/2838755
|
|
||||||
###############################################################################################################
|
|
||||||
|
|
||||||
]]
|
|
||||||
|
|
||||||
-----------------------
|
|
||||||
-- Public Methods:
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
--[[
|
|
||||||
Starts profiling any method that is called between this and ProFi:stop().
|
|
||||||
Pass the parameter 'once' to so that this methodis only run once.
|
|
||||||
Example:
|
|
||||||
ProFi:start( 'once' )
|
|
||||||
]]
|
|
||||||
function ProFi:start( param )
|
|
||||||
if param == 'once' then
|
|
||||||
if self:shouldReturn() then
|
|
||||||
return
|
|
||||||
else
|
|
||||||
self.should_run_once = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
self.has_started = true
|
|
||||||
self.has_finished = false
|
|
||||||
self:resetReports( self.reports )
|
|
||||||
self:startHooks()
|
|
||||||
self.startTime = getTime()
|
|
||||||
end
|
|
||||||
|
|
||||||
--[[
|
|
||||||
Stops profiling.
|
|
||||||
]]
|
|
||||||
function ProFi:stop()
|
|
||||||
if self:shouldReturn() then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
self.stopTime = getTime()
|
|
||||||
self:stopHooks()
|
|
||||||
self.has_finished = true
|
|
||||||
end
|
|
||||||
|
|
||||||
function ProFi:checkMemory( interval, note )
|
|
||||||
local time = getTime()
|
|
||||||
local interval = interval or 0
|
|
||||||
if self.lastCheckMemoryTime and time < self.lastCheckMemoryTime + interval then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
self.lastCheckMemoryTime = time
|
|
||||||
local memoryReport = {
|
|
||||||
['time'] = time;
|
|
||||||
['memory'] = collectgarbage('count');
|
|
||||||
['note'] = note or '';
|
|
||||||
}
|
|
||||||
table.insert( self.memoryReports, memoryReport )
|
|
||||||
self:setHighestMemoryReport( memoryReport )
|
|
||||||
self:setLowestMemoryReport( memoryReport )
|
|
||||||
end
|
|
||||||
|
|
||||||
--[[
|
|
||||||
Writes the profile report to a file.
|
|
||||||
Param: [filename:string:optional] defaults to 'ProFi.txt' if not specified.
|
|
||||||
]]
|
|
||||||
function ProFi:writeReport( filename )
|
|
||||||
if #self.reports > 0 or #self.memoryReports > 0 then
|
|
||||||
filename = filename or 'ProFi.txt'
|
|
||||||
self:sortReportsWithSortMethod( self.reports, self.sortMethod )
|
|
||||||
self:writeReportsToFilename( filename )
|
|
||||||
print( string.format("[ProFi]\t Report written to %s", filename) )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--[[
|
|
||||||
Resets any profile information stored.
|
|
||||||
]]
|
|
||||||
function ProFi:reset()
|
|
||||||
self.reports = {}
|
|
||||||
self.reportsByTitle = {}
|
|
||||||
self.memoryReports = {}
|
|
||||||
self.highestMemoryReport = nil
|
|
||||||
self.lowestMemoryReport = nil
|
|
||||||
self.has_started = false
|
|
||||||
self.has_finished = false
|
|
||||||
self.should_run_once = false
|
|
||||||
self.lastCheckMemoryTime = nil
|
|
||||||
self.hookCount = self.hookCount or DEFAULT_DEBUG_HOOK_COUNT
|
|
||||||
self.sortMethod = self.sortMethod or sortByDurationDesc
|
|
||||||
self.inspect = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
--[[
|
|
||||||
Set how often a hook is called.
|
|
||||||
See http://pgl.yoyo.org/luai/i/debug.sethook for information.
|
|
||||||
Param: [hookCount:number] if 0 ProFi counts every time a function is called.
|
|
||||||
if 2 ProFi counts every other 2 function calls.
|
|
||||||
]]
|
|
||||||
function ProFi:setHookCount( hookCount )
|
|
||||||
self.hookCount = hookCount
|
|
||||||
end
|
|
||||||
|
|
||||||
--[[
|
|
||||||
Set how the report is sorted when written to file.
|
|
||||||
Param: [sortType:string] either 'duration' or 'count'.
|
|
||||||
'duration' sorts by the time a method took to run.
|
|
||||||
'count' sorts by the number of times a method was called.
|
|
||||||
]]
|
|
||||||
function ProFi:setSortMethod( sortType )
|
|
||||||
if sortType == 'duration' then
|
|
||||||
self.sortMethod = sortByDurationDesc
|
|
||||||
elseif sortType == 'count' then
|
|
||||||
self.sortMethod = sortByCallCount
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--[[
|
|
||||||
By default the getTime method is os.clock (CPU time),
|
|
||||||
If you wish to use other time methods pass it to this function.
|
|
||||||
Param: [getTimeMethod:function]
|
|
||||||
]]
|
|
||||||
function ProFi:setGetTimeMethod( getTimeMethod )
|
|
||||||
getTime = getTimeMethod
|
|
||||||
end
|
|
||||||
|
|
||||||
--[[
|
|
||||||
Allows you to inspect a specific method.
|
|
||||||
Will write to the report a list of methods that
|
|
||||||
call this method you're inspecting, you can optionally
|
|
||||||
provide a levels parameter to traceback a number of levels.
|
|
||||||
Params: [methodName:string] the name of the method you wish to inspect.
|
|
||||||
[levels:number:optional] the amount of levels you wish to traceback, defaults to 1.
|
|
||||||
]]
|
|
||||||
function ProFi:setInspect( methodName, levels )
|
|
||||||
if self.inspect then
|
|
||||||
self.inspect.methodName = methodName
|
|
||||||
self.inspect.levels = levels or 1
|
|
||||||
else
|
|
||||||
self.inspect = {
|
|
||||||
['methodName'] = methodName;
|
|
||||||
['levels'] = levels or 1;
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-----------------------
|
|
||||||
-- Implementations methods:
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
function ProFi:shouldReturn( )
|
|
||||||
return self.should_run_once and self.has_finished
|
|
||||||
end
|
|
||||||
|
|
||||||
function ProFi:getFuncReport( funcInfo )
|
|
||||||
local title = self:getTitleFromFuncInfo( funcInfo )
|
|
||||||
local funcReport = self.reportsByTitle[ title ]
|
|
||||||
if not funcReport then
|
|
||||||
funcReport = self:createFuncReport( funcInfo )
|
|
||||||
self.reportsByTitle[ title ] = funcReport
|
|
||||||
table.insert( self.reports, funcReport )
|
|
||||||
end
|
|
||||||
return funcReport
|
|
||||||
end
|
|
||||||
|
|
||||||
function ProFi:getTitleFromFuncInfo( funcInfo )
|
|
||||||
local name = funcInfo.name or 'anonymous'
|
|
||||||
local source = funcInfo.short_src or 'C_FUNC'
|
|
||||||
local linedefined = funcInfo.linedefined or 0
|
|
||||||
linedefined = string.format( FORMAT_LINENUM, linedefined )
|
|
||||||
return string.format(FORMAT_TITLE, source, name, linedefined)
|
|
||||||
end
|
|
||||||
|
|
||||||
function ProFi:createFuncReport( funcInfo )
|
|
||||||
local name = funcInfo.name or 'anonymous'
|
|
||||||
local source = funcInfo.source or 'C Func'
|
|
||||||
local linedefined = funcInfo.linedefined or 0
|
|
||||||
local funcReport = {
|
|
||||||
['title'] = self:getTitleFromFuncInfo( funcInfo );
|
|
||||||
['count'] = 0;
|
|
||||||
['timer'] = 0;
|
|
||||||
}
|
|
||||||
return funcReport
|
|
||||||
end
|
|
||||||
|
|
||||||
function ProFi:startHooks()
|
|
||||||
debug.sethook( onDebugHook, 'cr', self.hookCount )
|
|
||||||
end
|
|
||||||
|
|
||||||
function ProFi:stopHooks()
|
|
||||||
debug.sethook()
|
|
||||||
end
|
|
||||||
|
|
||||||
function ProFi:sortReportsWithSortMethod( reports, sortMethod )
|
|
||||||
if reports then
|
|
||||||
table.sort( reports, sortMethod )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function ProFi:writeReportsToFilename( filename )
|
|
||||||
local file, err = io.open( filename, 'w' )
|
|
||||||
assert( file, err )
|
|
||||||
self:writeBannerToFile( file )
|
|
||||||
if #self.reports > 0 then
|
|
||||||
self:writeProfilingReportsToFile( self.reports, file )
|
|
||||||
end
|
|
||||||
if #self.memoryReports > 0 then
|
|
||||||
self:writeMemoryReportsToFile( self.memoryReports, file )
|
|
||||||
end
|
|
||||||
file:close()
|
|
||||||
end
|
|
||||||
|
|
||||||
function ProFi:writeProfilingReportsToFile( reports, file )
|
|
||||||
local totalTime = self.stopTime - self.startTime
|
|
||||||
local totalTimeOutput = string.format(FORMAT_TOTALTIME_LINE, totalTime)
|
|
||||||
file:write( totalTimeOutput )
|
|
||||||
local header = string.format( FORMAT_HEADER_LINE, "FILE", "FUNCTION", "LINE", "TIME", "RELATIVE", "CALLED" )
|
|
||||||
file:write( header )
|
|
||||||
for i, funcReport in ipairs( reports ) do
|
|
||||||
local timer = string.format(FORMAT_TIME, funcReport.timer)
|
|
||||||
local count = string.format(FORMAT_COUNT, funcReport.count)
|
|
||||||
local relTime = string.format(FORMAT_RELATIVE, (funcReport.timer / totalTime) * 100 )
|
|
||||||
local outputLine = string.format(FORMAT_OUTPUT_LINE, funcReport.title, timer, relTime, count )
|
|
||||||
file:write( outputLine )
|
|
||||||
if funcReport.inspections then
|
|
||||||
self:writeInpsectionsToFile( funcReport.inspections, file )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function ProFi:writeMemoryReportsToFile( reports, file )
|
|
||||||
file:write( FORMAT_MEMORY_HEADER1 )
|
|
||||||
self:writeHighestMemoryReportToFile( file )
|
|
||||||
self:writeLowestMemoryReportToFile( file )
|
|
||||||
file:write( FORMAT_MEMORY_HEADER2 )
|
|
||||||
for i, memoryReport in ipairs( reports ) do
|
|
||||||
local outputLine = self:formatMemoryReportWithFormatter( memoryReport, FORMAT_MEMORY_LINE )
|
|
||||||
file:write( outputLine )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function ProFi:writeHighestMemoryReportToFile( file )
|
|
||||||
local memoryReport = self.highestMemoryReport
|
|
||||||
local outputLine = self:formatMemoryReportWithFormatter( memoryReport, FORMAT_HIGH_MEMORY_LINE )
|
|
||||||
file:write( outputLine )
|
|
||||||
end
|
|
||||||
|
|
||||||
function ProFi:writeLowestMemoryReportToFile( file )
|
|
||||||
local memoryReport = self.lowestMemoryReport
|
|
||||||
local outputLine = self:formatMemoryReportWithFormatter( memoryReport, FORMAT_LOW_MEMORY_LINE )
|
|
||||||
file:write( outputLine )
|
|
||||||
end
|
|
||||||
|
|
||||||
function ProFi:formatMemoryReportWithFormatter( memoryReport, formatter )
|
|
||||||
local time = string.format(FORMAT_TIME, memoryReport.time)
|
|
||||||
local kbytes = string.format(FORMAT_KBYTES, memoryReport.memory)
|
|
||||||
local mbytes = string.format(FORMAT_MBYTES, memoryReport.memory/1024)
|
|
||||||
local outputLine = string.format(formatter, time, kbytes, mbytes, memoryReport.note)
|
|
||||||
return outputLine
|
|
||||||
end
|
|
||||||
|
|
||||||
function ProFi:writeBannerToFile( file )
|
|
||||||
local banner = string.format(FORMAT_BANNER, os.date())
|
|
||||||
file:write( banner )
|
|
||||||
end
|
|
||||||
|
|
||||||
function ProFi:writeInpsectionsToFile( inspections, file )
|
|
||||||
local inspectionsList = self:sortInspectionsIntoList( inspections )
|
|
||||||
file:write('\n==^ INSPECT ^======================================================================================================== COUNT ===\n')
|
|
||||||
for i, inspection in ipairs( inspectionsList ) do
|
|
||||||
local line = string.format(FORMAT_LINENUM, inspection.line)
|
|
||||||
local title = string.format(FORMAT_TITLE, inspection.source, inspection.name, line)
|
|
||||||
local count = string.format(FORMAT_COUNT, inspection.count)
|
|
||||||
local outputLine = string.format(FORMAT_INSPECTION_LINE, title, count )
|
|
||||||
file:write( outputLine )
|
|
||||||
end
|
|
||||||
file:write('===============================================================================================================================\n\n')
|
|
||||||
end
|
|
||||||
|
|
||||||
function ProFi:sortInspectionsIntoList( inspections )
|
|
||||||
local inspectionsList = {}
|
|
||||||
for k, inspection in pairs(inspections) do
|
|
||||||
inspectionsList[#inspectionsList+1] = inspection
|
|
||||||
end
|
|
||||||
table.sort( inspectionsList, sortByCallCount )
|
|
||||||
return inspectionsList
|
|
||||||
end
|
|
||||||
|
|
||||||
function ProFi:resetReports( reports )
|
|
||||||
for i, report in ipairs( reports ) do
|
|
||||||
report.timer = 0
|
|
||||||
report.count = 0
|
|
||||||
report.inspections = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function ProFi:shouldInspect( funcInfo )
|
|
||||||
return self.inspect and self.inspect.methodName == funcInfo.name
|
|
||||||
end
|
|
||||||
|
|
||||||
function ProFi:getInspectionsFromReport( funcReport )
|
|
||||||
local inspections = funcReport.inspections
|
|
||||||
if not inspections then
|
|
||||||
inspections = {}
|
|
||||||
funcReport.inspections = inspections
|
|
||||||
end
|
|
||||||
return inspections
|
|
||||||
end
|
|
||||||
|
|
||||||
function ProFi:getInspectionWithKeyFromInspections( key, inspections )
|
|
||||||
local inspection = inspections[key]
|
|
||||||
if not inspection then
|
|
||||||
inspection = {
|
|
||||||
['count'] = 0;
|
|
||||||
}
|
|
||||||
inspections[key] = inspection
|
|
||||||
end
|
|
||||||
return inspection
|
|
||||||
end
|
|
||||||
|
|
||||||
function ProFi:doInspection( inspect, funcReport )
|
|
||||||
local inspections = self:getInspectionsFromReport( funcReport )
|
|
||||||
local levels = 5 + inspect.levels
|
|
||||||
local currentLevel = 5
|
|
||||||
while currentLevel < levels do
|
|
||||||
local funcInfo = debug.getinfo( currentLevel, 'nS' )
|
|
||||||
if funcInfo then
|
|
||||||
local source = funcInfo.short_src or '[C]'
|
|
||||||
local name = funcInfo.name or 'anonymous'
|
|
||||||
local line = funcInfo.linedefined
|
|
||||||
local key = source..name..line
|
|
||||||
local inspection = self:getInspectionWithKeyFromInspections( key, inspections )
|
|
||||||
inspection.source = source
|
|
||||||
inspection.name = name
|
|
||||||
inspection.line = line
|
|
||||||
inspection.count = inspection.count + 1
|
|
||||||
currentLevel = currentLevel + 1
|
|
||||||
else
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function ProFi:onFunctionCall( funcInfo )
|
|
||||||
local funcReport = ProFi:getFuncReport( funcInfo )
|
|
||||||
funcReport.callTime = getTime()
|
|
||||||
funcReport.count = funcReport.count + 1
|
|
||||||
if self:shouldInspect( funcInfo ) then
|
|
||||||
self:doInspection( self.inspect, funcReport )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function ProFi:onFunctionReturn( funcInfo )
|
|
||||||
local funcReport = ProFi:getFuncReport( funcInfo )
|
|
||||||
if funcReport.callTime then
|
|
||||||
funcReport.timer = funcReport.timer + (getTime() - funcReport.callTime)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function ProFi:setHighestMemoryReport( memoryReport )
|
|
||||||
if not self.highestMemoryReport then
|
|
||||||
self.highestMemoryReport = memoryReport
|
|
||||||
else
|
|
||||||
if memoryReport.memory > self.highestMemoryReport.memory then
|
|
||||||
self.highestMemoryReport = memoryReport
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function ProFi:setLowestMemoryReport( memoryReport )
|
|
||||||
if not self.lowestMemoryReport then
|
|
||||||
self.lowestMemoryReport = memoryReport
|
|
||||||
else
|
|
||||||
if memoryReport.memory < self.lowestMemoryReport.memory then
|
|
||||||
self.lowestMemoryReport = memoryReport
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-----------------------
|
|
||||||
-- Local Functions:
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
getTime = os.clock
|
|
||||||
|
|
||||||
onDebugHook = function( hookType )
|
|
||||||
local funcInfo = debug.getinfo( 2, 'nS' )
|
|
||||||
if hookType == "call" then
|
|
||||||
ProFi:onFunctionCall( funcInfo )
|
|
||||||
elseif hookType == "return" then
|
|
||||||
ProFi:onFunctionReturn( funcInfo )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
sortByDurationDesc = function( a, b )
|
|
||||||
return a.timer > b.timer
|
|
||||||
end
|
|
||||||
|
|
||||||
sortByCallCount = function( a, b )
|
|
||||||
return a.count > b.count
|
|
||||||
end
|
|
||||||
|
|
||||||
-----------------------
|
|
||||||
-- Return Module:
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
ProFi:reset()
|
|
||||||
return ProFi
|
|
||||||
Vendored
-208
@@ -1,208 +0,0 @@
|
|||||||
-- gamera.lua v1.0.1
|
|
||||||
|
|
||||||
-- Copyright (c) 2012 Enrique García Cota
|
|
||||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
||||||
-- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
||||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
-- Based on YaciCode, from Julien Patte and LuaObject, from Sebastien Rocca-Serra
|
|
||||||
|
|
||||||
local gamera = {}
|
|
||||||
|
|
||||||
-- Private attributes and methods
|
|
||||||
|
|
||||||
local gameraMt = {__index = gamera}
|
|
||||||
local abs, min, max = math.abs, math.min, math.max
|
|
||||||
|
|
||||||
local function clamp(x, minX, maxX)
|
|
||||||
return x < minX and minX or (x>maxX and maxX or x)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function checkNumber(value, name)
|
|
||||||
if type(value) ~= 'number' then
|
|
||||||
error(name .. " must be a number (was: " .. tostring(value) .. ")")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function checkPositiveNumber(value, name)
|
|
||||||
if type(value) ~= 'number' or value <=0 then
|
|
||||||
error(name .. " must be a positive number (was: " .. tostring(value) ..")")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function checkAABB(l,t,w,h)
|
|
||||||
checkNumber(l, "l")
|
|
||||||
checkNumber(t, "t")
|
|
||||||
checkPositiveNumber(w, "w")
|
|
||||||
checkPositiveNumber(h, "h")
|
|
||||||
end
|
|
||||||
|
|
||||||
local function getVisibleArea(self, scale)
|
|
||||||
scale = scale or self.scale
|
|
||||||
local sin, cos = abs(self.sin), abs(self.cos)
|
|
||||||
local w,h = self.w / scale, self.h / scale
|
|
||||||
w,h = cos*w + sin*h, sin*w + cos*h
|
|
||||||
return min(w,self.ww), min(h, self.wh)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function cornerTransform(self, x,y)
|
|
||||||
local scale, sin, cos = self.scale, self.sin, self.cos
|
|
||||||
x,y = x - self.x, y - self.y
|
|
||||||
x,y = -cos*x + sin*y, -sin*x - cos*y
|
|
||||||
return self.x - (x/scale + self.l), self.y - (y/scale + self.t)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function adjustPosition(self)
|
|
||||||
local wl,wt,ww,wh = self.wl, self.wt, self.ww, self.wh
|
|
||||||
local w,h = getVisibleArea(self)
|
|
||||||
local w2,h2 = w*0.5, h*0.5
|
|
||||||
|
|
||||||
local left, right = wl + w2, wl + ww - w2
|
|
||||||
local top, bottom = wt + h2, wt + wh - h2
|
|
||||||
|
|
||||||
self.x, self.y = clamp(self.x, left, right), clamp(self.y, top, bottom)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function adjustScale(self)
|
|
||||||
local w,h,ww,wh = self.w, self.h, self.ww, self.wh
|
|
||||||
local rw,rh = getVisibleArea(self, 1) -- rotated frame: area around the window, rotated without scaling
|
|
||||||
local sx,sy = rw/ww, rh/wh -- vert/horiz scale: minimun scales that the window needs to occupy the world
|
|
||||||
local rscale = max(sx,sy)
|
|
||||||
|
|
||||||
self.scale = max(self.scale, rscale)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Public interface
|
|
||||||
|
|
||||||
function gamera.new(l,t,w,h)
|
|
||||||
|
|
||||||
local sw,sh = love.graphics.getWidth(), love.graphics.getHeight()
|
|
||||||
|
|
||||||
local cam = setmetatable({
|
|
||||||
x=0, y=0,
|
|
||||||
scale=1,
|
|
||||||
angle=0, sin=math.sin(0), cos=math.cos(0),
|
|
||||||
l=0, t=0, w=sw, h=sh, w2=sw*0.5, h2=sh*0.5
|
|
||||||
}, gameraMt)
|
|
||||||
|
|
||||||
cam:setWorld(l,t,w,h)
|
|
||||||
|
|
||||||
return cam
|
|
||||||
end
|
|
||||||
|
|
||||||
function gamera:setWorld(l,t,w,h)
|
|
||||||
checkAABB(l,t,w,h)
|
|
||||||
|
|
||||||
self.wl, self.wt, self.ww, self.wh = l,t,w,h
|
|
||||||
|
|
||||||
adjustPosition(self)
|
|
||||||
end
|
|
||||||
|
|
||||||
function gamera:setWindow(l,t,w,h)
|
|
||||||
checkAABB(l,t,w,h)
|
|
||||||
|
|
||||||
self.l, self.t, self.w, self.h, self.w2, self.h2 = l,t,w,h, w*0.5, h*0.5
|
|
||||||
|
|
||||||
adjustPosition(self)
|
|
||||||
end
|
|
||||||
|
|
||||||
function gamera:setPosition(x,y)
|
|
||||||
checkNumber(x, "x")
|
|
||||||
checkNumber(y, "y")
|
|
||||||
|
|
||||||
self.x, self.y = x,y
|
|
||||||
|
|
||||||
adjustPosition(self)
|
|
||||||
end
|
|
||||||
|
|
||||||
function gamera:setScale(scale)
|
|
||||||
checkNumber(scale, "scale")
|
|
||||||
|
|
||||||
self.scale = scale
|
|
||||||
|
|
||||||
adjustScale(self)
|
|
||||||
adjustPosition(self)
|
|
||||||
end
|
|
||||||
|
|
||||||
function gamera:setAngle(angle)
|
|
||||||
checkNumber(angle, "angle")
|
|
||||||
|
|
||||||
self.angle = angle
|
|
||||||
self.cos, self.sin = math.cos(angle), math.sin(angle)
|
|
||||||
|
|
||||||
adjustScale(self)
|
|
||||||
adjustPosition(self)
|
|
||||||
end
|
|
||||||
|
|
||||||
function gamera:getWorld()
|
|
||||||
return self.wl, self.wt, self.ww, self.wh
|
|
||||||
end
|
|
||||||
|
|
||||||
function gamera:getWindow()
|
|
||||||
return self.l, self.t, self.w, self.h
|
|
||||||
end
|
|
||||||
|
|
||||||
function gamera:getPosition()
|
|
||||||
return self.x, self.y
|
|
||||||
end
|
|
||||||
|
|
||||||
function gamera:getScale()
|
|
||||||
return self.scale
|
|
||||||
end
|
|
||||||
|
|
||||||
function gamera:getAngle()
|
|
||||||
return self.angle
|
|
||||||
end
|
|
||||||
|
|
||||||
function gamera:getVisible()
|
|
||||||
local w,h = getVisibleArea(self)
|
|
||||||
return self.x - w*0.5, self.y - h*0.5, w, h
|
|
||||||
end
|
|
||||||
|
|
||||||
function gamera:getVisibleCorners()
|
|
||||||
local x,y,w2,h2 = self.x, self.y, self.w2, self.h2
|
|
||||||
|
|
||||||
local x1,y1 = cornerTransform(self, x-w2,y-h2)
|
|
||||||
local x2,y2 = cornerTransform(self, x+w2,y-h2)
|
|
||||||
local x3,y3 = cornerTransform(self, x+w2,y+h2)
|
|
||||||
local x4,y4 = cornerTransform(self, x-w2,y+h2)
|
|
||||||
|
|
||||||
return x1,y1,x2,y2,x3,y3,x4,y4
|
|
||||||
end
|
|
||||||
|
|
||||||
function gamera:draw(f)
|
|
||||||
love.graphics.setScissor(self:getWindow())
|
|
||||||
|
|
||||||
love.graphics.push()
|
|
||||||
local scale = self.scale
|
|
||||||
love.graphics.scale(scale)
|
|
||||||
|
|
||||||
love.graphics.translate((self.w2 + self.l) / scale, (self.h2+self.t) / scale)
|
|
||||||
love.graphics.rotate(-self.angle)
|
|
||||||
love.graphics.translate(-self.x, -self.y)
|
|
||||||
|
|
||||||
f(self:getVisible())
|
|
||||||
|
|
||||||
love.graphics.pop()
|
|
||||||
|
|
||||||
love.graphics.setScissor()
|
|
||||||
end
|
|
||||||
|
|
||||||
function gamera:toWorld(x,y)
|
|
||||||
local scale, sin, cos = self.scale, self.sin, self.cos
|
|
||||||
x,y = (x - self.w2 - self.l) / scale, (y - self.h2 - self.t) / scale
|
|
||||||
x,y = cos*x - sin*y, sin*x + cos*y
|
|
||||||
return x + self.x, y + self.y
|
|
||||||
end
|
|
||||||
|
|
||||||
function gamera:toScreen(x,y)
|
|
||||||
local scale, sin, cos = self.scale, self.sin, self.cos
|
|
||||||
x,y = x - self.x, y - self.y
|
|
||||||
x,y = cos*x + sin*y, -sin*x + cos*y
|
|
||||||
return scale * x + self.w2 + self.l, scale * y + self.h2 + self.t
|
|
||||||
end
|
|
||||||
|
|
||||||
return gamera
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Vendored
-47
@@ -1,47 +0,0 @@
|
|||||||
HUMP - Helper Utilities for Massive Progression
|
|
||||||
===============================================
|
|
||||||
|
|
||||||
__HUMP__ is a small collection of tools for developing games with LÖVE.
|
|
||||||
|
|
||||||
Contents:
|
|
||||||
------------
|
|
||||||
|
|
||||||
* *gamestate.lua*: Easy gamestate management.
|
|
||||||
* *timer.lua*: Delayed and time-limited function calls and tweening functionality.
|
|
||||||
* *vector.lua*: 2D vector math.
|
|
||||||
* *vector-light.lua*: Lightweight 2D vector math (for optimisation purposes - leads to potentially ugly code).
|
|
||||||
* *class.lua*: Lightweight object orientation (class or prototype based).
|
|
||||||
* *signal.lua*: Simple Signal/Slot (aka. Observer) implementation.
|
|
||||||
* *camera.lua*: Move-, zoom- and rotatable camera.
|
|
||||||
|
|
||||||
Documentation
|
|
||||||
=============
|
|
||||||
|
|
||||||
You can find the documentation here: [http://vrld.github.com/hump/](http://vrld.github.com/hump/)
|
|
||||||
|
|
||||||
|
|
||||||
License
|
|
||||||
=======
|
|
||||||
> Copyright (c) 2010-2013 Matthias Richter
|
|
||||||
>
|
|
||||||
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
> of this software and associated documentation files (the "Software"), to deal
|
|
||||||
> in the Software without restriction, including without limitation the rights
|
|
||||||
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
> copies of the Software, and to permit persons to whom the Software is
|
|
||||||
> furnished to do so, subject to the following conditions:
|
|
||||||
>
|
|
||||||
> The above copyright notice and this permission notice shall be included in
|
|
||||||
> all copies or substantial portions of the Software.
|
|
||||||
>
|
|
||||||
> Except as contained in this notice, the name(s) of the above copyright holders
|
|
||||||
> shall not be used in advertising or otherwise to promote the sale, use or
|
|
||||||
> other dealings in this Software without prior written authorization.
|
|
||||||
>
|
|
||||||
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
> THE SOFTWARE.
|
|
||||||
Vendored
-117
@@ -1,117 +0,0 @@
|
|||||||
--[[
|
|
||||||
Copyright (c) 2010-2013 Matthias Richter
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
Except as contained in this notice, the name(s) of the above copyright holders
|
|
||||||
shall not be used in advertising or otherwise to promote the sale, use or
|
|
||||||
other dealings in this Software without prior written authorization.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
]]--
|
|
||||||
|
|
||||||
local _PATH = (...):match('^(.*[%./])[^%.%/]+$') or ''
|
|
||||||
local cos, sin = math.cos, math.sin
|
|
||||||
|
|
||||||
local camera = {}
|
|
||||||
camera.__index = camera
|
|
||||||
|
|
||||||
local function new(x,y, zoom, rot)
|
|
||||||
x,y = x or love.graphics.getWidth()/2, y or love.graphics.getHeight()/2
|
|
||||||
zoom = zoom or 1
|
|
||||||
rot = rot or 0
|
|
||||||
return setmetatable({x = x, y = y, scale = zoom, rot = rot}, camera)
|
|
||||||
end
|
|
||||||
|
|
||||||
function camera:lookAt(x,y)
|
|
||||||
self.x, self.y = x,y
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
function camera:move(x,y)
|
|
||||||
self.x, self.y = self.x + x, self.y + y
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
function camera:pos()
|
|
||||||
return self.x, self.y
|
|
||||||
end
|
|
||||||
|
|
||||||
function camera:rotate(phi)
|
|
||||||
self.rot = self.rot + phi
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
function camera:rotateTo(phi)
|
|
||||||
self.rot = phi
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
function camera:zoom(mul)
|
|
||||||
self.scale = self.scale * mul
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
function camera:zoomTo(zoom)
|
|
||||||
self.scale = zoom
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
function camera:attach()
|
|
||||||
local cx,cy = love.graphics.getWidth()/(2*self.scale), love.graphics.getHeight()/(2*self.scale)
|
|
||||||
love.graphics.push()
|
|
||||||
love.graphics.scale(self.scale)
|
|
||||||
love.graphics.translate(cx, cy)
|
|
||||||
love.graphics.rotate(self.rot)
|
|
||||||
love.graphics.translate(-self.x, -self.y)
|
|
||||||
end
|
|
||||||
|
|
||||||
function camera:detach()
|
|
||||||
love.graphics.pop()
|
|
||||||
end
|
|
||||||
|
|
||||||
function camera:draw(func)
|
|
||||||
self:attach()
|
|
||||||
func()
|
|
||||||
self:detach()
|
|
||||||
end
|
|
||||||
|
|
||||||
function camera:cameraCoords(x,y)
|
|
||||||
-- x,y = ((x,y) - (self.x, self.y)):rotated(self.rot) * self.scale + center
|
|
||||||
local w,h = love.graphics.getWidth(), love.graphics.getHeight()
|
|
||||||
local c,s = cos(self.rot), sin(self.rot)
|
|
||||||
x,y = x - self.x, y - self.y
|
|
||||||
x,y = c*x - s*y, s*x + c*y
|
|
||||||
return x*self.scale + w/2, y*self.scale + h/2
|
|
||||||
end
|
|
||||||
|
|
||||||
function camera:worldCoords(x,y)
|
|
||||||
-- x,y = (((x,y) - center) / self.scale):rotated(-self.rot) + (self.x,self.y)
|
|
||||||
local w,h = love.graphics.getWidth(), love.graphics.getHeight()
|
|
||||||
local c,s = cos(-self.rot), sin(-self.rot)
|
|
||||||
x,y = (x - w/2) / self.scale, (y - h/2) / self.scale
|
|
||||||
x,y = c*x - s*y, s*x + c*y
|
|
||||||
return x+self.x, y+self.y
|
|
||||||
end
|
|
||||||
|
|
||||||
function camera:mousepos()
|
|
||||||
return self:worldCoords(love.mouse.getPosition())
|
|
||||||
end
|
|
||||||
|
|
||||||
-- the module
|
|
||||||
return setmetatable({new = new},
|
|
||||||
{__call = function(_, ...) return new(...) end})
|
|
||||||
Vendored
-94
@@ -1,94 +0,0 @@
|
|||||||
--[[
|
|
||||||
Copyright (c) 2010-2013 Matthias Richter
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
Except as contained in this notice, the name(s) of the above copyright holders
|
|
||||||
shall not be used in advertising or otherwise to promote the sale, use or
|
|
||||||
other dealings in this Software without prior written authorization.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
]]--
|
|
||||||
|
|
||||||
local function include_helper(to, from, seen)
|
|
||||||
if from == nil then
|
|
||||||
return to
|
|
||||||
elseif type(from) ~= 'table' then
|
|
||||||
return from
|
|
||||||
elseif seen[from] then
|
|
||||||
return seen[from]
|
|
||||||
end
|
|
||||||
|
|
||||||
seen[from] = to
|
|
||||||
for k,v in pairs(from) do
|
|
||||||
k = include_helper({}, k, seen) -- keys might also be tables
|
|
||||||
if not to[k] then
|
|
||||||
to[k] = include_helper({}, v, seen)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return to
|
|
||||||
end
|
|
||||||
|
|
||||||
-- deeply copies `other' into `class'. keys in `other' that are already
|
|
||||||
-- defined in `class' are omitted
|
|
||||||
local function include(class, other)
|
|
||||||
return include_helper(class, other, {})
|
|
||||||
end
|
|
||||||
|
|
||||||
-- returns a deep copy of `other'
|
|
||||||
local function clone(other)
|
|
||||||
return setmetatable(include({}, other), getmetatable(other))
|
|
||||||
end
|
|
||||||
|
|
||||||
local function new(class)
|
|
||||||
-- mixins
|
|
||||||
local inc = class.__includes or {}
|
|
||||||
if getmetatable(inc) then inc = {inc} end
|
|
||||||
|
|
||||||
for _, other in ipairs(inc) do
|
|
||||||
include(class, other)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- class implementation
|
|
||||||
class.__index = class
|
|
||||||
class.init = class.init or class[1] or function() end
|
|
||||||
class.include = class.include or include
|
|
||||||
class.clone = class.clone or clone
|
|
||||||
|
|
||||||
-- constructor call
|
|
||||||
return setmetatable(class, {__call = function(c, ...)
|
|
||||||
local o = setmetatable({}, c)
|
|
||||||
o:init(...)
|
|
||||||
return o
|
|
||||||
end})
|
|
||||||
end
|
|
||||||
|
|
||||||
-- interface for cross class-system compatibility (see https://github.com/bartbes/Class-Commons).
|
|
||||||
if class_commons ~= false and not common then
|
|
||||||
common = {}
|
|
||||||
function common.class(name, prototype, parent)
|
|
||||||
return new{__includes = {prototype, parent}}
|
|
||||||
end
|
|
||||||
function common.instance(class, ...)
|
|
||||||
return class(...)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- the module
|
|
||||||
return setmetatable({new = new, include = include, clone = clone},
|
|
||||||
{__call = function(_,...) return new(...) end})
|
|
||||||
Vendored
-97
@@ -1,97 +0,0 @@
|
|||||||
--[[
|
|
||||||
Copyright (c) 2010-2013 Matthias Richter
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
Except as contained in this notice, the name(s) of the above copyright holders
|
|
||||||
shall not be used in advertising or otherwise to promote the sale, use or
|
|
||||||
other dealings in this Software without prior written authorization.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
]]--
|
|
||||||
|
|
||||||
local function __NULL__() end
|
|
||||||
|
|
||||||
-- default gamestate produces error on every callback
|
|
||||||
local state_init = setmetatable({leave = __NULL__},
|
|
||||||
{__index = function() error("Gamestate not initialized. Use Gamestate.switch()") end})
|
|
||||||
local stack = {state_init}
|
|
||||||
|
|
||||||
local GS = {}
|
|
||||||
function GS.new(t) return t or {} end -- constructor - deprecated!
|
|
||||||
|
|
||||||
function GS.switch(to, ...)
|
|
||||||
assert(to, "Missing argument: Gamestate to switch to")
|
|
||||||
assert(to ~= GS, "Can't call switch with colon operator")
|
|
||||||
local pre = stack[#stack]
|
|
||||||
;(pre.leave or __NULL__)(pre)
|
|
||||||
;(to.init or __NULL__)(to)
|
|
||||||
to.init = nil
|
|
||||||
stack[#stack] = to
|
|
||||||
return (to.enter or __NULL__)(to, pre, ...)
|
|
||||||
end
|
|
||||||
|
|
||||||
function GS.push(to, ...)
|
|
||||||
assert(to, "Missing argument: Gamestate to switch to")
|
|
||||||
assert(to ~= GS, "Can't call push with colon operator")
|
|
||||||
local pre = stack[#stack]
|
|
||||||
;(to.init or __NULL__)(to)
|
|
||||||
to.init = nil
|
|
||||||
stack[#stack+1] = to
|
|
||||||
return (to.enter or __NULL__)(to, pre, ...)
|
|
||||||
end
|
|
||||||
|
|
||||||
function GS.pop(...)
|
|
||||||
assert(#stack > 1, "No more states to pop!")
|
|
||||||
local pre = stack[#stack]
|
|
||||||
stack[#stack] = nil
|
|
||||||
;(pre.leave or __NULL__)(pre)
|
|
||||||
return (stack[#stack].resume or __NULL__)(pre, ...)
|
|
||||||
end
|
|
||||||
|
|
||||||
function GS.current()
|
|
||||||
return stack[#stack]
|
|
||||||
end
|
|
||||||
|
|
||||||
local all_callbacks = {
|
|
||||||
'draw', 'errhand', 'focus', 'keypressed', 'keyreleased', 'mousefocus',
|
|
||||||
'mousepressed', 'mousereleased', 'quit', 'resize', 'textinput',
|
|
||||||
'threaderror', 'update', 'visible', 'gamepadaxis', 'gamepadpressed',
|
|
||||||
'gamepadreleased', 'joystickadded', 'joystickaxis', 'joystickhat',
|
|
||||||
'joystickpressed', 'joystickreleased', 'joystickremoved'
|
|
||||||
}
|
|
||||||
|
|
||||||
function GS.registerEvents(callbacks)
|
|
||||||
local registry = {}
|
|
||||||
callbacks = callbacks or all_callbacks
|
|
||||||
for _, f in ipairs(callbacks) do
|
|
||||||
registry[f] = love[f] or __NULL__
|
|
||||||
love[f] = function(...)
|
|
||||||
registry[f](...)
|
|
||||||
return GS[f](...)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- forward any undefined functions
|
|
||||||
setmetatable(GS, {__index = function(_, func)
|
|
||||||
return function(...)
|
|
||||||
return (stack[#stack][func] or __NULL__)(stack[#stack], ...)
|
|
||||||
end
|
|
||||||
end})
|
|
||||||
|
|
||||||
return GS
|
|
||||||
Vendored
-95
@@ -1,95 +0,0 @@
|
|||||||
--[[
|
|
||||||
Copyright (c) 2012-2013 Matthias Richter
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
Except as contained in this notice, the name(s) of the above copyright holders
|
|
||||||
shall not be used in advertising or otherwise to promote the sale, use or
|
|
||||||
other dealings in this Software without prior written authorization.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
]]--
|
|
||||||
|
|
||||||
local Registry = {}
|
|
||||||
Registry.__index = function(self, key)
|
|
||||||
return Registry[key] or (function()
|
|
||||||
local t = {}
|
|
||||||
rawset(self, key, t)
|
|
||||||
return t
|
|
||||||
end)()
|
|
||||||
end
|
|
||||||
|
|
||||||
function Registry:register(s, f)
|
|
||||||
self[s][f] = f
|
|
||||||
return f
|
|
||||||
end
|
|
||||||
|
|
||||||
function Registry:emit(s, ...)
|
|
||||||
for f in pairs(self[s]) do
|
|
||||||
f(...)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Registry:remove(s, ...)
|
|
||||||
local f = {...}
|
|
||||||
for i = 1,select('#', ...) do
|
|
||||||
self[s][f[i]] = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Registry:clear(...)
|
|
||||||
local s = {...}
|
|
||||||
for i = 1,select('#', ...) do
|
|
||||||
self[s[i]] = {}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Registry:emit_pattern(p, ...)
|
|
||||||
for s in pairs(self) do
|
|
||||||
if s:match(p) then self:emit(s, ...) end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Registry:remove_pattern(p, ...)
|
|
||||||
for s in pairs(self) do
|
|
||||||
if s:match(p) then self:remove(s, ...) end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Registry:clear_pattern(p)
|
|
||||||
for s in pairs(self) do
|
|
||||||
if s:match(p) then self[s] = {} end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- the module
|
|
||||||
local function new()
|
|
||||||
local registry = setmetatable({}, Registry)
|
|
||||||
|
|
||||||
return setmetatable({
|
|
||||||
new = new,
|
|
||||||
register = function(...) return registry:register(...) end,
|
|
||||||
emit = function(...) registry:emit(...) end,
|
|
||||||
remove = function(...) registry:remove(...) end,
|
|
||||||
clear = function(...) registry:clear(...) end,
|
|
||||||
emit_pattern = function(...) registry:emit_pattern(...) end,
|
|
||||||
remove_pattern = function(...) registry:remove_pattern(...) end,
|
|
||||||
clear_pattern = function(...) registry:clear_pattern(...) end,
|
|
||||||
}, {__call = new})
|
|
||||||
end
|
|
||||||
|
|
||||||
return new()
|
|
||||||
Vendored
-188
@@ -1,188 +0,0 @@
|
|||||||
--[[
|
|
||||||
Copyright (c) 2010-2013 Matthias Richter
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
Except as contained in this notice, the name(s) of the above copyright holders
|
|
||||||
shall not be used in advertising or otherwise to promote the sale, use or
|
|
||||||
other dealings in this Software without prior written authorization.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
]]--
|
|
||||||
|
|
||||||
local Timer = {}
|
|
||||||
Timer.__index = Timer
|
|
||||||
|
|
||||||
local function _nothing_() end
|
|
||||||
|
|
||||||
function Timer:update(dt)
|
|
||||||
local to_remove = {}
|
|
||||||
for handle, delay in pairs(self.functions) do
|
|
||||||
delay = delay - dt
|
|
||||||
if delay <= 0 then
|
|
||||||
to_remove[#to_remove+1] = handle
|
|
||||||
end
|
|
||||||
self.functions[handle] = delay
|
|
||||||
handle.func(dt, delay)
|
|
||||||
end
|
|
||||||
for _,handle in ipairs(to_remove) do
|
|
||||||
self.functions[handle] = nil
|
|
||||||
handle.after(handle.after)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Timer:do_for(delay, func, after)
|
|
||||||
local handle = {func = func, after = after or _nothing_}
|
|
||||||
self.functions[handle] = delay
|
|
||||||
return handle
|
|
||||||
end
|
|
||||||
|
|
||||||
function Timer:add(delay, func)
|
|
||||||
return self:do_for(delay, _nothing_, func)
|
|
||||||
end
|
|
||||||
|
|
||||||
function Timer:addPeriodic(delay, func, count)
|
|
||||||
local count, handle = count or math.huge -- exploit below: math.huge - 1 = math.huge
|
|
||||||
|
|
||||||
handle = self:add(delay, function(f)
|
|
||||||
if func(func) == false then return end
|
|
||||||
count = count - 1
|
|
||||||
if count > 0 then
|
|
||||||
self.functions[handle] = delay
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
return handle
|
|
||||||
end
|
|
||||||
|
|
||||||
function Timer:cancel(handle)
|
|
||||||
self.functions[handle] = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
function Timer:clear()
|
|
||||||
self.functions = {}
|
|
||||||
end
|
|
||||||
|
|
||||||
Timer.tween = setmetatable({
|
|
||||||
-- helper functions
|
|
||||||
out = function(f) -- 'rotates' a function
|
|
||||||
return function(s, ...) return 1 - f(1-s, ...) end
|
|
||||||
end,
|
|
||||||
chain = function(f1, f2) -- concatenates two functions
|
|
||||||
return function(s, ...) return (s < .5 and f1(2*s, ...) or 1 + f2(2*s-1, ...)) * .5 end
|
|
||||||
end,
|
|
||||||
|
|
||||||
-- useful tweening functions
|
|
||||||
linear = function(s) return s end,
|
|
||||||
quad = function(s) return s*s end,
|
|
||||||
cubic = function(s) return s*s*s end,
|
|
||||||
quart = function(s) return s*s*s*s end,
|
|
||||||
quint = function(s) return s*s*s*s*s end,
|
|
||||||
sine = function(s) return 1-math.cos(s*math.pi/2) end,
|
|
||||||
expo = function(s) return 2^(10*(s-1)) end,
|
|
||||||
circ = function(s) return 1 - math.sqrt(1-s*s) end,
|
|
||||||
|
|
||||||
back = function(s,bounciness)
|
|
||||||
bounciness = bounciness or 1.70158
|
|
||||||
return s*s*((bounciness+1)*s - bounciness)
|
|
||||||
end,
|
|
||||||
|
|
||||||
bounce = function(s) -- magic numbers ahead
|
|
||||||
local a,b = 7.5625, 1/2.75
|
|
||||||
return math.min(a*s^2, a*(s-1.5*b)^2 + .75, a*(s-2.25*b)^2 + .9375, a*(s-2.625*b)^2 + .984375)
|
|
||||||
end,
|
|
||||||
|
|
||||||
elastic = function(s, amp, period)
|
|
||||||
amp, period = amp and math.max(1, amp) or 1, period or .3
|
|
||||||
return (-amp * math.sin(2*math.pi/period * (s-1) - math.asin(1/amp))) * 2^(10*(s-1))
|
|
||||||
end,
|
|
||||||
}, {
|
|
||||||
|
|
||||||
-- register new tween
|
|
||||||
__call = function(tween, self, len, subject, target, method, after, ...)
|
|
||||||
-- recursively collects fields that are defined in both subject and target into a flat list
|
|
||||||
local function tween_collect_payload(subject, target, out)
|
|
||||||
for k,v in pairs(target) do
|
|
||||||
local ref = subject[k]
|
|
||||||
assert(type(v) == type(ref), 'Type mismatch in field "'..k..'".')
|
|
||||||
if type(v) == 'table' then
|
|
||||||
tween_collect_payload(ref, v, out)
|
|
||||||
else
|
|
||||||
local ok, delta = pcall(function() return (v-ref)*1 end)
|
|
||||||
assert(ok, 'Field "'..k..'" does not support arithmetic operations')
|
|
||||||
out[#out+1] = {subject, k, delta}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return out
|
|
||||||
end
|
|
||||||
|
|
||||||
method = tween[method or 'linear'] -- see __index
|
|
||||||
local payload, t, args = tween_collect_payload(subject, target, {}), 0, {...}
|
|
||||||
|
|
||||||
local last_s = 0
|
|
||||||
return self:do_for(len, function(dt)
|
|
||||||
t = t + dt
|
|
||||||
local s = method(math.min(1, t/len), unpack(args))
|
|
||||||
local ds = s - last_s
|
|
||||||
last_s = s
|
|
||||||
for _, info in ipairs(payload) do
|
|
||||||
local ref, key, delta = unpack(info)
|
|
||||||
ref[key] = ref[key] + delta * ds
|
|
||||||
end
|
|
||||||
end, after)
|
|
||||||
end,
|
|
||||||
|
|
||||||
-- fetches function and generated compositions for method `key`
|
|
||||||
__index = function(tweens, key)
|
|
||||||
if type(key) == 'function' then return key end
|
|
||||||
|
|
||||||
assert(type(key) == 'string', 'Method must be function or string.')
|
|
||||||
if rawget(tweens, key) then return rawget(tweens, key) end
|
|
||||||
|
|
||||||
local function construct(pattern, f)
|
|
||||||
local method = rawget(tweens, key:match(pattern))
|
|
||||||
if method then return f(method) end
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
local out, chain = rawget(tweens,'out'), rawget(tweens,'chain')
|
|
||||||
return construct('^in%-([^-]+)$', function(...) return ... end)
|
|
||||||
or construct('^out%-([^-]+)$', out)
|
|
||||||
or construct('^in%-out%-([^-]+)$', function(f) return chain(f, out(f)) end)
|
|
||||||
or construct('^out%-in%-([^-]+)$', function(f) return chain(out(f), f) end)
|
|
||||||
or error('Unknown interpolation method: ' .. key)
|
|
||||||
end})
|
|
||||||
|
|
||||||
-- the module
|
|
||||||
local function new()
|
|
||||||
local timer = setmetatable({functions = {}, tween = Timer.tween}, Timer)
|
|
||||||
return setmetatable({
|
|
||||||
new = new,
|
|
||||||
update = function(...) return timer:update(...) end,
|
|
||||||
do_for = function(...) return timer:do_for(...) end,
|
|
||||||
add = function(...) return timer:add(...) end,
|
|
||||||
addPeriodic = function(...) return timer:addPeriodic(...) end,
|
|
||||||
cancel = function(...) return timer:cancel(...) end,
|
|
||||||
clear = function(...) return timer:clear(...) end,
|
|
||||||
tween = setmetatable({}, {
|
|
||||||
__index = Timer.tween,
|
|
||||||
__newindex = function(_,k,v) Timer.tween[k] = v end,
|
|
||||||
__call = function(t,...) return timer:tween(...) end,
|
|
||||||
})
|
|
||||||
}, {__call = new})
|
|
||||||
end
|
|
||||||
|
|
||||||
return new()
|
|
||||||
Vendored
-161
@@ -1,161 +0,0 @@
|
|||||||
--[[
|
|
||||||
Copyright (c) 2012-2013 Matthias Richter
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
Except as contained in this notice, the name(s) of the above copyright holders
|
|
||||||
shall not be used in advertising or otherwise to promote the sale, use or
|
|
||||||
other dealings in this Software without prior written authorization.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
]]--
|
|
||||||
|
|
||||||
local sqrt, cos, sin, atan2 = math.sqrt, math.cos, math.sin, math.atan2
|
|
||||||
|
|
||||||
local function str(x,y)
|
|
||||||
return "("..tonumber(x)..","..tonumber(y)..")"
|
|
||||||
end
|
|
||||||
|
|
||||||
local function mul(s, x,y)
|
|
||||||
return s*x, s*y
|
|
||||||
end
|
|
||||||
|
|
||||||
local function div(s, x,y)
|
|
||||||
return x/s, y/s
|
|
||||||
end
|
|
||||||
|
|
||||||
local function add(x1,y1, x2,y2)
|
|
||||||
return x1+x2, y1+y2
|
|
||||||
end
|
|
||||||
|
|
||||||
local function sub(x1,y1, x2,y2)
|
|
||||||
return x1-x2, y1-y2
|
|
||||||
end
|
|
||||||
|
|
||||||
local function permul(x1,y1, x2,y2)
|
|
||||||
return x1*x2, y1*y2
|
|
||||||
end
|
|
||||||
|
|
||||||
local function dot(x1,y1, x2,y2)
|
|
||||||
return x1*x2 + y1*y2
|
|
||||||
end
|
|
||||||
|
|
||||||
local function det(x1,y1, x2,y2)
|
|
||||||
return x1*y2 - y1*x2
|
|
||||||
end
|
|
||||||
|
|
||||||
local function eq(x1,y1, x2,y2)
|
|
||||||
return x1 == x2 and y1 == y2
|
|
||||||
end
|
|
||||||
|
|
||||||
local function lt(x1,y1, x2,y2)
|
|
||||||
return x1 < x2 or (x1 == x2 and y1 < y2)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function le(x1,y1, x2,y2)
|
|
||||||
return x1 <= x2 and y1 <= y2
|
|
||||||
end
|
|
||||||
|
|
||||||
local function len2(x,y)
|
|
||||||
return x*x + y*y
|
|
||||||
end
|
|
||||||
|
|
||||||
local function len(x,y)
|
|
||||||
return sqrt(x*x + y*y)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function dist2(x1,y1, x2,y2)
|
|
||||||
return len2(x1-x2, y1-y2)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function dist(x1,y1, x2,y2)
|
|
||||||
return len(x1-x2, y1-y2)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function normalize(x,y)
|
|
||||||
local l = len(x,y)
|
|
||||||
if l > 0 then
|
|
||||||
return x/l, y/l
|
|
||||||
end
|
|
||||||
return x,y
|
|
||||||
end
|
|
||||||
|
|
||||||
local function rotate(phi, x,y)
|
|
||||||
local c, s = cos(phi), sin(phi)
|
|
||||||
return c*x - s*y, s*x + c*y
|
|
||||||
end
|
|
||||||
|
|
||||||
local function perpendicular(x,y)
|
|
||||||
return -y, x
|
|
||||||
end
|
|
||||||
|
|
||||||
local function project(x,y, u,v)
|
|
||||||
local s = (x*u + y*v) / (u*u + v*v)
|
|
||||||
return s*u, s*v
|
|
||||||
end
|
|
||||||
|
|
||||||
local function mirror(x,y, u,v)
|
|
||||||
local s = 2 * (x*u + y*v) / (u*u + v*v)
|
|
||||||
return s*u - x, s*v - y
|
|
||||||
end
|
|
||||||
|
|
||||||
-- ref.: http://blog.signalsondisplay.com/?p=336
|
|
||||||
local function trim(maxLen, x, y)
|
|
||||||
local s = maxLen * maxLen / len2(x, y)
|
|
||||||
s = s > 1 and 1 or math.sqrt(s)
|
|
||||||
return x * s, y * s
|
|
||||||
end
|
|
||||||
|
|
||||||
local function angleTo(x,y, u,v)
|
|
||||||
if u and v then
|
|
||||||
return atan2(y, x) - atan2(v, u)
|
|
||||||
end
|
|
||||||
return atan2(y, x)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- the module
|
|
||||||
return {
|
|
||||||
str = str,
|
|
||||||
|
|
||||||
-- arithmetic
|
|
||||||
mul = mul,
|
|
||||||
div = div,
|
|
||||||
add = add,
|
|
||||||
sub = sub,
|
|
||||||
permul = permul,
|
|
||||||
dot = dot,
|
|
||||||
det = det,
|
|
||||||
cross = det,
|
|
||||||
|
|
||||||
-- relation
|
|
||||||
eq = eq,
|
|
||||||
lt = lt,
|
|
||||||
le = le,
|
|
||||||
|
|
||||||
-- misc operations
|
|
||||||
len2 = len2,
|
|
||||||
len = len,
|
|
||||||
dist2 = dist2,
|
|
||||||
dist = dist,
|
|
||||||
normalize = normalize,
|
|
||||||
rotate = rotate,
|
|
||||||
perpendicular = perpendicular,
|
|
||||||
project = project,
|
|
||||||
mirror = mirror,
|
|
||||||
trim = trim,
|
|
||||||
angleTo = angleTo,
|
|
||||||
}
|
|
||||||
Vendored
-191
@@ -1,191 +0,0 @@
|
|||||||
--[[
|
|
||||||
Copyright (c) 2010-2013 Matthias Richter
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
Except as contained in this notice, the name(s) of the above copyright holders
|
|
||||||
shall not be used in advertising or otherwise to promote the sale, use or
|
|
||||||
other dealings in this Software without prior written authorization.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
]]--
|
|
||||||
|
|
||||||
local assert = assert
|
|
||||||
local sqrt, cos, sin, atan2 = math.sqrt, math.cos, math.sin, math.atan2
|
|
||||||
|
|
||||||
local vector = {}
|
|
||||||
vector.__index = vector
|
|
||||||
|
|
||||||
local function new(x,y)
|
|
||||||
return setmetatable({x = x or 0, y = y or 0}, vector)
|
|
||||||
end
|
|
||||||
local zero = new(0,0)
|
|
||||||
|
|
||||||
local function isvector(v)
|
|
||||||
return type(v) == 'table' and type(v.x) == 'number' and type(v.y) == 'number'
|
|
||||||
end
|
|
||||||
|
|
||||||
function vector:clone()
|
|
||||||
return new(self.x, self.y)
|
|
||||||
end
|
|
||||||
|
|
||||||
function vector:unpack()
|
|
||||||
return self.x, self.y
|
|
||||||
end
|
|
||||||
|
|
||||||
function vector:__tostring()
|
|
||||||
return "("..tonumber(self.x)..","..tonumber(self.y)..")"
|
|
||||||
end
|
|
||||||
|
|
||||||
function vector.__unm(a)
|
|
||||||
return new(-a.x, -a.y)
|
|
||||||
end
|
|
||||||
|
|
||||||
function vector.__add(a,b)
|
|
||||||
assert(isvector(a) and isvector(b), "Add: wrong argument types (<vector> expected)")
|
|
||||||
return new(a.x+b.x, a.y+b.y)
|
|
||||||
end
|
|
||||||
|
|
||||||
function vector.__sub(a,b)
|
|
||||||
assert(isvector(a) and isvector(b), "Sub: wrong argument types (<vector> expected)")
|
|
||||||
return new(a.x-b.x, a.y-b.y)
|
|
||||||
end
|
|
||||||
|
|
||||||
function vector.__mul(a,b)
|
|
||||||
if type(a) == "number" then
|
|
||||||
return new(a*b.x, a*b.y)
|
|
||||||
elseif type(b) == "number" then
|
|
||||||
return new(b*a.x, b*a.y)
|
|
||||||
else
|
|
||||||
assert(isvector(a) and isvector(b), "Mul: wrong argument types (<vector> or <number> expected)")
|
|
||||||
return a.x*b.x + a.y*b.y
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function vector.__div(a,b)
|
|
||||||
assert(isvector(a) and type(b) == "number", "wrong argument types (expected <vector> / <number>)")
|
|
||||||
return new(a.x / b, a.y / b)
|
|
||||||
end
|
|
||||||
|
|
||||||
function vector.__eq(a,b)
|
|
||||||
return a.x == b.x and a.y == b.y
|
|
||||||
end
|
|
||||||
|
|
||||||
function vector.__lt(a,b)
|
|
||||||
return a.x < b.x or (a.x == b.x and a.y < b.y)
|
|
||||||
end
|
|
||||||
|
|
||||||
function vector.__le(a,b)
|
|
||||||
return a.x <= b.x and a.y <= b.y
|
|
||||||
end
|
|
||||||
|
|
||||||
function vector.permul(a,b)
|
|
||||||
assert(isvector(a) and isvector(b), "permul: wrong argument types (<vector> expected)")
|
|
||||||
return new(a.x*b.x, a.y*b.y)
|
|
||||||
end
|
|
||||||
|
|
||||||
function vector:len2()
|
|
||||||
return self.x * self.x + self.y * self.y
|
|
||||||
end
|
|
||||||
|
|
||||||
function vector:len()
|
|
||||||
return sqrt(self.x * self.x + self.y * self.y)
|
|
||||||
end
|
|
||||||
|
|
||||||
function vector.dist(a, b)
|
|
||||||
assert(isvector(a) and isvector(b), "dist: wrong argument types (<vector> expected)")
|
|
||||||
local dx = a.x - b.x
|
|
||||||
local dy = a.y - b.y
|
|
||||||
return sqrt(dx * dx + dy * dy)
|
|
||||||
end
|
|
||||||
|
|
||||||
function vector.dist2(a, b)
|
|
||||||
assert(isvector(a) and isvector(b), "dist: wrong argument types (<vector> expected)")
|
|
||||||
local dx = a.x - b.x
|
|
||||||
local dy = a.y - b.y
|
|
||||||
return (dx * dx + dy * dy)
|
|
||||||
end
|
|
||||||
|
|
||||||
function vector:normalize_inplace()
|
|
||||||
local l = self:len()
|
|
||||||
if l > 0 then
|
|
||||||
self.x, self.y = self.x / l, self.y / l
|
|
||||||
end
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
function vector:normalized()
|
|
||||||
return self:clone():normalize_inplace()
|
|
||||||
end
|
|
||||||
|
|
||||||
function vector:rotate_inplace(phi)
|
|
||||||
local c, s = cos(phi), sin(phi)
|
|
||||||
self.x, self.y = c * self.x - s * self.y, s * self.x + c * self.y
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
function vector:rotated(phi)
|
|
||||||
local c, s = cos(phi), sin(phi)
|
|
||||||
return new(c * self.x - s * self.y, s * self.x + c * self.y)
|
|
||||||
end
|
|
||||||
|
|
||||||
function vector:perpendicular()
|
|
||||||
return new(-self.y, self.x)
|
|
||||||
end
|
|
||||||
|
|
||||||
function vector:projectOn(v)
|
|
||||||
assert(isvector(v), "invalid argument: cannot project vector on " .. type(v))
|
|
||||||
-- (self * v) * v / v:len2()
|
|
||||||
local s = (self.x * v.x + self.y * v.y) / (v.x * v.x + v.y * v.y)
|
|
||||||
return new(s * v.x, s * v.y)
|
|
||||||
end
|
|
||||||
|
|
||||||
function vector:mirrorOn(v)
|
|
||||||
assert(isvector(v), "invalid argument: cannot mirror vector on " .. type(v))
|
|
||||||
-- 2 * self:projectOn(v) - self
|
|
||||||
local s = 2 * (self.x * v.x + self.y * v.y) / (v.x * v.x + v.y * v.y)
|
|
||||||
return new(s * v.x - self.x, s * v.y - self.y)
|
|
||||||
end
|
|
||||||
|
|
||||||
function vector:cross(v)
|
|
||||||
assert(isvector(v), "cross: wrong argument types (<vector> expected)")
|
|
||||||
return self.x * v.y - self.y * v.x
|
|
||||||
end
|
|
||||||
|
|
||||||
-- ref.: http://blog.signalsondisplay.com/?p=336
|
|
||||||
function vector:trim_inplace(maxLen)
|
|
||||||
local s = maxLen * maxLen / self:len2()
|
|
||||||
s = (s > 1 and 1) or math.sqrt(s)
|
|
||||||
self.x, self.y = self.x * s, self.y * s
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
function vector:angleTo(other)
|
|
||||||
if other then
|
|
||||||
return atan2(self.y, self.x) - atan2(other.y, other.x)
|
|
||||||
end
|
|
||||||
return atan2(self.y, self.x)
|
|
||||||
end
|
|
||||||
|
|
||||||
function vector:trimmed(maxLen)
|
|
||||||
return self:clone():trim_inplace(maxLen)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- the module
|
|
||||||
return setmetatable({new = new, isvector = isvector, zero = zero},
|
|
||||||
{__call = function(_, ...) return new(...) end})
|
|
||||||
Vendored
-388
@@ -1,388 +0,0 @@
|
|||||||
# Change Log
|
|
||||||
|
|
||||||
## 2016-01-12: v0.14.1.12
|
|
||||||
|
|
||||||
* Added: Basic support for object layers in Bump plugin (thanks @premek)
|
|
||||||
* Changed: New line token from CRLF to LF
|
|
||||||
* Fixed: Sprite batches should now respect the map draw order
|
|
||||||
|
|
||||||
## 2016-01-01: v0.14.1.11
|
|
||||||
|
|
||||||
* Fixed: Various bugs in the Box2D plugin (thanks @ChrisWeisiger)
|
|
||||||
* Fixed: Various bugs in the Bump plugin (thanks @bobbyjoness)
|
|
||||||
|
|
||||||
## 2015-12-31: v0.14.1.10
|
|
||||||
|
|
||||||
* Fixed: Box2D plugin was not recognizing a tile's embedded object group
|
|
||||||
|
|
||||||
## 2015-11-19: v0.14.1.9
|
|
||||||
|
|
||||||
* Changed: key in image cache to formatted path of image
|
|
||||||
|
|
||||||
## 2015-11-16: v0.14.1.8
|
|
||||||
|
|
||||||
* Added: image cache to STI module [sponsored by Binary Cocoa]
|
|
||||||
* Added: STI:flush() to clear out image cache
|
|
||||||
|
|
||||||
## 2015-11-15: v0.14.1.7
|
|
||||||
|
|
||||||
* Added: support for offsetting maps [sponsored by Binary Cocoa]
|
|
||||||
* Changed: Map.setDrawRange is more optimized via recycling tables
|
|
||||||
* Changed: render order now defaults to "right-down"
|
|
||||||
|
|
||||||
## 2015-11-07: v0.14.1.6
|
|
||||||
|
|
||||||
* Fixed: tileset images not being properly filtered
|
|
||||||
* Fixed: bump.lua plugin missing world argument in draw
|
|
||||||
|
|
||||||
## 2015-10-14: v0.14.1.5
|
|
||||||
|
|
||||||
* Added: bump.lua plugin (thanks @bobbyjoness)
|
|
||||||
|
|
||||||
## 2015-10-12: v0.14.1.4
|
|
||||||
|
|
||||||
* Fixed: removing a layer now properly removes tile and object instances
|
|
||||||
* Fixed: box2d plugin now properly removes collision objects
|
|
||||||
|
|
||||||
## 2015-10-09: v0.14.1.3
|
|
||||||
|
|
||||||
* Fixed: flipping animated tiles properly display
|
|
||||||
* Fixed: rotating animated tiles properly display
|
|
||||||
* Fixed: rotating tile objects properly display
|
|
||||||
* Fixed: box2d plugin properly creates rotated and flipped tile objects
|
|
||||||
* Fixed: box2d plugin no longer crashes when drawing a line with two vertices
|
|
||||||
|
|
||||||
## 2015-10-07: v0.14.1.2
|
|
||||||
|
|
||||||
* Added: support for all render orders (rd, ru, ld, lu)
|
|
||||||
* Added: support for sensors in the box2d plugin (only works on individual tiles and objects; sensor = true)
|
|
||||||
* Changed: addCustomLayer's index argument is now optional and defaults to the end of the array
|
|
||||||
* Fixed: a crash when using Base64 (uncompressed) with LOVE 0.9.2
|
|
||||||
|
|
||||||
## 2015-10-03: v0.14.1.1
|
|
||||||
|
|
||||||
* Added: support for gzip compressed maps (requires LOVE 0.10.0+)
|
|
||||||
|
|
||||||
## 2015-09-30: v0.14.1.0
|
|
||||||
|
|
||||||
* Added: support for Base64 compressed maps (requires LuaJIT)
|
|
||||||
* Added: support for zlib compressed maps (requires LOVE 0.10.0+)
|
|
||||||
|
|
||||||
## 2015-09-28: v0.14.0.1
|
|
||||||
|
|
||||||
* Added: Support for all staggered types (x/y, even/odd, iso/hex)
|
|
||||||
|
|
||||||
## 2015-09-27: v0.14.0.0
|
|
||||||
|
|
||||||
* Added: Hexagonal map support (thanks EntranceJew!)
|
|
||||||
* Added: Error message for compressed maps
|
|
||||||
* Fixed: box2d plugin threw an error in some cases (thanks maxha651!)
|
|
||||||
|
|
||||||
## 2015-09-17: v0.13.1.4
|
|
||||||
|
|
||||||
* Changed: sanity checks now search for love.physics instead of love.physics.*
|
|
||||||
|
|
||||||
## 2015-09-16: v0.13.1.3
|
|
||||||
|
|
||||||
* Changed: Improved documentation
|
|
||||||
|
|
||||||
## 2015-09-16: v0.13.1.2
|
|
||||||
|
|
||||||
* Changed: Simplified plugins
|
|
||||||
* Changed: Namespaced the box2d plugin
|
|
||||||
* Removed: Non-LOVE frameworks (they didn't work)
|
|
||||||
|
|
||||||
## 2015-09-16: v0.13.1.1
|
|
||||||
|
|
||||||
* Added: LDoc documentation
|
|
||||||
* Added: Plugin system where devs can extend STI
|
|
||||||
* Added: Reinstated the Box2D integration as a plugin
|
|
||||||
|
|
||||||
## 2015-09-15: v0.13.1.0
|
|
||||||
|
|
||||||
* Added: Map:convertToCustomLayer() now returns the layer
|
|
||||||
* Changed: Tightened localization of some functions
|
|
||||||
* Removed: Box2D collision integration
|
|
||||||
* Removed: Unused functions
|
|
||||||
|
|
||||||
## 2015-07-31: v0.12.3.0
|
|
||||||
|
|
||||||
* Added: Tiled version number to Map.tiledversion
|
|
||||||
* Added: Map.objects table indexed by unique object IDs
|
|
||||||
* Added: A better error message when trying to use Tile Collections
|
|
||||||
* Changed: Version number should now match Tiled's version number
|
|
||||||
* Changed: You must now add ".lua" in the filename of a new map as this is consistent with other libraries
|
|
||||||
* Changed: Renamed "pure" framework to "lua" (still doesn't work, though!)
|
|
||||||
* Changed: Map:setDrawRange no longer inverts tx and ty for you, do it yourself!
|
|
||||||
* Changed: Map:draw no longer accepts scale values, use love.graphics.scale!
|
|
||||||
* Fixed: A bug where tile objects were drawing an object border
|
|
||||||
* Removed: Corona framework file
|
|
||||||
|
|
||||||
## 2015-03-22: v0.9.8
|
|
||||||
|
|
||||||
* Fixed: A bug where Tiles without a Properties list would crash
|
|
||||||
|
|
||||||
## 2015-02-02: v0.9.7
|
|
||||||
|
|
||||||
* Added: userdata to Box2D fixtures
|
|
||||||
* Changed: changelog.txt -> CHANGELOG.md
|
|
||||||
* Changed: Flipping tiles now happens in both tile layers and object layers
|
|
||||||
* Fixed: A bug where tile objects were drawing oddly in some cases
|
|
||||||
* Fixed: A bug where circles would error if physics was disabled
|
|
||||||
|
|
||||||
## 2015-01-28: v0.9.6
|
|
||||||
|
|
||||||
* Added: getLayerProperties(), getTileProperties(), and getObjectProperties()
|
|
||||||
* Fixed: A bug where flipped tiles crashed STI during initCollision()
|
|
||||||
* Fixed: Flipped collision tiles now have correct offset
|
|
||||||
* Removed: Reverted the change in v0.9.3 that filled in empty tiles with false
|
|
||||||
|
|
||||||
## 2014-12-15: v0.9.5
|
|
||||||
|
|
||||||
* Fixed: A bug where tile collision objects were using the wrong size in some cases
|
|
||||||
* Fixed: A bug where flipped tiles weren't always creating collision objects
|
|
||||||
|
|
||||||
## 2014-12-05: v0.9.4
|
|
||||||
|
|
||||||
* Changed: STI's canvas plays nicely with other libraries
|
|
||||||
* Changed: addCustomLayer() now returns a handle on the created layer
|
|
||||||
|
|
||||||
## 2014-12-03: v0.9.3
|
|
||||||
|
|
||||||
* Added: Local Tile IDs to Tile objects
|
|
||||||
* Added: Terrain information
|
|
||||||
* Fixed: Some conversion functions
|
|
||||||
* Changed: Tile Layers now contain "false" instead of "nil" where there is no tile
|
|
||||||
* Changed: Added \_LICENSE, \_URL, \_VERSION, and \_DESCRIPTION properties to core STI object
|
|
||||||
|
|
||||||
## 2014-09-29: v0.9.2
|
|
||||||
|
|
||||||
* Added: Support for drawing tiles in object layers
|
|
||||||
* Fixed: Incorrect calculation of some collision objects
|
|
||||||
|
|
||||||
## 2014-09-26: v0.9.1
|
|
||||||
|
|
||||||
* Fixed: A crash when a collidable tile is initialized but not used
|
|
||||||
* Removed: Public access to formatPath(), rotateVertex(), and convertEllipseToPolygon()
|
|
||||||
|
|
||||||
## 2014-09-24: v0.9.0
|
|
||||||
|
|
||||||
* Added: Animated tiles! (Thanks to Clean3d)
|
|
||||||
* Fixed: A crash when a collidable rectangle has no rotation value
|
|
||||||
* Fixed: Incorrect values given to orthogonal collision objects
|
|
||||||
|
|
||||||
## 2014-09-24: v0.8.3
|
|
||||||
|
|
||||||
* Added: Map:convertScreenToTile() and Map:convertTileToScreen()
|
|
||||||
* Added: Map:convertScreenToIsometricTile() and Map:convertIsometricTileToScreen()
|
|
||||||
* Added: Map:convertScreenToStaggeredTile() and Map:convertStaggeredTileToScreen()
|
|
||||||
* Fixed: Map:removeLayer() now works properly
|
|
||||||
* Changed: Tile Objects now use the tile's collision map by default
|
|
||||||
|
|
||||||
## 2014-09-22: v0.8.2
|
|
||||||
|
|
||||||
* Added: "collidable" property for objects, tiles, and layers
|
|
||||||
* if collidable is set to true in Tiled, STI will pick it up and set all appropriate entities to collidable objects
|
|
||||||
* Fixed: Physics module no long required if not needed.
|
|
||||||
* Fixed: Whitespace discrepencies
|
|
||||||
* Changed: Map:initWorldCollision() now supports a whole lot more
|
|
||||||
|
|
||||||
## 2014-09-21: v0.8.1
|
|
||||||
|
|
||||||
* Added: README now lists minimum requirements
|
|
||||||
* Changed: README updated with new collision system
|
|
||||||
* Changed: Map:enableCollision() renamed to Map:initWorldCollision()
|
|
||||||
* Changed: Map:drawCollisionMap() renamed to Map:drawWorldCollision()
|
|
||||||
* Changed: Updated framework files (still no real Lua/Corona support)
|
|
||||||
* Changed: Tidied up collision code
|
|
||||||
* Removed: Map:getCollisionMap()
|
|
||||||
|
|
||||||
## 2014-09-20: v0.8.0
|
|
||||||
|
|
||||||
* Added: Box2D collision via Map:enableCollision()
|
|
||||||
* Added: Map:convertEllipseToPolygon()
|
|
||||||
|
|
||||||
## 2014-09-17: v0.7.6
|
|
||||||
|
|
||||||
* Added: Map:convertScreenToIsometric and Map:convertIsometricToScreen
|
|
||||||
* Added: Map:setObjectCoordinates
|
|
||||||
* Added: Map:rotateVertex
|
|
||||||
* Fixed: Adjusted map positioning for Isometric and Staggered maps
|
|
||||||
* Fixed: Object positioning in Isometric maps
|
|
||||||
* Removed: Temporary fix for Tiled 0.9.1
|
|
||||||
|
|
||||||
## 2014-08-05: v0.7.5
|
|
||||||
|
|
||||||
* Fixed: Properties offset by 1
|
|
||||||
* Fixed: Drawing a single Layer can now use Layer's name/index
|
|
||||||
|
|
||||||
## 2014-04-28: v0.7.4
|
|
||||||
|
|
||||||
* Fixed: Canvas resize type
|
|
||||||
|
|
||||||
## 2014-04-18: v0.7.3
|
|
||||||
|
|
||||||
* Fixed: Canvas using wrong filter
|
|
||||||
|
|
||||||
## 2014-04-08: v0.7.2
|
|
||||||
|
|
||||||
* Removed: Dependency for LuaJIT's bitwise operations
|
|
||||||
|
|
||||||
## 2014-04-08: v0.7.1
|
|
||||||
|
|
||||||
* Added: Map:resize(w, h)
|
|
||||||
* Changed: Map:draw() now takes two optional arguments: ScaleX and ScaleY
|
|
||||||
* Changed: STI now draws to a Canvas before drawing to screen (fixes scaling oddities)
|
|
||||||
|
|
||||||
## 2014-04-07: v0.7.0
|
|
||||||
|
|
||||||
* Added: Files for Corona and Pure Lua implementation
|
|
||||||
* Changed: Restructured sti.lua into several files
|
|
||||||
* Changed: Library is now LOVE agnostic and should allow for implementation of other frameworks
|
|
||||||
|
|
||||||
## 2014-03-1 : v0.6.16
|
|
||||||
|
|
||||||
* Changed: Ellipses now use polygons instead of... Not polygons.
|
|
||||||
|
|
||||||
## 2014-03-1 : v0.6.15
|
|
||||||
|
|
||||||
* Fixed: Tile spacing calculated properly in all cases
|
|
||||||
|
|
||||||
## 2014-02-0 : v0.6.14
|
|
||||||
|
|
||||||
* Fixed: Tile properties ACTUALLY being added now!
|
|
||||||
|
|
||||||
## 2014-01-2 : v0.6.13
|
|
||||||
|
|
||||||
* Added: Missing Tile Flag
|
|
||||||
|
|
||||||
## 2014-01-2 : v0.6.12
|
|
||||||
|
|
||||||
* Added: drawCollisionMap() now supports Isometric and Staggered maps
|
|
||||||
* Changed: drawCollisionMap() now requires a collision map parameter
|
|
||||||
* Changed: setCollisionMap() renamed to getCollisionMap()
|
|
||||||
* Changed: getCollisionMap() now returns the collision map
|
|
||||||
* Fixed: Tile properties not being added
|
|
||||||
* Removed: Map.collision table removed
|
|
||||||
|
|
||||||
## 2014-01-2 : v0.6.11
|
|
||||||
|
|
||||||
* Added: Descriptive error messages
|
|
||||||
* Fixed: Image filters for scaling
|
|
||||||
|
|
||||||
## 2014-01-2 : v0.6.10
|
|
||||||
|
|
||||||
* Fixed: Optimized load time
|
|
||||||
|
|
||||||
## 2014-01-25: v0.6.9
|
|
||||||
|
|
||||||
* Fixed: Parallax Scrolling
|
|
||||||
|
|
||||||
## 2014-01-25: v0.6.8
|
|
||||||
|
|
||||||
* Changed: Revised and restructured code
|
|
||||||
* Changed: createCollisionMap() renamed to setCollisionMap()
|
|
||||||
* Changed: newCustomLayer() renamed to addCustomLayer()
|
|
||||||
|
|
||||||
## 2014-01-24: v0.6.7
|
|
||||||
|
|
||||||
* Fixed: Number of tiles wasn't calculated properly
|
|
||||||
|
|
||||||
## 2014-01-24: v0.6.6
|
|
||||||
|
|
||||||
* Fixed: Spacing wasn't calculated properly
|
|
||||||
|
|
||||||
## 2014-01-24: v0.6.5
|
|
||||||
|
|
||||||
* Added: Staggered Maps
|
|
||||||
|
|
||||||
## 2014-01-24: v0.6.4
|
|
||||||
|
|
||||||
* Added: Isometric Maps
|
|
||||||
|
|
||||||
## 2014-01-20: v0.6.3
|
|
||||||
|
|
||||||
* Added: Tile Flags (flip/rotation)
|
|
||||||
|
|
||||||
## 2014-01-20: v0.6.2
|
|
||||||
|
|
||||||
* Fixed: A scaling bug
|
|
||||||
|
|
||||||
## 2014-01-19: v0.6.1
|
|
||||||
|
|
||||||
* Fixed: A bug causing the Collision Map to be nil
|
|
||||||
|
|
||||||
## 2014-01-19: v0.6.0
|
|
||||||
|
|
||||||
* Added: Sprite Batches
|
|
||||||
|
|
||||||
## 2014-01-19: v0.5.0
|
|
||||||
|
|
||||||
* Added: Draw Range optimization
|
|
||||||
|
|
||||||
## 2014-01-18: v0.4.3
|
|
||||||
|
|
||||||
* Added: Layer draw offsets
|
|
||||||
|
|
||||||
## 2014-01-17: v0.4.2
|
|
||||||
|
|
||||||
* Changed: Organized library a little better
|
|
||||||
|
|
||||||
## 2014-01-17: v0.4.1
|
|
||||||
|
|
||||||
* Fixed: Tiles incorrectly offset
|
|
||||||
* Fixed: Drawing concave polygons
|
|
||||||
|
|
||||||
## 2014-01-17: v0.4.0
|
|
||||||
|
|
||||||
* Added: Draw Object Layers
|
|
||||||
|
|
||||||
## 2014-01-16: v0.3.3
|
|
||||||
|
|
||||||
* Added: Create new Custom Layer
|
|
||||||
* Added: Callbacks for all layers
|
|
||||||
* Added: Remove Layer
|
|
||||||
* Changed: Simplified sti.new()
|
|
||||||
|
|
||||||
## 2014-01-16: v0.3.2
|
|
||||||
|
|
||||||
* Fixed: Crash if using Tiled 0.9.1
|
|
||||||
* Changed: Map structure to remove "map" table
|
|
||||||
|
|
||||||
## 2014-01-16: v0.3.1
|
|
||||||
|
|
||||||
* Added: Update callback to Custom Layers
|
|
||||||
|
|
||||||
## 2014-01-16: v0.3.0
|
|
||||||
|
|
||||||
* Added: Support for converting layers to Custom Layers
|
|
||||||
* Changed: sti.new() no longer requires the file extension
|
|
||||||
|
|
||||||
## 2014-01-15: v0.2.2
|
|
||||||
|
|
||||||
* Added: Support for basic collision layer
|
|
||||||
|
|
||||||
## 2014-01-15: v0.2.1
|
|
||||||
|
|
||||||
* Added: Support for map instances
|
|
||||||
* Added: Name alias to layer indices
|
|
||||||
* Changed: Sandboxed map environment
|
|
||||||
* Changed: Data structures are more efficient
|
|
||||||
* Removed: Unnecessary update function
|
|
||||||
|
|
||||||
Thanks to JarrettBillingsley for many of these changes
|
|
||||||
|
|
||||||
## 2014-01-14: v0.2.0
|
|
||||||
|
|
||||||
* Fixed: Drawing Tile Offset
|
|
||||||
* Changed: Tile Layer data structure is more efficient
|
|
||||||
* Changed: Simplified Quad generation
|
|
||||||
|
|
||||||
## 2014-01-14: v0.1.0
|
|
||||||
|
|
||||||
* Initial Commit
|
|
||||||
* Added: Orthogonal Map support
|
|
||||||
* Added: Draw Tile Layers
|
|
||||||
* Added: Draw Image Layers
|
|
||||||
* Added: Ignore Hidden Layers
|
|
||||||
* Added: Layer Opacity
|
|
||||||
Vendored
-26
@@ -1,26 +0,0 @@
|
|||||||
# Simple Tiled Implementation
|
|
||||||
|
|
||||||
This code is licensed under the [**MIT/X11 Open Source License**][MIT].
|
|
||||||
|
|
||||||
Copyright (c) 2014 Landon Manning - LManning17@gmail.com - [LandonManning.com][LM]
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
|
|
||||||
[MIT]: http://www.opensource.org/licenses/mit-license.html
|
|
||||||
[LM]: http://LandonManning.com
|
|
||||||
Vendored
-96
@@ -1,96 +0,0 @@
|
|||||||
# Simple Tiled Implementation
|
|
||||||
|
|
||||||
Simple Tiled Implementation is a [**Tiled**][Tiled] map loader and renderer designed for the **\*awesome\*** [**LÖVE**][LOVE] framework. Please read the [**documentation**][dox] to learn how it works!
|
|
||||||
|
|
||||||
## Quick Example
|
|
||||||
|
|
||||||
```lua
|
|
||||||
-- This example uses the default Box2D (love.physics) plugin!!
|
|
||||||
|
|
||||||
local sti = require "sti"
|
|
||||||
|
|
||||||
function love.load()
|
|
||||||
-- Grab window size
|
|
||||||
windowWidth = love.graphics.getWidth()
|
|
||||||
windowHeight = love.graphics.getHeight()
|
|
||||||
|
|
||||||
-- Set world meter size (in pixels)
|
|
||||||
love.physics.setMeter(32)
|
|
||||||
|
|
||||||
-- Load a map exported to Lua from Tiled
|
|
||||||
map = sti.new("assets/maps/map01.lua", { "box2d" })
|
|
||||||
|
|
||||||
-- Prepare physics world with horizontal and vertical gravity
|
|
||||||
world = love.physics.newWorld(0, 0)
|
|
||||||
|
|
||||||
-- Prepare collision objects
|
|
||||||
map:box2d_init(world)
|
|
||||||
|
|
||||||
-- Create a Custom Layer
|
|
||||||
map:addCustomLayer("Sprite Layer", 3)
|
|
||||||
|
|
||||||
-- Add data to Custom Layer
|
|
||||||
local spriteLayer = map.layers["Sprite Layer"]
|
|
||||||
spriteLayer.sprites = {
|
|
||||||
player = {
|
|
||||||
image = love.graphics.newImage("assets/sprites/player.png"),
|
|
||||||
x = 64,
|
|
||||||
y = 64,
|
|
||||||
r = 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-- Update callback for Custom Layer
|
|
||||||
function spriteLayer:update(dt)
|
|
||||||
for _, sprite in pairs(self.sprites) do
|
|
||||||
sprite.r = sprite.r + math.rad(90 * dt)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Draw callback for Custom Layer
|
|
||||||
function spriteLayer:draw()
|
|
||||||
for _, sprite in pairs(self.sprites) do
|
|
||||||
local x = math.floor(sprite.x)
|
|
||||||
local y = math.floor(sprite.y)
|
|
||||||
local r = sprite.r
|
|
||||||
love.graphics.draw(sprite.image, x, y, r)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function love.update(dt)
|
|
||||||
map:update(dt)
|
|
||||||
end
|
|
||||||
|
|
||||||
function love.draw()
|
|
||||||
-- Translation would normally be based on a player's x/y
|
|
||||||
local translateX = 0
|
|
||||||
local translateY = 0
|
|
||||||
|
|
||||||
-- Draw Range culls unnecessary tiles
|
|
||||||
map:setDrawRange(-translateX, -translateY, windowWidth, windowHeight)
|
|
||||||
|
|
||||||
-- Draw the map and all objects within
|
|
||||||
map:draw()
|
|
||||||
|
|
||||||
-- Draw Collision Map (useful for debugging)
|
|
||||||
love.graphics.setColor(255, 0, 0, 255)
|
|
||||||
map:box2d_draw()
|
|
||||||
|
|
||||||
-- Reset color
|
|
||||||
love.graphics.setColor(255, 255, 255, 255)
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
|
|
||||||
This library recommends LÖVE 0.9.2 or 0.10.0 and Tiled 0.14.1. If you are updating from an older version of Tiled, please re-export your Lua map files.
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
This code is licensed under the [**MIT/X11 Open Source License**][MIT]. Check out the LICENSE file for more information.
|
|
||||||
|
|
||||||
[Tiled]: http://www.mapeditor.org/
|
|
||||||
[LOVE]: https://www.love2d.org/
|
|
||||||
[dox]: http://karai17.github.io/Simple-Tiled-Implementation/
|
|
||||||
[MIT]: http://www.opensource.org/licenses/mit-license.html
|
|
||||||
Vendored
-53
@@ -1,53 +0,0 @@
|
|||||||
--- Simple and fast Tiled map loader and renderer.
|
|
||||||
-- @module sti
|
|
||||||
-- @author Landon Manning
|
|
||||||
-- @copyright 2015
|
|
||||||
-- @license MIT/X11
|
|
||||||
|
|
||||||
local STI = {
|
|
||||||
_LICENSE = "MIT/X11",
|
|
||||||
_URL = "https://github.com/karai17/Simple-Tiled-Implementation",
|
|
||||||
_VERSION = "0.14.1.12",
|
|
||||||
_DESCRIPTION = "Simple Tiled Implementation is a Tiled Map Editor library designed for the *awesome* LÖVE framework.",
|
|
||||||
cache = {}
|
|
||||||
}
|
|
||||||
|
|
||||||
local path = (...):gsub('%.init$', '') .. "."
|
|
||||||
local Map = require(path .. "map")
|
|
||||||
|
|
||||||
--- Instance a new map.
|
|
||||||
-- @param path Path to the map file.
|
|
||||||
-- @param plugins A list of plugins to load.
|
|
||||||
-- @param ox Offset of map on the X axis (in pixels)
|
|
||||||
-- @param oy Offset of map on the Y axis (in pixels)
|
|
||||||
-- @return table The loaded Map.
|
|
||||||
function STI.new(map, plugins, ox, oy)
|
|
||||||
-- Check for valid map type
|
|
||||||
local ext = map:sub(-4, -1)
|
|
||||||
assert(ext == ".lua", string.format(
|
|
||||||
"Invalid file type: %s. File must be of type: lua.",
|
|
||||||
ext
|
|
||||||
))
|
|
||||||
|
|
||||||
-- Get path to map
|
|
||||||
local path = map:reverse():find("[/\\]") or ""
|
|
||||||
if path ~= "" then
|
|
||||||
path = map:sub(1, 1 + (#map - path))
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Load map
|
|
||||||
map = love.filesystem.load(map)
|
|
||||||
setfenv(map, {})
|
|
||||||
map = setmetatable(map(), {__index = Map})
|
|
||||||
|
|
||||||
map:init(STI, path, plugins, ox, oy)
|
|
||||||
|
|
||||||
return map
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Flush image cache.
|
|
||||||
function STI:flush()
|
|
||||||
self.cache = {}
|
|
||||||
end
|
|
||||||
|
|
||||||
return STI
|
|
||||||
Vendored
-1388
File diff suppressed because it is too large
Load Diff
Vendored
-349
@@ -1,349 +0,0 @@
|
|||||||
--- Box2D plugin for STI
|
|
||||||
-- @module box2d
|
|
||||||
-- @author Landon Manning
|
|
||||||
-- @copyright 2015
|
|
||||||
-- @license MIT/X11
|
|
||||||
|
|
||||||
return {
|
|
||||||
box2d_LICENSE = "MIT/X11",
|
|
||||||
box2d_URL = "https://github.com/karai17/Simple-Tiled-Implementation",
|
|
||||||
box2d_VERSION = "2.3.2.1",
|
|
||||||
box2d_DESCRIPTION = "Box2D hooks for STI.",
|
|
||||||
|
|
||||||
--- Initialize Box2D physics world.
|
|
||||||
-- @param world The Box2D world to add objects to.
|
|
||||||
-- @return nil
|
|
||||||
box2d_init = function(map, world)
|
|
||||||
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 collision = {
|
|
||||||
body = body,
|
|
||||||
}
|
|
||||||
|
|
||||||
local function convertEllipseToPolygon(x, y, w, h, max_segments)
|
|
||||||
local function calc_segments(segments)
|
|
||||||
local function vdist(a, b)
|
|
||||||
local c = {
|
|
||||||
x = a.x - b.x,
|
|
||||||
y = a.y - b.y,
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.x * c.x + c.y * c.y
|
|
||||||
end
|
|
||||||
|
|
||||||
segments = segments or 64
|
|
||||||
local vertices = {}
|
|
||||||
|
|
||||||
local v = { 1, 2, math.ceil(segments/4-1), math.ceil(segments/4) }
|
|
||||||
|
|
||||||
local m
|
|
||||||
if love.physics then
|
|
||||||
m = love.physics.getMeter()
|
|
||||||
else
|
|
||||||
m = 32
|
|
||||||
end
|
|
||||||
|
|
||||||
for _, i in ipairs(v) do
|
|
||||||
local angle = (i / segments) * math.pi * 2
|
|
||||||
local px = x + w / 2 + math.cos(angle) * w / 2
|
|
||||||
local py = y + h / 2 + math.sin(angle) * h / 2
|
|
||||||
|
|
||||||
table.insert(vertices, { x = px / m, y = py / m })
|
|
||||||
end
|
|
||||||
|
|
||||||
local dist1 = vdist(vertices[1], vertices[2])
|
|
||||||
local dist2 = vdist(vertices[3], vertices[4])
|
|
||||||
|
|
||||||
-- Box2D threshold
|
|
||||||
if dist1 < 0.0025 or dist2 < 0.0025 then
|
|
||||||
return calc_segments(segments-2)
|
|
||||||
end
|
|
||||||
|
|
||||||
return segments
|
|
||||||
end
|
|
||||||
|
|
||||||
local segments = calc_segments(max_segments)
|
|
||||||
local vertices = {}
|
|
||||||
|
|
||||||
table.insert(vertices, { x = x + w / 2, y = y + h / 2 })
|
|
||||||
|
|
||||||
for i=0, segments do
|
|
||||||
local angle = (i / segments) * math.pi * 2
|
|
||||||
local px = x + w / 2 + math.cos(angle) * w / 2
|
|
||||||
local py = y + h / 2 + math.sin(angle) * h / 2
|
|
||||||
|
|
||||||
table.insert(vertices, { x = px, y = py })
|
|
||||||
end
|
|
||||||
|
|
||||||
return vertices
|
|
||||||
end
|
|
||||||
|
|
||||||
local function rotateVertex(v, x, y, cos, sin, oy)
|
|
||||||
oy = oy or 0
|
|
||||||
|
|
||||||
local vertex = {
|
|
||||||
x = v.x,
|
|
||||||
y = v.y - oy,
|
|
||||||
}
|
|
||||||
|
|
||||||
vertex.x = vertex.x - x
|
|
||||||
vertex.y = vertex.y - y
|
|
||||||
|
|
||||||
local vx = cos * vertex.x - sin * vertex.y
|
|
||||||
local vy = sin * vertex.x + cos * vertex.y
|
|
||||||
|
|
||||||
return vx + x, vy + y + oy
|
|
||||||
end
|
|
||||||
|
|
||||||
local function addObjectToWorld(objshape, vertices, userdata, object)
|
|
||||||
local shape
|
|
||||||
|
|
||||||
if objshape == "polyline" then
|
|
||||||
shape = love.physics.newChainShape(false, unpack(vertices))
|
|
||||||
else
|
|
||||||
shape = love.physics.newPolygonShape(unpack(vertices))
|
|
||||||
end
|
|
||||||
|
|
||||||
local fixture = love.physics.newFixture(body, shape)
|
|
||||||
|
|
||||||
fixture:setUserData(userdata)
|
|
||||||
|
|
||||||
if userdata.properties.sensor == "true" then
|
|
||||||
fixture:setSensor(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
local obj = {
|
|
||||||
object = object,
|
|
||||||
shape = shape,
|
|
||||||
fixture = fixture,
|
|
||||||
}
|
|
||||||
|
|
||||||
table.insert(collision, obj)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function getPolygonVertices(object)
|
|
||||||
local vertices = {}
|
|
||||||
for _, vertex in ipairs(object.polygon) do
|
|
||||||
table.insert(vertices, vertex.x)
|
|
||||||
table.insert(vertices, vertex.y)
|
|
||||||
end
|
|
||||||
|
|
||||||
return vertices
|
|
||||||
end
|
|
||||||
|
|
||||||
local function calculateObjectPosition(object, tile)
|
|
||||||
local o = {
|
|
||||||
shape = object.shape,
|
|
||||||
x = object.dx or object.x,
|
|
||||||
y = object.dy or object.y,
|
|
||||||
w = object.width,
|
|
||||||
h = object.height,
|
|
||||||
polygon = object.polygon or object.polyline or object.ellipse or object.rectangle
|
|
||||||
}
|
|
||||||
|
|
||||||
local userdata = {
|
|
||||||
object = o,
|
|
||||||
properties = object.properties
|
|
||||||
}
|
|
||||||
|
|
||||||
if o.shape == "rectangle" then
|
|
||||||
o.r = object.rotation or 0
|
|
||||||
local cos = math.cos(math.rad(o.r))
|
|
||||||
local sin = math.sin(math.rad(o.r))
|
|
||||||
local oy = 0
|
|
||||||
|
|
||||||
if object.gid then
|
|
||||||
local tileset = map.tilesets[map.tiles[object.gid].tileset]
|
|
||||||
local lid = object.gid - tileset.firstgid
|
|
||||||
local tile = {}
|
|
||||||
|
|
||||||
-- This fixes a height issue
|
|
||||||
o.y = o.y + map.tiles[object.gid].offset.y
|
|
||||||
oy = tileset.tileheight
|
|
||||||
|
|
||||||
for _, t in ipairs(tileset.tiles) do
|
|
||||||
if t.id == lid then
|
|
||||||
tile = t
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if tile.objectGroup then
|
|
||||||
for _, obj in ipairs(tile.objectGroup.objects) do
|
|
||||||
-- Every object in the tile
|
|
||||||
calculateObjectPosition(obj, object)
|
|
||||||
end
|
|
||||||
|
|
||||||
return
|
|
||||||
else
|
|
||||||
o.w = map.tiles[object.gid].width
|
|
||||||
o.h = map.tiles[object.gid].height
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
o.polygon = {
|
|
||||||
{ 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+o.h },
|
|
||||||
{ x=o.x+0, y=o.y+o.h },
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, vertex in ipairs(o.polygon) do
|
|
||||||
if map.orientation == "isometric" then
|
|
||||||
vertex.x, vertex.y = map:convertIsometricToScreen(vertex.x, vertex.y)
|
|
||||||
end
|
|
||||||
|
|
||||||
vertex.x, vertex.y = rotateVertex(vertex, o.x, o.y, cos, sin, oy)
|
|
||||||
end
|
|
||||||
|
|
||||||
local vertices = getPolygonVertices(o)
|
|
||||||
addObjectToWorld(o.shape, vertices, userdata, tile or object)
|
|
||||||
elseif o.shape == "ellipse" then
|
|
||||||
if not o.polygon then
|
|
||||||
o.polygon = convertEllipseToPolygon(o.x, o.y, o.w, o.h)
|
|
||||||
end
|
|
||||||
local vertices = getPolygonVertices(o)
|
|
||||||
local triangles = love.math.triangulate(vertices)
|
|
||||||
|
|
||||||
for _, triangle in ipairs(triangles) do
|
|
||||||
addObjectToWorld(o.shape, triangle, userdata, tile or object)
|
|
||||||
end
|
|
||||||
elseif o.shape == "polygon" then
|
|
||||||
local vertices = getPolygonVertices(o)
|
|
||||||
local triangles = love.math.triangulate(vertices)
|
|
||||||
|
|
||||||
for _, triangle in ipairs(triangles) do
|
|
||||||
addObjectToWorld(o.shape, triangle, userdata, tile or object)
|
|
||||||
end
|
|
||||||
elseif o.shape == "polyline" then
|
|
||||||
local vertices = getPolygonVertices(o)
|
|
||||||
addObjectToWorld(o.shape, vertices, userdata, tile or object)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
for _, tile in pairs(map.tiles) do
|
|
||||||
local tileset = map.tilesets[tile.tileset]
|
|
||||||
|
|
||||||
-- Every object in every instance of a tile
|
|
||||||
if tile.objectGroup then
|
|
||||||
if map.tileInstances[tile.gid] then
|
|
||||||
for _, instance in ipairs(map.tileInstances[tile.gid]) do
|
|
||||||
for _, object in ipairs(tile.objectGroup.objects) do
|
|
||||||
object.dx = object.x + instance.x
|
|
||||||
object.dy = object.y + instance.y
|
|
||||||
calculateObjectPosition(object, instance)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Every instance of a tile
|
|
||||||
elseif tile.properties and tile.properties.collidable == "true" and map.tileInstances[tile.gid] then
|
|
||||||
for _, instance in ipairs(map.tileInstances[tile.gid]) do
|
|
||||||
local object = {
|
|
||||||
shape = "rectangle",
|
|
||||||
x = instance.x,
|
|
||||||
y = instance.y,
|
|
||||||
width = tileset.tilewidth,
|
|
||||||
height = tileset.tileheight,
|
|
||||||
properties = tile.properties
|
|
||||||
}
|
|
||||||
|
|
||||||
calculateObjectPosition(object, instance)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
for _, layer in ipairs(map.layers) do
|
|
||||||
-- Entire layer
|
|
||||||
if layer.properties.collidable == "true" then
|
|
||||||
if layer.type == "tilelayer" then
|
|
||||||
for gid, tiles in pairs(map.tileInstances) do
|
|
||||||
local tile = map.tiles[gid]
|
|
||||||
local tileset = map.tilesets[tile.tileset]
|
|
||||||
|
|
||||||
for _, instance in ipairs(tiles) do
|
|
||||||
if instance.layer == layer then
|
|
||||||
local object = {
|
|
||||||
shape = "rectangle",
|
|
||||||
x = instance.x,
|
|
||||||
y = instance.y,
|
|
||||||
width = tileset.tilewidth,
|
|
||||||
height = tileset.tileheight,
|
|
||||||
properties = tile.properties
|
|
||||||
}
|
|
||||||
|
|
||||||
calculateObjectPosition(object, instance)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elseif layer.type == "objectgroup" then
|
|
||||||
for _, object in ipairs(layer.objects) do
|
|
||||||
calculateObjectPosition(object)
|
|
||||||
end
|
|
||||||
elseif layer.type == "imagelayer" then
|
|
||||||
local object = {
|
|
||||||
shape = "rectangle",
|
|
||||||
x = layer.x or 0,
|
|
||||||
y = layer.y or 0,
|
|
||||||
width = layer.width,
|
|
||||||
height = layer.height,
|
|
||||||
properties = layer.properties
|
|
||||||
}
|
|
||||||
|
|
||||||
calculateObjectPosition(object)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Individual objects
|
|
||||||
if layer.type == "objectgroup" then
|
|
||||||
for _, object in ipairs(layer.objects) do
|
|
||||||
if object.properties.collidable == "true" then
|
|
||||||
calculateObjectPosition(object)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
map.box2d_collision = collision
|
|
||||||
end,
|
|
||||||
|
|
||||||
--- Remove Box2D fixtures and shapes from world.
|
|
||||||
-- @param index The index or name of the layer being removed
|
|
||||||
-- @return nil
|
|
||||||
box2d_removeLayer = function(map, index)
|
|
||||||
local layer = assert(map.layers[index], "Layer not found: " .. index)
|
|
||||||
local collision = map.box2d_collision
|
|
||||||
|
|
||||||
-- Remove collision objects
|
|
||||||
for i=#collision, 1, -1 do
|
|
||||||
local obj = collision[i]
|
|
||||||
|
|
||||||
if obj.object.layer == layer then
|
|
||||||
obj.fixture:destroy()
|
|
||||||
table.remove(collision, i)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
|
|
||||||
--- Draw Box2D physics world.
|
|
||||||
-- @return nil
|
|
||||||
box2d_draw = function(map)
|
|
||||||
local collision = map.box2d_collision
|
|
||||||
|
|
||||||
for _, obj in ipairs(collision) do
|
|
||||||
local points = {collision.body:getWorldPoints(obj.shape:getPoints())}
|
|
||||||
|
|
||||||
if #points == 4 then
|
|
||||||
love.graphics.line(points)
|
|
||||||
else
|
|
||||||
love.graphics.polygon("line", points)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
}
|
|
||||||
|
|
||||||
--- Custom Properties in Tiled are used to tell this plugin what to do.
|
|
||||||
-- @table Properties
|
|
||||||
-- @field collidable set to "true", can be used on any Layer, Tile, or Object
|
|
||||||
-- @field sensor set to "true", can be used on any Tile or Object that is also collidable
|
|
||||||
Vendored
-103
@@ -1,103 +0,0 @@
|
|||||||
--- Bump.lua plugin for STI
|
|
||||||
-- @module bump.lua
|
|
||||||
-- @author David Serrano (BobbyJones|FrenchFryLord)
|
|
||||||
-- @copyright 2016
|
|
||||||
-- @license MIT/X11
|
|
||||||
|
|
||||||
return {
|
|
||||||
|
|
||||||
bump_LICENSE = "MIT/X11",
|
|
||||||
bump_URL = "https://github.com/karai17/Simple-Tiled-Implementation",
|
|
||||||
bump_VERSION = "3.1.5.2",
|
|
||||||
bump_DESCRIPTION = "Bump hooks for STI.",
|
|
||||||
|
|
||||||
|
|
||||||
--- Adds each collidable tile to the Bump world.
|
|
||||||
-- @param world The Bump world to add objects to.
|
|
||||||
-- @return collidables table containing the handles to the objects in the Bump world.
|
|
||||||
bump_init = function(map, world)
|
|
||||||
|
|
||||||
local collidables = {}
|
|
||||||
|
|
||||||
for _, tileset in ipairs(map.tilesets) do
|
|
||||||
for _, tile in ipairs(tileset.tiles) do
|
|
||||||
local gid = tileset.firstgid + tile.id
|
|
||||||
-- Every object in every instance of a tile
|
|
||||||
if tile.properties and tile.properties.collidable == "true" and map.tileInstances[gid] then
|
|
||||||
for _, instance in ipairs(map.tileInstances[gid]) do
|
|
||||||
local t = {properties = tile.properties, x = instance.x + map.offsetx, y = instance.y + map.offsety, width = map.tilewidth, height = map.tileheight, layer = instance.layer }
|
|
||||||
world:add(t, t.x,t.y, t.width,t.height)
|
|
||||||
table.insert(collidables,t)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
for _, layer in ipairs(map.layers) do
|
|
||||||
-- Entire layer
|
|
||||||
if layer.properties.collidable == "true" then
|
|
||||||
if layer.type == "tilelayer" then
|
|
||||||
for y, tiles in ipairs(layer.data) do
|
|
||||||
for x, tile in pairs(tiles) do
|
|
||||||
local t = {properties = tile.properties, x = x * map.tilewidth + tile.offset.x + map.offsetx, y = y * map.tileheight + tile.offset.y + map.offsety, width = tile.width, height = tile.height, layer = layer }
|
|
||||||
world:add(t, t.x,t.y, t.width,t.height )
|
|
||||||
table.insert(collidables,t)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elseif layer.type == "imagelayer" then
|
|
||||||
world:add(layer, layer.x,layer.y, layer.width,layer.height)
|
|
||||||
table.insert(collidables,layer)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- individual collidable objects in a layer that is not "collidable"
|
|
||||||
-- or whole collidable objects layer
|
|
||||||
if layer.type == "objectgroup" then
|
|
||||||
for _, obj in ipairs(layer.objects) do
|
|
||||||
if (layer.properties and layer.properties.collidable == "true")
|
|
||||||
or (obj.properties and obj.properties.collidable == "true") then
|
|
||||||
if obj.shape == "rectangle" then
|
|
||||||
local t = {properties = obj.properties, x = obj.x, y = obj.y, width = obj.width, height = obj.height, type = obj.type, name = obj.name, id = obj.id, gid = obj.gid, layer = layer }
|
|
||||||
if obj.gid then t.y = t.y - obj.height end
|
|
||||||
world:add(t, t.x,t.y, t.width,t.height )
|
|
||||||
table.insert(collidables,t)
|
|
||||||
end -- TODO implement other object shapes?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
map.bump_collidables = collidables
|
|
||||||
end,
|
|
||||||
|
|
||||||
--- Remove layer
|
|
||||||
-- @params index to layer to be removed
|
|
||||||
-- @params world bump world the holds the tiles
|
|
||||||
-- @return nil
|
|
||||||
bump_removeLayer = function(map, index, world)
|
|
||||||
local layer = assert(map.layers[index], "Layer not found: " .. index)
|
|
||||||
local collidables = map.bump_collidables
|
|
||||||
|
|
||||||
-- Remove collision objects
|
|
||||||
for i=#collidables, 1, -1 do
|
|
||||||
local obj = collidables[i]
|
|
||||||
|
|
||||||
if obj.layer == layer
|
|
||||||
and (
|
|
||||||
layer.properties.collidable == "true"
|
|
||||||
or obj.properties.collidable == "true"
|
|
||||||
) then
|
|
||||||
world:remove(obj)
|
|
||||||
table.remove(collidables, i)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
|
|
||||||
--- Draw bump collisions world.
|
|
||||||
-- @params world bump world holding the tiles geometry
|
|
||||||
-- @return nil
|
|
||||||
bump_draw = function(map, world)
|
|
||||||
for k,collidable in pairs(map.bump_collidables) do
|
|
||||||
love.graphics.rectangle("line",world:getRect(collidable))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
}
|
|
||||||
@@ -1,372 +1,52 @@
|
|||||||
require "lib/postshader"
|
local game = require 'assets/scripts/game'
|
||||||
local LightWorld = require "lib"
|
local stages = require 'assets/scripts/stages'
|
||||||
local ProFi = require 'game.vendor.ProFi'
|
local controls = require 'assets/scripts/controls'
|
||||||
|
local bells = require 'assets/scripts/bells'
|
||||||
exf = {}
|
local camera = require 'assets/scripts/camera'
|
||||||
exf.current = nil
|
local stress = require 'assets/scripts/stress'
|
||||||
|
local messages = require 'assets/scripts/messages'
|
||||||
exf.available = {}
|
local start = require 'assets/scripts/start'
|
||||||
|
|
||||||
|
-- LOAD
|
||||||
function love.load()
|
function love.load()
|
||||||
exf.list = List:new()
|
game.load()
|
||||||
exf.smallfont = love.graphics.newFont(12)
|
camera.load(game)
|
||||||
exf.mediumfont = love.graphics.newFont(18)
|
stages.load(game, camera)
|
||||||
exf.bigfont = love.graphics.newFont(40)
|
stress.load(game, camera)
|
||||||
exf.list.font = exf.smallfont
|
bells.load(game, camera)
|
||||||
|
controls.load(game)
|
||||||
|
messages.load(game)
|
||||||
|
start.load(game)
|
||||||
|
end
|
||||||
|
|
||||||
exf.bigball = love.graphics.newImage("game/gfx/not-estudio.png")
|
-- UPDATE
|
||||||
exf.music = love.audio.newSource("assets/audio/music/theme.mp3", "static")
|
function love.update(dt)
|
||||||
exf.music:setVolume(0.9) -- 90% of ordinary volume
|
--require('assets/scripts/vendor/lovebird').update()
|
||||||
exf.music:setPitch(0.5) -- one octave lower
|
game.world:update(dt)
|
||||||
exf:playMusic()
|
game.update(dt)
|
||||||
-- Find available demos.
|
camera.update(game)
|
||||||
local files = love.filesystem.getDirectoryItems("game")
|
stages.update(dt, game, camera)
|
||||||
local n = 0
|
stress.update(dt, game, camera)
|
||||||
|
bells.update(dt, game, camera)
|
||||||
|
controls.update(dt, game, camera)
|
||||||
|
messages.update(dt, game)
|
||||||
|
start.update(dt, game)
|
||||||
|
end
|
||||||
|
|
||||||
for i, v in ipairs(files) do
|
-- DRAW
|
||||||
is_file = love.filesystem.isFile("game/".. v )
|
function love.draw()
|
||||||
if is_file then
|
camera.gcam:draw(
|
||||||
n = n + 1
|
function(l,t,w,h)
|
||||||
table.insert(exf.available, v);
|
stages.draw()
|
||||||
local file = love.filesystem.newFile(v, love.file_read)
|
stress.draw()
|
||||||
file:open("r")
|
bells.draw(game)
|
||||||
local contents = love.filesystem.read("game/" .. v, 100)
|
|
||||||
local s, e, c = string.find(contents, "Example: ([%a%p ]-)[\r\n]")
|
|
||||||
file:close(file)
|
|
||||||
if not c then c = "Untitled" end
|
|
||||||
local title = " Inicia la Aventura!"
|
|
||||||
exf.list:add(title, v)
|
|
||||||
end
|
end
|
||||||
end
|
)
|
||||||
|
controls.draw()
|
||||||
exf.list:done()
|
messages.draw()
|
||||||
exf.resume()
|
start.draw(game)
|
||||||
end
|
end
|
||||||
|
|
||||||
function love.update(dt) end
|
function love.mousepressed(x, y, button, istouch)
|
||||||
function love.draw() end
|
start.mousepressed(game)
|
||||||
function love.keypressed(k) end
|
|
||||||
function love.keyreleased(k) end
|
|
||||||
function love.mousepressed(x, y, b) end
|
|
||||||
function love.mousereleased(x, y, b) end
|
|
||||||
function exf.empty() end
|
|
||||||
|
|
||||||
function exf.update(dt)
|
|
||||||
exf.list:update(dt)
|
|
||||||
lightMouse:setPosition(love.mouse.getX(), love.mouse.getY())
|
|
||||||
end
|
|
||||||
|
|
||||||
function exf.draw()
|
|
||||||
lightWorld:draw(function()
|
|
||||||
love.graphics.setBackgroundColor(0, 0, 0)
|
|
||||||
|
|
||||||
love.graphics.setColor(10, 110,110)
|
|
||||||
love.graphics.rectangle("fill", 0, 0, love.graphics.getWidth(), love.graphics.getHeight())
|
|
||||||
|
|
||||||
love.graphics.setColor(255, 255, 255, 191)
|
|
||||||
love.graphics.setFont(exf.bigfont)
|
|
||||||
love.graphics.print("Shall I Kill Her", 500, 50)
|
|
||||||
|
|
||||||
love.graphics.setFont(exf.mediumfont)
|
|
||||||
love.graphics.print("Un hombre atormentado por oscuros sentimientos de debate", 380, 140)
|
|
||||||
love.graphics.print("entre el bien y el mal. Debe tomar la decisión entre matar o no a ", 360, 160)
|
|
||||||
love.graphics.print("su actual pareja. Para ello recorre sus recuerdos en busca de una razón.", 335, 180)
|
|
||||||
exf.list:draw()
|
|
||||||
|
|
||||||
love.graphics.setColor(255, 255, 255)
|
|
||||||
love.graphics.draw(exf.bigball, 760 - 128, 600 - 128, love.timer.getTime(), 1, 1, exf.bigball:getWidth() * 0.5, exf.bigball:getHeight() * 0.5)
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
function exf.keypressed(k)
|
|
||||||
end
|
|
||||||
|
|
||||||
function exf.keyreleased(k)
|
|
||||||
end
|
|
||||||
|
|
||||||
function exf.mousepressed(x, y, b)
|
|
||||||
exf.list:mousepressed(x, y, b)
|
|
||||||
end
|
|
||||||
|
|
||||||
function exf.mousereleased(x, y, b)
|
|
||||||
exf.list:mousereleased(x, y, b)
|
|
||||||
end
|
|
||||||
|
|
||||||
function exf.intable(t, e)
|
|
||||||
for k, v in ipairs(t) do
|
|
||||||
if v == e then return true end
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
function exf.start(item, file)
|
|
||||||
local e_id = string.sub(item, 1, 4)
|
|
||||||
local e_rest = string.sub(item, 5)
|
|
||||||
local unused1, unused2, n = string.find(item, "(%s)%.lua")
|
|
||||||
exf:stopMusic()
|
|
||||||
if exf.intable(exf.available, file) then
|
|
||||||
if not love.filesystem.exists("game/" .. file) then
|
|
||||||
print("Could not load game .. " .. file)
|
|
||||||
else
|
|
||||||
|
|
||||||
-- Clear all callbacks.
|
|
||||||
love.load = exf.empty
|
|
||||||
love.update = exf.empty
|
|
||||||
love.draw = exf.empty
|
|
||||||
love.keypressed = exf.empty
|
|
||||||
love.keyreleased = exf.empty
|
|
||||||
love.mousepressed = exf.empty
|
|
||||||
love.mousereleased = exf.empty
|
|
||||||
|
|
||||||
love.filesystem.load("game/" .. file)()
|
|
||||||
exf.clear()
|
|
||||||
|
|
||||||
--love.window.setTitle(e_rest)
|
|
||||||
|
|
||||||
-- Redirect keypress
|
|
||||||
local o_keypressed = love.keypressed
|
|
||||||
love.keypressed =
|
|
||||||
function(k)
|
|
||||||
if k == "escape" then
|
|
||||||
exf.resume()
|
|
||||||
end
|
|
||||||
o_keypressed(k)
|
|
||||||
end
|
|
||||||
|
|
||||||
love.load()
|
|
||||||
end
|
|
||||||
else
|
|
||||||
print("Game ".. e_id .. " does not exist.")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function exf.clear()
|
|
||||||
love.graphics.setBackgroundColor(0,0,0)
|
|
||||||
love.graphics.setColor(255, 255, 255)
|
|
||||||
love.graphics.setLineWidth(1)
|
|
||||||
love.graphics.setLineStyle("smooth")
|
|
||||||
love.graphics.setBlendMode("alpha")
|
|
||||||
love.mouse.setVisible(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
function exf.resume()
|
|
||||||
|
|
||||||
load = nil
|
|
||||||
love.update = exf.update
|
|
||||||
love.draw = exf.draw
|
|
||||||
love.keypressed = exf.keypressed
|
|
||||||
love.keyreleased = exf.keyreleased
|
|
||||||
love.mousepressed = exf.mousepressed
|
|
||||||
love.mousereleased = exf.mousereleased
|
|
||||||
|
|
||||||
love.mouse.setVisible(true)
|
|
||||||
love.window.setTitle("Shall I Kill Her")
|
|
||||||
|
|
||||||
-- create light world
|
|
||||||
lightWorld = LightWorld({
|
|
||||||
ambient = {127, 127, 127}
|
|
||||||
})
|
|
||||||
|
|
||||||
-- create light
|
|
||||||
lightMouse = lightWorld:newLight(0, 0, 255, 127, 63, 500)
|
|
||||||
lightMouse:setSmooth(2)
|
|
||||||
|
|
||||||
-- create shadow bodys
|
|
||||||
circleTest = lightWorld:newCircle(760 - 128, 600 - 128, exf.bigball:getWidth()*0.5)
|
|
||||||
end
|
|
||||||
|
|
||||||
function inside(mx, my, x, y, w, h)
|
|
||||||
return mx >= x and mx <= (x+w) and my >= y and my <= (y+h)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
----------------------
|
|
||||||
-- List object
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
List = {}
|
|
||||||
|
|
||||||
function List:new()
|
|
||||||
o = {}
|
|
||||||
setmetatable(o, self)
|
|
||||||
self.__index = self
|
|
||||||
|
|
||||||
o.items = {}
|
|
||||||
o.files = {}
|
|
||||||
|
|
||||||
o.x = 520
|
|
||||||
o.y = 300
|
|
||||||
|
|
||||||
o.width = 220
|
|
||||||
o.height = 160
|
|
||||||
|
|
||||||
o.item_height = 23
|
|
||||||
o.sum_item_height = 0
|
|
||||||
|
|
||||||
o.bar_size = 20
|
|
||||||
o.bar_pos = 0
|
|
||||||
o.bar_max_pos = 0
|
|
||||||
o.bar_width = 15
|
|
||||||
o.bar_lock = nil
|
|
||||||
|
|
||||||
return o
|
|
||||||
end
|
|
||||||
|
|
||||||
function List:add(item, file)
|
|
||||||
table.insert(self.items, item)
|
|
||||||
table.insert(self.files, file)
|
|
||||||
end
|
|
||||||
|
|
||||||
function List:done()
|
|
||||||
self.items.n = #self.items
|
|
||||||
|
|
||||||
-- Recalc bar size.
|
|
||||||
self.bar_pos = 0
|
|
||||||
|
|
||||||
local num_items = (self.height/self.item_height)
|
|
||||||
local ratio = num_items/self.items.n
|
|
||||||
self.bar_size = self.height * ratio
|
|
||||||
self.bar_max_pos = self.height - self.bar_size - 3
|
|
||||||
|
|
||||||
-- Calculate height of everything.
|
|
||||||
self.sum_item_height = (self.item_height+1) * self.items.n + 2
|
|
||||||
end
|
|
||||||
|
|
||||||
function List:hasBar()
|
|
||||||
return self.sum_item_height > self.height
|
|
||||||
end
|
|
||||||
|
|
||||||
function List:getBarRatio()
|
|
||||||
return self.bar_pos/self.bar_max_pos
|
|
||||||
end
|
|
||||||
|
|
||||||
function List:getOffset()
|
|
||||||
local ratio = self.bar_pos/self.bar_max_pos
|
|
||||||
return math.floor((self.sum_item_height-self.height)*ratio + 0.5)
|
|
||||||
end
|
|
||||||
|
|
||||||
function List:update(dt)
|
|
||||||
if self.bar_lock then
|
|
||||||
local dy = math.floor(love.mouse.getY()-self.bar_lock.y+0.5)
|
|
||||||
self.bar_pos = self.bar_pos + dy
|
|
||||||
|
|
||||||
if self.bar_pos < 0 then
|
|
||||||
self.bar_pos = 0
|
|
||||||
elseif self.bar_pos > self.bar_max_pos then
|
|
||||||
self.bar_pos = self.bar_max_pos
|
|
||||||
end
|
|
||||||
|
|
||||||
self.bar_lock.y = love.mouse.getY()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function List:mousepressed(mx, my, b)
|
|
||||||
if self:hasBar() then
|
|
||||||
if b == 1 then
|
|
||||||
local x, y, w, h = self:getBarRect()
|
|
||||||
if inside(mx, my, x, y, w, h) then
|
|
||||||
self.bar_lock = { x = mx, y = my }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local per_pixel = (self.sum_item_height-self.height)/self.bar_max_pos
|
|
||||||
local bar_pixel_dt = math.floor(((self.item_height)*3)/per_pixel + 0.5)
|
|
||||||
|
|
||||||
if b == "wd" then
|
|
||||||
self.bar_pos = self.bar_pos + bar_pixel_dt
|
|
||||||
if self.bar_pos > self.bar_max_pos then
|
|
||||||
self.bar_pos = self.bar_max_pos
|
|
||||||
end
|
|
||||||
elseif b == "wu" then
|
|
||||||
self.bar_pos = self.bar_pos - bar_pixel_dt
|
|
||||||
if self.bar_pos < 0 then
|
|
||||||
self.bar_pos = 0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if b == 1 and inside(mx, my, self.x+2, self.y+1, self.width-3, self.height-3) then
|
|
||||||
local tx, ty = mx-self.x, my + self:getOffset() - self.y
|
|
||||||
local index = math.floor((ty/self.sum_item_height)*self.items.n)
|
|
||||||
local i = self.items[index+1]
|
|
||||||
local f = self.files[index+1]
|
|
||||||
if f then
|
|
||||||
exf.start(i, f)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function List:mousereleased(x, y, b)
|
|
||||||
if self:hasBar() then
|
|
||||||
if b == 1 then
|
|
||||||
self.bar_lock = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function List:getBarRect()
|
|
||||||
return self.x+self.width+2, self.y+1+self.bar_pos,
|
|
||||||
self.bar_width-3, self.bar_size
|
|
||||||
end
|
|
||||||
|
|
||||||
function List:getItemRect(i)
|
|
||||||
return self.x+2, self.y+((self.item_height+1)*(i-1)+1)-self:getOffset(),
|
|
||||||
self.width-3, self.item_height
|
|
||||||
end
|
|
||||||
|
|
||||||
function List:draw()
|
|
||||||
love.graphics.setLineWidth(2)
|
|
||||||
love.graphics.setLineStyle("rough")
|
|
||||||
love.graphics.setFont(self.font)
|
|
||||||
|
|
||||||
love.graphics.setColor(48, 156, 225)
|
|
||||||
|
|
||||||
local mx, my = love.mouse.getPosition()
|
|
||||||
|
|
||||||
-- Get interval to display.
|
|
||||||
local start_i = math.floor( self:getOffset()/(self.item_height+1) ) + 1
|
|
||||||
local end_i = start_i+math.floor( self.height/(self.item_height+1) ) + 1
|
|
||||||
|
|
||||||
if end_i > self.items.n then
|
|
||||||
end_i = self.items.n
|
|
||||||
end
|
|
||||||
|
|
||||||
love.graphics.setScissor(self.x, self.y, self.width, self.height)
|
|
||||||
|
|
||||||
-- Items.
|
|
||||||
for i = start_i,end_i do
|
|
||||||
local x, y, w, h = self:getItemRect(i)
|
|
||||||
local hover = inside(mx, my, x, y, w, h)
|
|
||||||
|
|
||||||
if hover then
|
|
||||||
love.graphics.setColor(0, 0, 0, 127)
|
|
||||||
else
|
|
||||||
love.graphics.setColor(0, 0, 0, 63)
|
|
||||||
end
|
|
||||||
|
|
||||||
love.graphics.rectangle("fill", x+1, y+i+1, w-3, h)
|
|
||||||
|
|
||||||
if hover then
|
|
||||||
love.graphics.setColor(255, 255, 255)
|
|
||||||
else
|
|
||||||
love.graphics.setColor(255, 255, 255, 127)
|
|
||||||
end
|
|
||||||
|
|
||||||
local e_id = string.sub(self.items[i], 1, 5)
|
|
||||||
local e_rest = string.sub(self.items[i], 5)
|
|
||||||
|
|
||||||
love.graphics.print(e_id, x+10, y+i+6) --Updated y placement -- Used to change position of Example IDs
|
|
||||||
love.graphics.print(e_rest, x+50, y+i+6) --Updated y placement -- Used to change position of Example Titles
|
|
||||||
end
|
|
||||||
|
|
||||||
love.graphics.setScissor()
|
|
||||||
|
|
||||||
|
|
||||||
end
|
|
||||||
function exf:playMusic()
|
|
||||||
exf.music:play()
|
|
||||||
end
|
|
||||||
|
|
||||||
function exf:stopMusic()
|
|
||||||
exf.music:stop()
|
|
||||||
end
|
end
|
||||||
Reference in New Issue
Block a user