diff --git a/.vscode/settings.json b/.vscode/settings.json index 53fd123..c8988a9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,5 +8,8 @@ "core", "scenes", "game" + ], + "Lua.diagnostics.disable": [ + "redundant-parameter" ] } diff --git a/CHANGELOG.md b/CHANGELOG.md index c008a23..093dc08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased -- Project renamed to Birb +- Project renamed to Birb and rebased entirely on Sonic Radiance codebase - New loading system diff --git a/README.md b/README.md index 2a84206..ffadc57 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # Birb Love2D Engine -Birb aim to be an integrated, simple engine for love2D. It aim to work as a set of managers to automatically handle inputs, screen, and several utilities to make game developpement easier and less repetitive. +Birb aim to be an integrated, simple engine for love2D, in replacement of my old "gamecore" love2D engine. It aim to work as a set of managers to automatically handle inputs, screen, and several utilities to make game developpement easier and less repetitive. It's also specialized in game with RPG mechanics, with functions to serialize/deserialize easily datas. Birb use [Classic](https://github.com/rxi/classic/) as its base Object. -## How to load GameCore +## How to load Birb The birb engine must be located in the `birb/` folder to work. After that, all you have to do is to load a gamecore based engine and then. diff --git a/birb/callbacks.lua b/birb/callbacks.lua index 39fe422..30d4463 100644 --- a/birb/callbacks.lua +++ b/birb/callbacks.lua @@ -23,19 +23,22 @@ function love.update(dt) core:update(dt) + if (game ~= nil) then + game:update(dt) + end end function love.draw() core:draw() end -function love.mousemoved(x, y, dx, dy) - core:mousemoved(x, y, dx, dy) -end +-- function love.mousemoved(x, y, dx, dy) +-- core:mousemoved(x, y, dx, dy) +-- end -function love.mousepressed( x, y, button, istouch ) - core:mousepressed(x, y, button, istouch) -end +-- function love.mousepressed( x, y, button, istouch ) +-- core:mousepressed(x, y, button, istouch) +-- end function love.keypressed( key, scancode, isrepeat ) core:keypressed( key, scancode, isrepeat ) diff --git a/birb/objects/2D/indexedrect.lua b/birb/classes/2D/indexedrect.lua similarity index 97% rename from birb/objects/2D/indexedrect.lua rename to birb/classes/2D/indexedrect.lua index fe87245..7511046 100644 --- a/birb/objects/2D/indexedrect.lua +++ b/birb/classes/2D/indexedrect.lua @@ -23,7 +23,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ]] -local Rect = require "birb.objects.2D.rect" +local Rect = require "birb.classes.2D.rect" local IndexedRect = Rect:extend() function IndexedRect:new(origin, ox, oy, w, h) diff --git a/birb/objects/2D/point.lua b/birb/classes/2D/point.lua similarity index 100% rename from birb/objects/2D/point.lua rename to birb/classes/2D/point.lua diff --git a/birb/objects/2D/rect.lua b/birb/classes/2D/rect.lua similarity index 94% rename from birb/objects/2D/rect.lua rename to birb/classes/2D/rect.lua index 97fa54e..75e46f0 100644 --- a/birb/objects/2D/rect.lua +++ b/birb/classes/2D/rect.lua @@ -21,7 +21,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ]] -local Point = require "birb.objects.2D.point" +local Point = require "birb.classes.2D.point" local Rect = Point:extend() function Rect:new(x, y, w, h) @@ -67,6 +67,10 @@ function Rect:getRelativeCoordinate(dx, dy) return dx - self.x, dy - self.y end +function Rect:getDimensions() + return self.w, self.h +end + function Rect:drawBox() utils.graphics.box(self.x, self.y, self.w, self.h) end diff --git a/birb/objects/3D/box.lua b/birb/classes/3D/box.lua similarity index 96% rename from birb/objects/3D/box.lua rename to birb/classes/3D/box.lua index 8453374..904a1fe 100644 --- a/birb/objects/3D/box.lua +++ b/birb/classes/3D/box.lua @@ -21,7 +21,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ]] -local Point = require "birb.objects.3D.point3D" +local Point = require "birb.classes.3D.point3D" local Box = Point:extend() function Box:new(x, y, z, w, h, d) @@ -42,6 +42,7 @@ end function Box:getShape() local x, y, z, w, h, d = self:getArea() + return x, y-z-d, w, h+d end function Box:getCorners() diff --git a/birb/objects/3D/indexedbox.lua b/birb/classes/3D/indexedbox.lua similarity index 97% rename from birb/objects/3D/indexedbox.lua rename to birb/classes/3D/indexedbox.lua index 8ee36b2..e8b2857 100644 --- a/birb/objects/3D/indexedbox.lua +++ b/birb/classes/3D/indexedbox.lua @@ -23,7 +23,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ]] -local Rect = require "birb.objects.2D.rect" +local Rect = require "birb.classes.2D.rect" local IndexedRect = Rect:extend() function IndexedRect:new(origin, ox, oy, oz, w, h, d) diff --git a/birb/objects/3D/point3D.lua b/birb/classes/3D/point3D.lua similarity index 100% rename from birb/objects/3D/point3D.lua rename to birb/classes/3D/point3D.lua diff --git a/birb/classes/datapack.lua b/birb/classes/datapack.lua new file mode 100644 index 0000000..bfaf29b --- /dev/null +++ b/birb/classes/datapack.lua @@ -0,0 +1,121 @@ +-- datapack.lua :: a categorized and indexed pack of data. Aim to make easy to get +-- the category from an element, without having + +--[[ + Copyright © 2021 Kazhnuz + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +]] + +local DataPack = Object:extend() + +local UNCATEGORIZED = "uncategorized" + +function DataPack:new(foldername, categories, areFiles, subfiles) + self.foldername = foldername + self.areFiles = (areFiles ~= false) + self.subfiles = subfiles or {} + self.categories = categories or {} + --print("loading " .. foldername) + self:loadAllDatas() +end + +function DataPack:getBaseDirectory(lua) + local foldername = self.foldername + if (not lua) then + foldername = string.gsub(foldername, "%.", "/") + end + return utils.datas.concatDataFolder(foldername, lua) +end + +function DataPack:getCategoryDirectory(category, lua) + if (category == UNCATEGORIZED) then + return self:getBaseDirectory(lua) + else + return utils.datas.concatFolder(self:getBaseDirectory(lua), category, lua) + end +end + +function DataPack:haveCategories() + return (#self.categories > 0) +end + +function DataPack:loadAllDatas() + self.index = {} + self.reverseIndex = {} + + if (self:haveCategories()) then + for i, category in ipairs(self.categories) do + self:loadDatas(category) + end + else + self:loadDatas(UNCATEGORIZED) + end +end + +function DataPack:loadDatas(category) + local directory = self:getCategoryDirectory(category) + local items = love.filesystem.getDirectoryItems(directory) + self.reverseIndex[category] = {} + for i, filename in ipairs(items) do + if (utils.datas.isLuaFile(filename) == self.areFiles) then + if (self.areFiles) then + filename = utils.datas.luaFileToModule(filename) + end + + if (self.index[filename] ~= nil) then + error("Data " .. filename .. " already exists for " .. self.foldername) + end + --print("loading " .. filename .. " from category " .. category .. " for " .. self.foldername) + self.index[filename] = category + table.insert(self.reverseIndex[category], filename) + end + end +end + +function DataPack:dataExists(name) + return (self.index[name] ~= nil) +end + +function DataPack:getPath(name, lua) + if (not self:dataExists(name)) then + error("Data " .. name .. " do not exist for " .. self.foldername) + end + local category = self.index[name] + + local categoryDirectory = self:getCategoryDirectory(category, true) + + return utils.datas.concatFolder(categoryDirectory, name, lua) +end + +function DataPack:get(name) + local path = self:getPath(name, true) + local data = utils.datas.copy(path) + if (not self.areFiles) then + for i, subfile in ipairs(self.subfiles) do + data[subfile] = utils.datas.copyDataset(path, subfile) + end + end + return data +end + +function DataPack:getFromCategory(category) + return self.reverseIndex[category] or {} +end + +return DataPack diff --git a/birb/classes/parser.lua b/birb/classes/parser.lua new file mode 100644 index 0000000..8e674c6 --- /dev/null +++ b/birb/classes/parser.lua @@ -0,0 +1,63 @@ +-- parser.lua :: a data parser, used to parse data from arguments + +--[[ + Copyright © 2021 Kazhnuz + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +]] + +local Parser = Object:extend() + +function Parser:new(headings, argumentsList, argumentwrapper, nullableNbr) + self.headings = headings + self.argumentsList = argumentsList + self.argumentwrapper = argumentwrapper or "" + self.nullableNbr = nullableNbr or 0 +end + +function Parser:getArguments(name) + if (self.argumentsList[name] ~= nil) then + local arguments = {} + utils.table.mergeList(arguments, self.headings) + utils.table.mergeList(arguments, self.argumentsList[name]) + return arguments + else + error("No arguments data for argumentList " .. name) + end +end + +function Parser:parse(datas) + local arguments = self:getArguments(datas[1]) + --print(utils.table.toString(arguments)) + local parsedData = utils.table.parse(datas, arguments, self.nullableNbr) + if (utils.string.isEmpty(self.argumentwrapper)) then + -- print(utils.table.toString(parsedData)) + return parsedData + else + local finalTable = {} + for i, heading in ipairs(self.headings) do + finalTable[heading] = parsedData[heading] + parsedData[heading] = nil + end + finalTable[self.argumentwrapper] = parsedData + -- print(utils.table.toString(finalTable)) + return finalTable + end +end + +return Parser \ No newline at end of file diff --git a/birb/classes/predicate/init.lua b/birb/classes/predicate/init.lua new file mode 100644 index 0000000..26abbbb --- /dev/null +++ b/birb/classes/predicate/init.lua @@ -0,0 +1,115 @@ +-- classes/predicates :: a predicate system, to be an intermediary between condition +-- solvers and complex conditions. You simply create a predicate with your data and the +-- solver to create a predicate, then use the Predicate:solve() API to get your response + +-- To create a Predicate, prefer the Predicate.createPredicate instead of Predicate:new() +-- As it'll allow you to dynamically create simple or complex predicate on the fly +-- while Predicate:new() will try to create a complex predicate + +--[[ + Copyright © 2021 Kazhnuz + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +]] + +local Predicate = Object:extend() +local SimplePredicate = require "birb.classes.predicate.simple" + +function Predicate.createPredicate(data, solver, asker) + local predicate = nil + if (type(data) == "table") then + predicate = Predicate(data, solver, asker) + end + if (type(data) == "string") then + predicate = SimplePredicate(data, solver, asker) + end + + if (predicate ~= nil) then + return predicate + else + error("Predicate data aren't a table or a string : " .. tostring(data)) + end +end + +function Predicate:new(data ,solver, asker) + self.solver = solver + self.asker = asker + self.beginAt = 1 + self:setType(data) + self.notTag = false + self:setList(data) +end + +function Predicate:solve() + local predicateSolved + if (self.type == "or") then + predicateSolved = self:solveOr() + else + predicateSolved = self:solveAnd() + end + + if (self.notTag) then + predicateSolved = (predicateSolved == false) + end + + return predicateSolved +end + +-- INTERNAL FUNCTIONS +-- Handle the complex predicate + +function Predicate:setType(data) + self.type = "and" + if (type(data[1]) == "string") then + if (data[1] == "or") or (data[1] == "and") then + self.beginAt = 2 + self.type = data[1] + end + end +end + +function Predicate:setList(data) + self.list = {} + for i = self.beginAt, #data, 1 do + if (i == #data) and (data[i] == "not") then + self.notTag = true + else + table.insert(self.list, Predicate.createPredicate(data[i], self.solver, self.asker)) + end + end +end + +function Predicate:solveOr() + for i, predicate in ipairs(self.list) do + if (predicate:solve()) then + return true + end + end + return false +end + +function Predicate:solveAnd() + for i, predicate in ipairs(self.list) do + if (not predicate:solve()) then + return false + end + end + return true +end + +return Predicate \ No newline at end of file diff --git a/birb/classes/predicate/simple.lua b/birb/classes/predicate/simple.lua new file mode 100644 index 0000000..f342721 --- /dev/null +++ b/birb/classes/predicate/simple.lua @@ -0,0 +1,68 @@ +-- classes/simple :: the actual solver of the predicate system. It parse a condition +-- system, and pass the data to a solver function. If the last argument of a condition +-- is "not", it'll negate the whole condition. + +-- Each solver function will get as argument the list of conditions, the predicate and the +-- asker. The predicate contain an utility subclass with some function to handle easily +-- some stuff like converting truth tags or comparing numbers +-- An empty string will return true, a non-existing solver question an error, except if the solver have a +-- default function. + +--[[ + Copyright © 2021 Kazhnuz + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +]] + +local SimplePredicate = Object:extend() +local SEPARATOR = ":" +local NOT = "not" +local DEFAULT = "default" + +SimplePredicate.utils = require "birb.classes.predicate.utils" + +function SimplePredicate:new(data, solver, asker) + self.solver = solver + self.asker = asker + self.data = data +end + +function SimplePredicate:solve() + if (utils.string.isEmpty(self.data)) then + return true + end + local conditionArgs = utils.string.split(self.data, SEPARATOR) + local solverFunction = self:getFunction(conditionArgs[1]) + local conditionFulfilled = solverFunction(conditionArgs, self, self.asker) + if (conditionArgs[#conditionArgs] == NOT) then + conditionFulfilled = (not conditionFulfilled) + end + return conditionFulfilled +end + +function SimplePredicate:getFunction(functionName) + if (self.solver[functionName] == nil) then + if (self.solver[DEFAULT] == nil) then + error("Function " .. functionName .. " doesn't exist in solver, and it doesn't have a 'default' function.") + end + return self.solver[DEFAULT] + end + return self.solver[functionName] +end + +return SimplePredicate \ No newline at end of file diff --git a/birb/modules/timers/libs/timer.lua b/birb/classes/predicate/utils.lua similarity index 50% rename from birb/modules/timers/libs/timer.lua rename to birb/classes/predicate/utils.lua index 375ef32..fefe6fa 100644 --- a/birb/modules/timers/libs/timer.lua +++ b/birb/classes/predicate/utils.lua @@ -1,7 +1,7 @@ --- timer.lua :: a basic implementation of a timer for the actor system. +-- predicate/utils :: Simple utilities for predicates --[[ - Copyright © 2019 Kazhnuz + Copyright © 2021 Kazhnuz 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 @@ -21,25 +21,45 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ]] -local Timer = Object:extend() +local ConditionsUtils = {} -function Timer:new(controller, duration, name) - self.controller = controller +function ConditionsUtils.testVariables(var1, testType, var2) + local var2 = tonumber(var2) + if (testType == "eq" and var1 == var2) then + return true + end + if (testType == "ne" and var1 ~= var2) then + return true + end + if (testType == "gt" and var1 > var2) then + return true + end + if (testType == "ge" and var1 >= var2) then + return true + end + if (testType == "lt" and var1 < var2) then + return true + end + if (testType == "le" and var1 <= var2) then + return true + end - self.time = duration - self.name = name + return false end -function Timer:update(dt) - self.time = self.time - dt - if (self.time <= 0) then - self:finish() - end +function ConditionsUtils.testBool(bool, boolType) + return (bool == (boolType == "V")) end -function Timer:finish() - self.controller:timerResponse(self.name) - self.controller.timers[self.name] = nil +function ConditionsUtils.merge(cond) + local returnString = "" + for i, condElement in ipairs(cond) do + returnString = returnString .. condElement + if (i < #cond) then + returnString = returnString .. ":" + end + end + return returnString end -return Timer +return ConditionsUtils; \ No newline at end of file diff --git a/birb/classes/serializable/init.lua b/birb/classes/serializable/init.lua new file mode 100644 index 0000000..ed6b27b --- /dev/null +++ b/birb/classes/serializable/init.lua @@ -0,0 +1,139 @@ +-- classes/serializable :: a serializable object, can give its field as data + +--[[ + Copyright © 2021 Kazhnuz + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +]] + +local Serializable = Object:extend() + +function Serializable:new(serializeFields, listSerializable) + self.serializeFields = serializeFields + self.listSerializable = listSerializable +end + +function Serializable:getData() + local data = {} + -- We serialize all fields + if (self.serializeFields ~= nil) then + for _, key in ipairs(self.serializeFields) do + data[key] = self:wrapField(key) + end + end + -- We serialize all list of serializable + if (self.listSerializable ~= nil) then + for _, key in ipairs(self.listSerializable) do + data[key] = self:wrapList(key) + end + end + return data +end + +function Serializable:wrapField(key) + local serializedField = self[key] + if (serializedField ~= nil) then + if (type(serializedField) == "table" and serializedField.is ~= nil) then + if (serializedField:is(Serializable)) then + serializedField = serializedField:getData() + serializedField.isSerializable = true + end + end + self:print(key, serializedField, false) + return serializedField + end +end + +function Serializable:wrapList(key) + local serializedList = {} + serializedList.isListSerializable = true + for listKey, listElement in pairs(self[key]) do + serializedList[listKey] = listElement:getData() + end + self:print(key, serializedList, false) + return serializedList +end + +function Serializable:setData(data) + for key, value in pairs(data) do + if (key ~= "serializedField") then + self:unwrapField(key, value) + end + end + self:finishDeserialization() +end + +function Serializable:unwrapField(key, value) + local serializedField = value + if (serializedField ~= nil) then + if (type(serializedField) == "table") then + if (serializedField.isSerializable == true) then + self[key]:setData(serializedField) + elseif (serializedField.isListSerializable) then + self:unwrapList(key, serializedField) + else + self[key] = serializedField or self[key] + end + else + self[key] = serializedField or self[key] + self:print(key, serializedField, true) + end + end +end + +function Serializable:unwrapList(key, list) + if (list == nil) then + error("List " .. key .. " shouldn't be null in the save") + end + for listKey, listElement in pairs(list) do + if (listKey ~= "isListSerializable") then + self[key][listKey]:setData(listElement) + end + end + self:print(key, list, true) +end + +function Serializable:print(key, value, isLoading) + local loadString = "Loading " + if (isLoading == false) then + loadString = "Saving " + end + local valueString = value + if type(valueString) == "boolean" then + if valueString then + valueString = "true" + else + valueString = "false" + end + end + if (type(value) == "table") then + valueString = utils.table.toString(value) + end + loadString = loadString .. key .. " " .. ": " .. valueString + if (core ~= nil) then + core.debug:debug("serializable", loadString) + else + --print("serializable", loadString) + end +end + +function Serializable:finishDeserialization() + -- Empty function callback +end + +return Serializable \ No newline at end of file diff --git a/birb/classes/serializable/serializer.lua b/birb/classes/serializable/serializer.lua new file mode 100644 index 0000000..24636b3 --- /dev/null +++ b/birb/classes/serializable/serializer.lua @@ -0,0 +1,73 @@ +-- classes/serializable/serializer :: a serializer, able to put stuff into a bin file + +--[[ + Copyright © 2021 Kazhnuz + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +]] +local Serializable = require "birb.classes.serializable" +local Serializer = Serializable:extend() +local binser = require("birb.libs.binser") + +function Serializer:new(serializeFields, listSerializable) + Serializer.super.new(self, serializeFields, listSerializable) +end + +function Serializer:reset() + +end + +function Serializer:delete(filename) + local filepath = self:getFile(true, filename) + if utils.filesystem.exists(filename) then + love.filesystem.remove(filepath) + end +end + +function Serializer:deserialize(filename) + local filepath = self:getFile(true, filename) + if utils.filesystem.exists(filename) then + local loadedDatas = binser.readFile(filepath) + self:setData(loadedDatas[1]) + else + self:reset() + end +end + +function Serializer:serialize(filename) + local data = self:getData() + + local filepath = self:getFile(true, filename) + binser.writeFile(filepath, data) +end + +function Serializer:getFile(absolute, filename) + local dir = "" + if absolute then + dir = love.filesystem.getSaveDirectory() .. "/" + if (not utils.filesystem.exists(dir)) then + love.filesystem.createDirectory("") + end + end + + local filepath = dir .. filename + + return filepath +end + +return Serializer diff --git a/birb/classes/time/func.lua b/birb/classes/time/func.lua new file mode 100644 index 0000000..3684bf4 --- /dev/null +++ b/birb/classes/time/func.lua @@ -0,0 +1,14 @@ +local Timer = require "birb.classes.time.timer" +local TimedFunction = Timer:extend() + +function TimedFunction:new(actor, name, func, t) + TimedFunction.super.new(self, actor, name, t) + self.func = func +end + +function TimedFunction:finish() + self.actor.funcs[self.name] = nil + self.func() +end + +return TimedFunction \ No newline at end of file diff --git a/birb/modules/timers/init.lua b/birb/classes/time/init.lua similarity index 51% rename from birb/modules/timers/init.lua rename to birb/classes/time/init.lua index 4ea7e20..c980378 100644 --- a/birb/modules/timers/init.lua +++ b/birb/classes/time/init.lua @@ -1,4 +1,6 @@ --- timers :: a basic implementation of a timer system. + +-- time.lua :: a timer, tweener and timed switch handler. +-- This class need birb.libs.tween to work --[[ Copyright © 2019 Kazhnuz @@ -21,57 +23,102 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ]] -local cwd = (...):gsub('%.init$', '') .. "." +local TweenManager = Object:extend() -local TimersManager = Object:extend() -local Timer = require(cwd .. "libs.timer") -local Tween = require(cwd .. "libs.tween") +local tween = require "birb.libs.tween" +local Timer = require "birb.classes.time.timer" +local TimedFunction = require "birb.classes.time.func" - -function TimersManager:new(subject) +function TweenManager:new(subject) self.subject = subject self.time = 0 - self.timers = {} - self.switches = {} self.tweens = {} + self.switches = {} + + self.timers = {} + self.funcs = {} end --- UPDATE --- Update every timers +function TweenManager:newTween(start, duration, target, easing) + table.insert(self.tweens, self:createTween(start, duration, target, easing)) +end -function TimersManager:update(dt) - self.time = self.time + dt +function TweenManager:setNamedTween(name, start, duration, target, easing) + self.tweens[name] = nil + self.tweens[name] = self:createTween(start, duration, target, easing) +end - for k, timer in pairs(self.timers) do - timer:update(dt) - end +function TweenManager:createTween(start, duration, target, easing) + local newTween = {} + -- we add the data into a tween wrapper + newTween.tween = tween.new(duration, self.subject, target, easing) + newTween.start = self.time + start -- /!\ START IS RELATIVE TO CURRENT TIME + newTween.clear = newTween.start + duration - self:updateSwitches(dt) - self:updateTweens(dt) + return newTween +end + +function TweenManager:removeNamedTween(name) + self.tweens[name] = nil +end + +function TweenManager:haveTween() + return #self.tweens > 0 end -- TIMER FUNCTIONS --- Handle the timers +-- Help to get info from timers -function TimersManager:newTimer(duration, name) - self.timers[name] = Timer(self, duration, name) +function TweenManager:newTimer(start, name) + self.timers[name] = Timer(self, name, start) end -function TimersManager:timerResponse(timername) - if self.subject.timerResponse == nil then - core.debug:logWarn("TimersManager", "the subject have no timerResponse function") - return 0 +function TweenManager:delayTimer(time, name, absolute) + if (self.timers[name] ~= nil) then + self.timers[name]:delay(time, absolute) end - self.subject:timerResponse(timername) +end + +function TweenManager:getTimerInfo(name) + if (self.timers[name] ~= nil) then + return self.timers[name]:getInfo() + end +end + +function TweenManager:removeTimer(name) + self.timers[name] = nil +end + +-- FUNCTION FUNCTIONS +-- Help to get functions + +function TweenManager:newFunc(start, name, func) + self.funcs[name] = TimedFunction(self, name, func, start) +end + +function TweenManager:delayFunc(time, name, absolute) + if (self.funcs[name] ~= nil) then + self.funcs[name]:delay(time, absolute) + end +end + +function TweenManager:getFuncInfo(name) + if (self.funcs[name] ~= nil) then + return self.funcs[name]:getInfo() + end +end + +function TweenManager:removeFunc(name) + self.funcs[name] = nil end -- SWITCH FUNCTIONS --- Handle switches +-- Help to handle switches -function TimersManager:newSwitch(start, bools) +function TweenManager:newSwitch(start, bools) local newSwitch = {} - -- we add the data into a switch wrapper + -- we add the data into a tween wrapper newSwitch.bools = bools newSwitch.start = self.time + start -- /!\ START IS RELATIVE TO CURRENT TIME newSwitch.clear = newSwitch.start + 1 @@ -79,8 +126,19 @@ function TimersManager:newSwitch(start, bools) table.insert(self.switches, newSwitch) end -function TimersManager:updateSwitches(dt) - for i, switch in ipairs(self.switches) do +function TweenManager:update(dt) + self.time = self.time + dt + + for key, tweenWrapper in pairs(self.tweens) do + if (self.time > tweenWrapper.start) then + tweenWrapper.tween:update(dt) + if (self.time > tweenWrapper.clear) then + self.tweens[key] = nil + end + end + end + + for i, switch in pairs(self.switches) do if (self.time > switch.start) then -- We test each boolean in the switch for i, bool in ipairs(switch.bools) do @@ -95,32 +153,27 @@ function TimersManager:updateSwitches(dt) table.remove(self.switches, i) end end -end --- TWEENING FUNCTIONS --- Handle tween support via tween.lua + for k, timer in pairs(self.timers) do + timer:update(dt) + end -function TimersManager:newTween(start, duration, target, easing) - local newTween = {} - -- we add the data into a tween wrapper - newTween.tween = Tween.new(duration, self.subject, target, easing) - newTween.start = self.time + start -- /!\ START IS RELATIVE TO CURRENT TIME - newTween.clear = newTween.start + duration - - table.insert(self.tweens, newTween) -end - -function TimersManager:updateTweens(dt) - for i, tweenWrapper in ipairs(self.tweens) do - if (self.time > tweenWrapper.start) then - tweenWrapper.tween:update(dt) - end + for k, func in pairs(self.funcs) do + func:update(dt) end self:clearEndedTweens() end -function TimersManager:clearEndedTweens() +function TweenManager:timerResponse(timername) + if self.subject.timerResponse == nil then + core.debug:warning("tweenmanager", "the subject have no timerResponse function") + return 0 + end + self.subject:timerResponse(timername) +end + +function TweenManager:clearEndedTweens(dt) for i, tweenWrapper in ipairs(self.tweens) do if (self.time > tweenWrapper.clear) then table.remove(self.tweens, i) @@ -128,4 +181,4 @@ function TimersManager:clearEndedTweens() end end -return TimersManager +return TweenManager diff --git a/birb/modules/world/actors/utils/timer.lua b/birb/classes/time/timer.lua similarity index 81% rename from birb/modules/world/actors/utils/timer.lua rename to birb/classes/time/timer.lua index 5ba7c3f..c095daf 100644 --- a/birb/modules/world/actors/utils/timer.lua +++ b/birb/classes/time/timer.lua @@ -24,6 +24,7 @@ local Timer = Object:extend() function Timer:new(actor, name, t) + self.baseTime = t self.time = t self.actor = actor self.name = name @@ -36,9 +37,23 @@ function Timer:update(dt) end end +function Timer:delay(time, absolute) + if (absolute == true) then + self.baseTime = self.baseTime + (time - self.time) + self.time = time + else + self.baseTime = self.baseTime + time + self.time = self.time + time + end +end + +function Timer:getInfo() + return self.time, self.baseTime, (self.time / self.baseTime) +end + function Timer:finish() - self.actor:timerResponse(self.name) self.actor.timers[self.name] = nil + self.actor:timerResponse(self.name) end return Timer diff --git a/birb/core/assets.lua b/birb/core/assets.lua deleted file mode 100644 index 3eac342..0000000 --- a/birb/core/assets.lua +++ /dev/null @@ -1,105 +0,0 @@ --- core/assets :: a simple assets manager, aim to put every assets in a simple --- serie of table in order to find them easily. - ---[[ - Copyright © 2019 Kazhnuz - - Permission is hereby granted, free of charge, to any person obtaining a copy of - this software and associated documentation files (the "Software"), to deal in - the Software without restriction, including without limitation the rights to - use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - the Software, and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -]] - -local AssetManager = Object:extend() - -function AssetManager:new() - self.locals = {} - self.globals = {} - self.updatables = {} - - self.isActive = true -end - -function AssetManager:update(dt) - if (self.isActive) then - for key, updatable in pairs(self.updatables) do - updatable:update(dt) - end - end -end - -function AssetManager:add(name, asset, isGlobal) - if (isGlobal == true) then - self:addGlobal(name, asset) - else - self:addLocal(name, asset) - end -end - -function AssetManager:addGlobal(name, asset) - self.globals[name] = asset -end - -function AssetManager:addLocal(name, asset) - self.locals[name] = asset -end - -function AssetManager:clear() - self.locals = {} - self.globals = {} - collectgarbage() -end - -function AssetManager:clearLocal() - self.locals = {} -end - -function AssetManager:get(name) - local asset - if self.locals[name] ~= nil then - asset = self.locals[name] - else - asset = self.globals[name] - end - - if (asset ~= nil) then - return asset - else - core.debug:fail("core.assets", "L'asset " .. name .. " n'existe pas.") - end -end - --- Specific functions - -function AssetManager:playSFX(name) - local asset = self:get(name) - asset:play() -end - --- Activity Functions - -function AssetManager:setActivity(isActive) - self.isActive = isActive -end - -function AssetManager:switchActivity() - self.isActive = (self.isActive == false) -end - -function AssetManager:getActivity() - return self.isActive -end - -return AssetManager \ No newline at end of file diff --git a/birb/core/datas.lua b/birb/core/datas.lua new file mode 100644 index 0000000..324e748 --- /dev/null +++ b/birb/core/datas.lua @@ -0,0 +1,82 @@ +-- datas.lua :: The main file of the core system, an object full of subsystem +-- loaded by the game to handle the main functions (like screen, translation, +-- inputs…) + +--[[ + Copyright © 2021 Kazhnuz + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +]] + +local DataManager = Object:extend() +local DataPack = require "birb.classes.datapack" +local Parser = require "birb.classes.parser" +local index = require "datas.gamedata.index" + +function DataManager:new(core) + self.core = core + self:loadDatas() + self:loadParsers() +end + +function DataManager:loadDatas() + self.datapacks = {} + if (index.datapack ~= nil) then + for key, datas in pairs(index.datapacks) do + self.core.debug:debug("datamanager", "loading data for " .. key) + self.datapacks[key] = DataPack(datas[1], datas[2], datas[3], datas[4], datas[5]) + end + end +end + +function DataManager:get(datapack, name) + return self.datapacks[datapack]:get(name) +end + +function DataManager:exists(datapack, name) + return self.datapacks[datapack]:dataExists(name) +end + +function DataManager:getFromCategory(datapack, category) + return self.datapacks[datapack]:getFromCategory(category) +end + +function DataManager:getCategories(datapack) + return self.datapacks[datapack].categories +end + +-- Load parsers + +function DataManager:loadParsers() + self.parsers = {} + local items = love.filesystem.getDirectoryItems("datas/parsers") + for i, item in ipairs(items) do + local filename = utils.datas.luaFileToModule(item) + local data = require("datas.parsers." .. filename) + + self.core.debug:debug("datamanager", "creating parser for " .. filename) + self.parsers[filename] = Parser(data.headings, data.argumentLists, data.argumentWrapper, 0) + end +end + +function DataManager:parse(parser, data) + return self.parsers[parser]:parse(data) +end + + +return DataManager \ No newline at end of file diff --git a/birb/core/debug.lua b/birb/core/debug.lua index d23a115..6e2531f 100644 --- a/birb/core/debug.lua +++ b/birb/core/debug.lua @@ -1,4 +1,4 @@ --- core/debug.lua :: A basic framework for debug. +-- core/debug.lua :: The basic internal debug framework of the birb engine. --[[ Copyright © 2019 Kazhnuz @@ -23,128 +23,70 @@ local DebugSystem = Object:extend() -local lovebird = require("birb.libs.lovebird") +local lovebird -local ERROR = 0 -local WARN = 1 -local INFO = 2 -local DEBUG = 3 +local Levels = enum { + "ERROR", + "WARNING", + "INFO", + "DEBUG" +} ---- Create a new DebugSystem. --- It allow you to determinate the debug level of the game. --- @param controller the birb core --- @param debugLevel the debug mode level function DebugSystem:new(controller, debugLevel) - self.core = controller - self.debugLevel = debugLevel or 0 + self.controller = controller - self:updateUI() -end - ---- Update the DebugSystem. --- @param dt the delta time -function DebugSystem:update(dt) - self:updateUI(dt) -end - ---- Update the lovebird UI if the debug level is debug. --- @param dt the delta time -function DebugSystem:updateUI(dt) - if (self:isDebug()) then - lovebird.update(dt) + self.debugLevel = debugLevel or Levels.WARNING + self.active = (self.debugLevel == Levels.DEBUG) + if (self.active) then + lovebird = require "birb.libs.lovebird" + lovebird.update() end end --- TEST FUNCTIONS --- Simple warper to get easily the debug level - ---- Test if debug level is "DEBUG" --- @return true if the debug level is "DEBUG" -function DebugSystem:isDebug() - return (self.debugLevel >= DEBUG) -end - ---- Test if debug level is "INFO" --- @return true if the debug level is "INFO" -function DebugSystem:isInfo() - return (self.debugLevel >= INFO) -end - ---- Test if debug level is "WARN" --- @return true if the debug level is "WARN" -function DebugSystem:isWarn() - return (self.debugLevel >= WARN) -end - ---- Test if debug level is "ERROR" --- @return true if the debug level is "ERROR" -function DebugSystem:isError() - return (self.debugLevel >= ERROR) +function DebugSystem:update(dt) + if (self.active and lovebird ~= nil) then + lovebird.update(dt) + end end -- PRINT FUNCTIONS -- Print and log debug string ---- Log a debug line --- --- @param context the context of the log --- @param string the logged string -function DebugSystem:logDebug(context, string) - if (self:isDebug()) then - print(self:createLogLine("DEBUG", context, string)) +function DebugSystem:debug(context, string) + self:log(Levels.DEBUG, context, string) +end + +function DebugSystem:print(context, string) + self:log(Levels.INFO, context, string) +end + +function DebugSystem:warning(context, string) + self:log(Levels.WARNING, context, string) +end + +function DebugSystem:error(context, string) + self:log(Levels.ERROR, context, string) + error(self:getMessage(": ", context, string)) +end + +function DebugSystem:log(level, context, string) + if (self.debugLevel >= level) then + print(self:getLogLine(Levels[level], context, string)) end end ---- Log an info --- --- @param context the context of the log --- @param string the logged string -function DebugSystem:logInfo(context, string) - if (self:isInfo()) then - print(self:createLogLine("INFO", context, string)) +function DebugSystem:getLogLine(type, context, string) + local head = self.controller:getIdentity(false) .. "|" .. os.date("%x-%X") .. "|" .. type .. "|" + return head .. self:getMessage("|", context, string) +end + +function DebugSystem:getMessage(separator, string1, string2) + if (string2 == nil) then + return string1 + else + return string1 .. separator .. string2 end end ---- Log a warning --- --- @param context the context of the log --- @param string the logged string -function DebugSystem:logWarn(context, string) - if (self:isWarn()) then - print(self:createLogLine("WARNING", context, string)) - end -end - ---- Log an error --- --- @param context the context of the log --- @param string the logged string -function DebugSystem:logError(context, string) - if (self:isError()) then - print(self:createLogLine("ERROR", context, string)) - end -end - ---- Log an error and fail --- --- @param context the context of the log --- @param string the logged string -function DebugSystem:fail(context, string) - if (self:isError()) then - print(self:createLogLine("ERROR", context, string)) - error(string) - end -end - ---- Create a formatted debug line --- --- @param level the level of the log --- @param context the context of the log --- @param string the logged string --- @return the debug line -function DebugSystem:createLogLine(level, context, string) - local head = self.core:getName() .. "|" .. os.date("%x-%X") .. "|" - return head .. level .. "|" .. context .. ": " .. string; -end return DebugSystem diff --git a/birb/core/init.lua b/birb/core/init.lua index e0d69e8..c618bd0 100644 --- a/birb/core/init.lua +++ b/birb/core/init.lua @@ -28,33 +28,37 @@ local cwd = (...):gsub('%.init$', '') .. "." local CoreSystem = Object:extend() local DebugSystem = require(cwd .. "debug") + local Options = require(cwd .. "options") local Input = require(cwd .. "input") local Screen = require(cwd .. "screen") local Lang = require(cwd .. "lang") local SceneManager = require(cwd .. "scenemanager") local MusicManager = require(cwd .. "music") -local Assets = require(cwd .. "assets") +local DataManager = require(cwd .. "datas") -- INIT FUNCTIONS -- Initialize and configure the core object -function CoreSystem:new(debugLevel) - local conf = self:getDefaultConf() - self.gameName = conf.identity +function CoreSystem:new(args) + self.args = args + self:setDefaultConf() - self.modules = birb.modules - - self.debug = DebugSystem(self, debugLevel) + self.debug = DebugSystem(self, self:getArg("DEBUGLEVEL", true)) self.options = Options(self) self.input = Input(self) self.screen = Screen(self) self.scenemanager = SceneManager(self) self.lang = Lang(self) self.music = MusicManager(self) - self.assets = Assets(self) + self.datas = DataManager(self) +end - self.debug:logDebug("birbcore","Birb initialized") +function CoreSystem:setDefaultConf() + self.conf = {} + self.conf.window = {} + self.conf.modules = {} + love.conf(self.conf) end function CoreSystem:registerGameSystem(gamesystem) @@ -62,17 +66,29 @@ function CoreSystem:registerGameSystem(gamesystem) end function CoreSystem:getDefaultConf() - local defaultConf = {} - defaultConf.window = {} - defaultConf.modules = {} - - love.conf(defaultConf) - - return defaultConf + return self.conf end -function CoreSystem:getName() - return self.gameName +function CoreSystem:getIdentity(versionned) + local identity = self.conf.identity or "birbengine" + if (versionned) then + local version = self.conf.gameversion or 0 + identity = identity .. "-" .. version + end + return identity +end + +function CoreSystem:getArg(name, isNumber) + for _, arg in ipairs(self.args) do + local argData = utils.string.split(arg, "=") + if (argData[1] == name) then + if (isNumber == true) then + return tonumber(argData[2]) + else + return argData[2] + end + end + end end -- MOUSE FUNCTIONS @@ -104,25 +120,26 @@ end -- Load every sytem every update functions of the scene and objects function CoreSystem:update(dt) + -- If the frameskip is to high, prefer slowdown to frameskip + local dt = math.min(dt, 1/15) self.debug:update(dt) self.input:update(dt) - self.screen:update(dt) - self.music:update(dt) - self.assets:update(dt) if (self.game ~= nil) then self.game:update(dt) end self.scenemanager:update(dt) + self.screen:update(dt) + self.music:update(dt) end -- DRAW FUNCTIONS -- Draw the whole game function CoreSystem:draw() + self.scenemanager:redraw() self.scenemanager:draw() - self.screen:drawFade() end -- EXIT FUNCTIONS diff --git a/birb/core/input.lua b/birb/core/input.lua index 5304b1f..b7c01cd 100644 --- a/birb/core/input.lua +++ b/birb/core/input.lua @@ -143,7 +143,7 @@ function VirtualPad:isDown(key) isdown = love.keyboard.isDown(self.data.keys[key]) else local warnstring = "unsupported input device " .. self.type .. " for source " .. self.id - core.debug:logWarn("core/input", warnstring) + core.debug:warning("core/input", warnstring) end return isdown @@ -159,13 +159,13 @@ function VirtualPad:checkKey(key) local isDown = self:isDown(key) if (isDown) then if not (self.keys[key].isDown) then - core.debug:logDebug("virtualpad", "key " .. key .. " is Pressed") + --core.debug:print("virtualpad", "key " .. key .. " is Pressed") self.keys[key].isDown = true self.keys[key].isPressed = true self.keys[key].isReleased = false else if (self.keys[key].isPressed) then - core.debug:logDebug("virtualpad", "key " .. key .. " is Down") + --core.debug:print("virtualpad", "key " .. key .. " is Down") self.keys[key].isPressed = false end end @@ -176,7 +176,7 @@ function VirtualPad:checkKey(key) self.keys[key].isReleased = true else if (self.keys[key].isReleased) then - core.debug:logDebug("virtualpad", "key " .. key .. " is Released") + --core.debug:print("virtualpad", "key " .. key .. " is Released") self.keys[key].isReleased = false end end diff --git a/birb/core/lang.lua b/birb/core/lang.lua index 1d8fb50..260c82d 100644 --- a/birb/core/lang.lua +++ b/birb/core/lang.lua @@ -95,7 +95,7 @@ function LanguageManager:getTranslationStringList(lang, library) if fileinfo ~= nil then list = require(_path) else - core.debug:logWarn("core/lang","file " .. _path .. " do not exists") + core.debug:warning("core/lang","file " .. _path .. " do not exists") end return list @@ -120,7 +120,7 @@ function LanguageManager:translate(library, string) if (translation == nil) then translation = string - core.debug:logWarn("core/lang", "no translation path found for " .. string .. " in " .. library) + core.debug:warning("core/lang", "no translation path found for " .. string .. " in " .. library) end return translation diff --git a/birb/core/music.lua b/birb/core/music.lua index 64928a4..d662e93 100644 --- a/birb/core/music.lua +++ b/birb/core/music.lua @@ -1,4 +1,4 @@ --- core/langs.lua :: A music system, in order to add some usefull features +-- core/music.lua :: A music system, in order to add some usefull features -- and to make music not scene dependant --[[ @@ -54,10 +54,6 @@ function MusicManager:haveMusic() return (self.musics[1] ~= nil) end -function MusicManager:applyVolume() - self.musics[1]:setVolume(self.core.options.data.audio.music / 100) -end - function MusicManager:playMusic() if (self:haveMusic()) then self.musics[1]:setVolume(self.core.options.data.audio.music / 100) @@ -87,7 +83,7 @@ function MusicManager:silence() end end -function MusicManager:skipMusic() +function MusicManager:skip() if (self:haveMusic()) then self.musics[1]:stop() self.isPlaying = false diff --git a/birb/core/options.lua b/birb/core/options.lua index 96b4d9c..5f6baf2 100644 --- a/birb/core/options.lua +++ b/birb/core/options.lua @@ -21,34 +21,36 @@ 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 OptionsManager = Object:extend() - -local binser = require("birb.libs.binser") +local Serializer = require "birb.classes.serializable.serializer" +local OptionsManager = Serializer:extend() local TRANSLATION_PATH = "datas/languages/" +local OPTION_FILE = "options.data" + -- INIT FUNCTIONS -- Initialize and configure the game options -function OptionsManager:new(core) - self.core = core +function OptionsManager:new(controller) + OptionsManager.super.new(self, {"data"}) + + self.controller = controller -- We begin by creating an empty data table before reading the data. - self.data = {} + self:reset() self:read() end function OptionsManager:reset() - -- load the default set of config - local defaultConf = self.core:getDefaultConf() - + local conf = self.controller:getDefaultConf() -- Reset the option to the game defaults. + self.data = {} + self.data.video = {} - self.data.video.crtfilter = false - self.data.video.resolution = defaultConf.window.resolution - self.data.video.borderless = defaultConf.window.borderless - self.data.video.vsync = defaultConf.window.vsync - self.data.video.fullscreen = defaultConf.window.fullscreen + self.data.video.crtfilter = (conf.window.crtfilter == true) + self.data.video.resolution = conf.window.resolution or 1 + self.data.video.border = (conf.window.borderless == false) + self.data.video.vsync = (conf.window.vsync ~= false) + self.data.video.fullscreen = (conf.window.fullscreen == true) -- We load the default files self.data.input = self:getInputDefaultData() @@ -57,27 +59,13 @@ function OptionsManager:reset() self.data.language = self:getTranslationDefaultData() self.data.audio = {} - self.data.audio.music = defaultConf.volume.music - self.data.audio.sfx = defaultConf.volume.sfx + self.data.audio.music = conf.volume.music or 100 + self.data.audio.sfx = conf.volume.sfx or 100 end -- INFO FUNCTIONS -- Get informations from the option managers -function OptionsManager:getFile(absolute) - local dir = "" - if absolute then - dir = love.filesystem.getSaveDirectory() .. "/" - if not utils.filesystem.exists(dir) then - love.filesystem.createDirectory( "" ) - end - end - - local filepath = dir .. "options.data" - - return filepath -end - function OptionsManager:getInputDefaultData() local _path = "datas/inputs.lua" local datas = {} @@ -121,8 +109,7 @@ function OptionsManager:getTranslationDefaultData() local _path = TRANSLATION_PATH .. "init.lua" local fileinfo = love.filesystem.getInfo(_path) local datas = nil - local lang = nil - + local lang if fileinfo ~= nil then lang = require(TRANSLATION_PATH) lang.current = lang.default or "en" @@ -133,9 +120,9 @@ function OptionsManager:getTranslationDefaultData() end function OptionsManager:setLanguage(lang) - if (self.core.lang:isLangAvailable(lang)) then + if (self.controller.lang:isLangAvailable(lang)) then self.data.language.current = lang - self.core.lang:getTranslationData() + self.controller.lang:getTranslationData() end end @@ -145,30 +132,11 @@ end -- FIXME: maybe subclass a special module for that ? function OptionsManager:write() - local data = self:getData() - - local filepath = self:getFile(true) - binser.writeFile(filepath, data) + self:serialize(OPTION_FILE) end function OptionsManager:read() - local filepath = self:getFile(true) - if utils.filesystem.exists("options.data") then - local loadedDatas = binser.readFile(filepath) - self.core.debug:logInfo("core/options", "data file found, loading it") - self:setData(loadedDatas[1]) - else - self:reset() - self.core.debug:logInfo("core/options", "no data file found, reseting data") - end -end - -function OptionsManager:getData(data) - return self.data -end - -function OptionsManager:setData(data) - self.data = data + self:deserialize(OPTION_FILE) end return OptionsManager diff --git a/birb/core/scenemanager.lua b/birb/core/scenemanager.lua index fca5991..8c081c8 100644 --- a/birb/core/scenemanager.lua +++ b/birb/core/scenemanager.lua @@ -30,22 +30,19 @@ local SceneManager = Object:extend() function SceneManager:new(controller) self.controller = controller - self.timers = self.controller.modules.Timers(self) self.currentScene = nil + self.nextScene = nil self.storage = {} - - self:initTransitions() end function SceneManager:setScene(scene) - if self.transition.isPrepared then - self:startTransition(scene) - else - self.currentScene = scene - self.currentScene:start() - self.currentScene.isActive = true - end + --self.currentScene = nil + self.nextScene = scene +end + +function SceneManager:haveStoredScene(name) + return (self.storage[name] ~= nil) end function SceneManager:storeCurrentScene(name) @@ -57,6 +54,8 @@ function SceneManager:setStoredScene(name) if storedScene ~= nil then self.currentScene = storedScene self.storage[name] = nil + collectgarbage() + self.currentScene:restored() end end @@ -72,7 +71,12 @@ end -- Update the current scene and its subobjects function SceneManager:update(dt) - self.timers:update(dt) + if (self.nextScene ~= nil) then + self.currentScene = self.nextScene + self.nextScene = nil + collectgarbage() + end + if (self.currentScene ~= nil) then self.currentScene:updateScene(dt) end @@ -86,14 +90,12 @@ function SceneManager:mousemoved(x, y, dx, dy) self.currentScene.mouse.x, self.currentScene.mouse.y = x, y self.currentScene:mousemoved(x, y, dx, dy) - self.currentScene.menusystem:mousemoved(x, y, dx, dy) end end function SceneManager:mousepressed( x, y, button, istouch ) if (self.currentScene ~= nil) then self.currentScene:mousepressed( x, y, button, istouch ) - self.currentScene.menusystem:mousepressed( x, y, button, istouch ) end end @@ -101,55 +103,14 @@ end -- Add send keys functions to the scene function SceneManager:keypressed( key, scancode, isrepeat ) - self.currentScene:keypressed( key, scancode, isrepeat ) + if (self.currentScene ~= nil) then + self.currentScene:keypressed( key, scancode, isrepeat ) + end end function SceneManager:keyreleased( key ) - self.currentScene:keyreleased( key ) -end - --- TRANSITION FUNCTIONS --- Prepare transitionning to the next scene - -function SceneManager:initTransitions() - self.transition = {} - - self.transition.easeIn = "inQuad" - self.transition.easeOut = "outQuad" - self.transition.duration = 1 - - self.transition.nextScene = nil - self.transition.isPrepared = false -end - -function SceneManager:prepareTransition(duration, easeIn, easeOut) - self.transition.easeIn = easeIn or self.transition.easeIn - self.transition.easeOut = easeOut or self.transition.easeOut - self.transition.duration = duration or self.transition.duration - - self.transition.isPrepared = true -end - -function SceneManager:startTransition(nextScene) - self.transition.nextScene = nextScene - self.currentScene:flushKeys(self.transition.duration) - self.currentScene.isActive = false - self.transition.nextScene.isActive = false - core.screen:fadeIn(self.transition.duration / 2.5, self.transition.easeIn) - self.timers:newTimer(self.transition.duration / 2, "fadeOut") -end - -function SceneManager:timerResponse(timer) - if timer == "fadeOut" then - self.currentScene = self.transition.nextScene - self.currentScene:start() - self.currentScene:flushKeys(self.transition.duration / 2.5) - self.currentScene.isActive = false - core.screen:fadeOut(self.transition.duration / 2.5, self.transition.easeOut) - self.transition.isPrepared = false - self.timers:newTimer(self.transition.duration / 2.5, "activateScene") - elseif timer == 'activateScene' then - self.currentScene.isActive = true + if (self.currentScene ~= nil) then + self.currentScene:keyreleased( key ) end end @@ -164,4 +125,8 @@ function SceneManager:draw() self.controller.screen:cease() end +function SceneManager:redraw() + self.currentScene:redraw() +end + return SceneManager diff --git a/birb/core/screen.lua b/birb/core/screen.lua index f2a747e..16651b9 100644 --- a/birb/core/screen.lua +++ b/birb/core/screen.lua @@ -39,9 +39,28 @@ function ScreenManager:new(controller) love.graphics.setDefaultFilter( "nearest", "nearest", 1 ) - self.timers = self.controller.modules.Timers(self) + self.transition = nil + self.transitionOut = nil + self.isOpaque = false +end - self.transitionValue = 0 +function ScreenManager:startTransition(transitionIn, transitionOut, func, x, y) + self.transition = transitionIn(func, x, y, false) + self.transitionOut = transitionOut(nil, x, y, true) + self.isOpaque = true +end + +function ScreenManager:transitionOver(fadeOut) + if (not fadeOut) then + self.transition = self.transitionOut + else + self.transition = nil + self.isOpaque = false + end +end + +function ScreenManager:isActive() + return ((self.transition == nil) and (not self.isOpaque)) end function ScreenManager:applySettings() @@ -49,7 +68,7 @@ function ScreenManager:applySettings() local flags = {} flags.vsync = self.data.vsync - flags.borderless = (self.data.borderless) + flags.borderless = (self.data.border == false) love.window.setMode(self.width * self.data.resolution, self.height * self.data.resolution, flags) love.window.setFullscreen( self.data.fullscreen ) @@ -58,6 +77,12 @@ function ScreenManager:applySettings() CScreen.update(width, height) end +function ScreenManager:update(dt) + if (self.transition ~= nil) then + self.transition:update(dt) + end +end + -- POINTER FUNCTIONS -- Translate the pointer according to the screen coordinates @@ -96,35 +121,6 @@ function ScreenManager:resetScissor() love.graphics.setScissor( ) end --- UPDATE FUNCTIONS --- Update the screen - -function ScreenManager:update(dt) - self.timers:update(dt) -end - --- TRANSITION FUNCTIONS --- Handle transitions - -function ScreenManager:fadeIn(duration, easing) - local duration = duration or 1 - local easing = easing or "inExpo" - self.timers:newTween(0, duration, {transitionValue = 1}, easing) -end - -function ScreenManager:fadeOut(duration, easing) - local duration = duration or 1 - local easing = easing or "outExpo" - self.timers:newTween(0, duration, {transitionValue = 0}, easing) -end - -function ScreenManager:drawFade() - local w, h = love.graphics.getDimensions() - love.graphics.setColor(0, 0, 0, self.transitionValue) - love.graphics.rectangle("fill", 0, 0, w, h) - utils.graphics.resetColor() -end - -- DRAW FUNCTIONS -- Apply draw functions to the scene @@ -136,4 +132,16 @@ function ScreenManager:cease() CScreen.cease() end +function ScreenManager:drawTransition() + if (self.isOpaque) then + if (self.transition ~= nil) then + self.transition:draw() + else + love.graphics.setColor(0,0,0,1) + love.graphics.rectangle("fill",0,0,424,240) + utils.graphics.resetColor() + end + end +end + return ScreenManager diff --git a/birb/gamesystem/init.lua b/birb/gamesystem/init.lua new file mode 100644 index 0000000..aebf3dc --- /dev/null +++ b/birb/gamesystem/init.lua @@ -0,0 +1,102 @@ +-- GameSystem :: The main GameSystem subsystem. Basically a big object that handle all the +-- GameSystem-related data like characters, monsters, etc. While the core aim to be +-- reusable at will, the GameSystem is specifically made for the current GameSystem. + +--[[ + Copyright © 2019 Kazhnuz + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +]] + + +local Serializer = require "birb.classes.serializable.serializer" +local GameSystem = Serializer:extend() + +local VAR_TO_SERIALIZE = { + "gametime", + "destroyedGizmo", + "variables", + "flags" +} + +function GameSystem:new() + self.slot = -1 + self.slotNumber = 3 + self.version = core.conf.gameversion or "N/A" + self:reset() + GameSystem.super.new(self, VAR_TO_SERIALIZE) +end + +function GameSystem:reset() + self.gametime = 0 + + self.flags = {} + self.destroyedGizmo = {} + self.variables = {} + self.mapName = "" +end + +function GameSystem:reload() + self:read(self.slot) +end + +function GameSystem:read(save_id) + self.slot = save_id + if (self.slot > 0) then + self:deserialize(self:getSaveName()) + end +end + +function GameSystem:deleteCurrentSave() + if (self.slot > 0) then + self:delete(self:getSaveName()) + self.metadata:remove(self.slot) + end +end + +function GameSystem:write() + if (self.slot > 0) then + self:serialize(self:getSaveName()) + end +end + +function GameSystem:getSaveName(saveslot) + local saveslot = saveslot or self.slot + return "save" .. saveslot .. ".save" +end + +function GameSystem:resetSaves() + for i=1, self.slotNumber do + self:delete(self:getSaveName(i)) + end +end + +function GameSystem:update(dt) + self.gametime = self.gametime + dt +end + +function GameSystem:getTime() + return utils.time.getFields(self.gametime) +end + +function GameSystem:getTimeString() + return utils.time.toString(self.gametime) +end + +function GameSystem:printTime() + core.debug:print(self:getTimeString()) +end + +return GameSystem \ No newline at end of file diff --git a/birb/init.lua b/birb/init.lua index f0e7f8e..b6827c4 100644 --- a/birb/init.lua +++ b/birb/init.lua @@ -1,8 +1,7 @@ --- birb/init.lua :: The main file of birb, that initilize the whole birb engine --- It basically works by loading everything needed for a full birb experience. +-- birb :: The main birb script, loading the core and main utilities --[[ - Copyright © 2019 Kazhnuz + Copyright © 2021 Kazhnuz 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 @@ -30,12 +29,24 @@ birb = {} Object = require("birb.libs.classic") utils = require("birb.utils") +enum = require("birb.utils.enum") -birb.modules = require("birb.modules") birb.Core = require("birb.core") -function birb.startCore(debugLevel) - core = birb.Core(debugLevel) +function birb.start(gamemodule, args) + birb.startCore(args) + if (gamemodule ~= nil) then + birb.startGame(gamemodule) + end end -require("birb.callbacks") +function birb.startCore(args) + core = birb.Core(args) +end + +function birb.startGame(gamemodule) + local GameObject = require(gamemodule) + game = GameObject() +end + +require("birb.callbacks") \ No newline at end of file diff --git a/birb/libs/talkies.lua b/birb/libs/talkies.lua new file mode 100644 index 0000000..0b4456c --- /dev/null +++ b/birb/libs/talkies.lua @@ -0,0 +1,392 @@ +-- +-- talkies +-- +-- Copyright (c) 2017 twentytwoo, tanema +-- +-- This library is free software; you can redistribute it and/or modify it +-- under the terms of the MIT license. See LICENSE for details. +-- +local utf8 = require("utf8") + +local function playSound(sound, pitch) + if type(sound) == "userdata" then + sound:setPitch(pitch or 1) + sound:play() + end +end + +local function parseSpeed(speed) + if speed == "fast" then return 0.01 + elseif speed == "medium" then return 0.04 + elseif speed == "slow" then return 0.08 + else + assert(tonumber(speed), "setSpeed() - Expected number, got " .. tostring(speed)) + return speed + end +end + +local Fifo = {} +function Fifo.new () return setmetatable({first=1,last=0},{__index=Fifo}) end +function Fifo:peek() return self[self.first] end +function Fifo:len() return (self.last+1)-self.first end + +function Fifo:push(value) + self.last = self.last + 1 + self[self.last] = value +end + +function Fifo:pop() + if self.first > self.last then return end + local value = self[self.first] + self[self.first] = nil + self.first = self.first + 1 + return value +end + +local Typer = {} +function Typer.new(msg, speed) + local timeToType = parseSpeed(speed) + return setmetatable({ + msg = msg, complete = false, paused = false, + timer = timeToType, max = timeToType, position = 0, visible = "", + },{__index=Typer}) +end + +function Typer:resume() + if not self.paused then return end + self.msg = self.msg:gsub("%-%-", " ", 1) + self.paused = false +end + +function Typer:finish() + if self.complete then return end + self.msg = self.msg:gsub("%-%-", " ") + self.visible = self.msg + self.complete = true +end + +function Typer:update(dt) + local typed = false + if self.complete then return typed end + if not self.paused then + self.timer = self.timer - dt + while not self.paused and not self.complete and self.timer <= 0 do + typed = string.sub(self.msg, self.position, self.position) ~= " " + self.position = self.position + 1 + + self.timer = self.timer + self.max + self.visible = string.sub(self.msg, 0, utf8.offset(self.msg, self.position) - 1) + self.complete = (self.visible == self.msg) + self.paused = string.sub(self.msg, string.len(self.visible)+1, string.len(self.visible)+2) == "--" + end + end + + return typed +end + +local Talkies = { + _VERSION = '0.0.1', + _URL = 'https://github.com/tanema/talkies', + _DESCRIPTION = 'A simple messagebox system for LÖVE', + + -- Theme + indicatorCharacter = ">>", + optionCharacter = ">", + padding = 4, + talkSound = nil, + optionSwitchSound = nil, + optionOnSelectSound = nil, + inlineOptions = true, + + titleColor = {1, 1, 1}, + titleBackgroundColor = nil, + titleBorderColor = nil, + messageColor = {1, 1, 1}, + messageBackgroundColor = {0, 0, 0, 0.8}, + messageBorderColor = nil, + + rounding = 0, + thickness = 0, + + textSpeed = 1 / 60, + font = love.graphics.newFont(), + + typedNotTalked = true, + pitchValues = {0.7, 0.8, 1.0, 1.2, 1.3}, + + indicatorTimer = 0, + indicatorDelay = 3, + showIndicator = false, + dialogs = Fifo.new(), +} + +function Talkies.say(title, messages, config) + config = config or {} + if type(messages) ~= "table" then + messages = { messages } + end + + msgFifo = Fifo.new() + + for i=1, #messages do + msgFifo:push(Typer.new(messages[i], config.textSpeed or Talkies.textSpeed)) + end + + local font = config.font or Talkies.font + + -- Insert the Talkies.new into its own instance (table) + local newDialog = { + title = title or "", + messages = msgFifo, + image = config.image, + options = config.options, + onstart = config.onstart or function(dialog) end, + onmessage = config.onmessage or function(dialog, left) end, + oncomplete = config.oncomplete or function(dialog) end, + + -- theme + indicatorCharacter = config.indicatorCharacter or Talkies.indicatorCharacter, + optionCharacter = config.optionCharacter or Talkies.optionCharacter, + padding = config.padding or Talkies.padding, + rounding = config.rounding or Talkies.rounding, + thickness = config.thickness or Talkies.thickness, + talkSound = config.talkSound or Talkies.talkSound, + optionSwitchSound = config.optionSwitchSound or Talkies.optionSwitchSound, + optionOnSelectSound = config.optionOnSelectSound or Talkies.optionOnSelectSound, + inlineOptions = config.inlineOptions or Talkies.inlineOptions, + font = font, + fontHeight = font:getHeight(" "), + typedNotTalked = config.typedNotTalked == nil and Talkies.typedNotTalked or config.typedNotTalked, + pitchValues = config.pitchValues or Talkies.pitchValues, + + optionIndex = 1, + + showOptions = function(dialog) return dialog.messages:len() == 1 and type(dialog.options) == "table" end, + isShown = function(dialog) return Talkies.dialogs:peek() == dialog end + } + + newDialog.messageBackgroundColor = config.messageBackgroundColor or Talkies.messageBackgroundColor + newDialog.titleBackgroundColor = config.titleBackgroundColor or Talkies.titleBackgroundColor or newDialog.messageBackgroundColor + + newDialog.messageColor = config.messageColor or Talkies.messageColor + newDialog.titleColor = config.titleColor or Talkies.titleColor or newDialog.messageColor + + newDialog.messageBorderColor = config.messageBorderColor or Talkies.messageBorderColor or newDialog.messageBackgroundColor + newDialog.titleBorderColor = config.titleBorderColor or Talkies.titleBorderColor or newDialog.messageBorderColor + + Talkies.dialogs:push(newDialog) + if Talkies.dialogs:len() == 1 then + Talkies.dialogs:peek():onstart() + end + + return newDialog +end + +function Talkies.update(dt) + local currentDialog = Talkies.dialogs:peek() + if currentDialog == nil then return end + local currentMessage = currentDialog.messages:peek() + + if currentMessage.paused or currentMessage.complete then + Talkies.indicatorTimer = Talkies.indicatorTimer + (10 * dt) + if Talkies.indicatorTimer > Talkies.indicatorDelay then + Talkies.showIndicator = not Talkies.showIndicator + Talkies.indicatorTimer = 0 + end + else + Talkies.showIndicator = false + end + + if currentMessage:update(dt) then + if currentDialog.typedNotTalked then + playSound(currentDialog.talkSound) + elseif not currentDialog.talkSound:isPlaying() then + local pitch = currentDialog.pitchValues[math.random(#currentDialog.pitchValues)] + playSound(currentDialog.talkSound, pitch) + end + end +end + +function Talkies.advanceMsg() + local currentDialog = Talkies.dialogs:peek() + if currentDialog == nil then return end + currentDialog:onmessage(currentDialog.messages:len() - 1) + if currentDialog.messages:len() == 1 then + Talkies.dialogs:pop() + currentDialog:oncomplete() + if Talkies.dialogs:len() == 0 then + Talkies.clearMessages() + else + Talkies.dialogs:peek():onstart() + end + end + currentDialog.messages:pop() +end + +function Talkies.isOpen() + return Talkies.dialogs:peek() ~= nil +end + +function Talkies.draw() + local currentDialog = Talkies.dialogs:peek() + if currentDialog == nil then return end + + local currentMessage = currentDialog.messages:peek() + + --love.graphics.push() + love.graphics.setDefaultFilter("nearest", "nearest") + + local function getDimensions() + return core.screen:getDimensions() + end + + local windowWidth, windowHeight = getDimensions() + + love.graphics.setLineWidth(currentDialog.thickness) + + -- message box + local boxW = windowWidth---(2*currentDialog.padding) + local boxH = (windowHeight/3)--(2*currentDialog.padding) + local boxX = 0--currentDialog.padding + local boxY = windowHeight-(boxH+currentDialog.padding) + + -- image + local imgX, imgY, imgW, imgScale = boxX+currentDialog.padding, boxY+currentDialog.padding, 0, 0 + if currentDialog.image ~= nil then + imgScale = (boxH - (currentDialog.padding * 2)) / currentDialog.image:getHeight() + imgW = currentDialog.image:getWidth() * imgScale + end + + -- title box + local textX, textY = imgX + imgW + currentDialog.padding, boxY + 4 + + love.graphics.setFont(currentDialog.font) + + if currentDialog.title ~= "" then + local titleBoxW = currentDialog.font:getWidth(currentDialog.title)+(4*currentDialog.padding) + local titleBoxH = currentDialog.fontHeight+currentDialog.padding + local titleBoxY = boxY-titleBoxH-(currentDialog.padding/2) + local titleBoxX = currentDialog.padding * 2 + local titleX, titleY = titleBoxX + currentDialog.padding*2, titleBoxY + 2 + + -- Message title + love.graphics.setColor(currentDialog.titleBackgroundColor) + love.graphics.rectangle("fill", titleBoxX, titleBoxY, titleBoxW, titleBoxH, titleBoxH/2, titleBoxH/2) + if currentDialog.thickness > 0 then + love.graphics.setColor(currentDialog.titleBorderColor) + love.graphics.rectangle("line", boxX, titleBoxY, titleBoxW, titleBoxH, currentDialog.rounding, currentDialog.rounding) + end + love.graphics.setColor(currentDialog.titleColor) + love.graphics.print(currentDialog.title, titleX, titleY) + end + + -- Main message box + love.graphics.setColor(currentDialog.messageBackgroundColor) + love.graphics.rectangle("fill", boxX, boxY, boxW, boxH, currentDialog.rounding, currentDialog.rounding) + if currentDialog.thickness > 0 then + love.graphics.setColor(currentDialog.messageBorderColor) + love.graphics.rectangle("line", boxX, boxY, boxW, boxH, currentDialog.rounding, currentDialog.rounding) + end + + -- Message avatar + if currentDialog.image ~= nil then + love.graphics.push() + love.graphics.setColor(1, 1, 1) + love.graphics.draw(currentDialog.image, imgX, imgY, 0, imgScale, imgScale) + love.graphics.pop() + end + + -- Message text + love.graphics.setColor(currentDialog.messageColor) + local textW = boxW - imgW - (4 * currentDialog.padding) + local _, modmsg = currentDialog.font:getWrap(currentMessage.msg, textW) + local catmsg = table.concat(modmsg, "\n") + + local display = string.sub(catmsg, 1, #currentMessage.visible + #modmsg - 1) + + love.graphics.print(display, textX, textY) + + -- Message options (when shown) + if currentDialog:showOptions() and currentMessage.complete then + if currentDialog.inlineOptions then + local optionsY = textY+currentDialog.font:getHeight(currentMessage.visible)-(currentDialog.padding/1.6) + local optionLeftPad = currentDialog.font:getWidth(currentDialog.optionCharacter.." ") + for k, option in pairs(currentDialog.options) do + love.graphics.print(option[1], optionLeftPad+textX+currentDialog.padding, optionsY+((k-1)*currentDialog.fontHeight)) + end + love.graphics.print( + currentDialog.optionCharacter.." ", + textX+currentDialog.padding, + optionsY+((currentDialog.optionIndex-1)*currentDialog.fontHeight)) + else + local optionWidth = 0 + + local optionText = "" + for k, option in pairs(currentDialog.options) do + local newText = (currentDialog.optionIndex == k and currentDialog.optionCharacter or " ") .. " " .. option[1] + optionWidth = math.max(optionWidth, currentDialog.font:getWidth(newText) ) + optionText = optionText .. newText .. "\n" + end + + local optionsH = (currentDialog.font:getHeight() * #currentDialog.options) + local optionsX = math.floor((windowWidth / 2) - (optionWidth / 2)) + local optionsY = math.floor((windowHeight / 3) - (optionsH / 2)) + + love.graphics.setColor(currentDialog.messageBackgroundColor) + love.graphics.rectangle("fill", optionsX - currentDialog.padding, optionsY - currentDialog.padding, optionWidth + currentDialog.padding * 2, optionsH + currentDialog.padding * 2, currentDialog.rounding, currentDialog.rounding) + + if currentDialog.thickness > 0 then + love.graphics.setColor(currentDialog.messageBorderColor) + love.graphics.rectangle("line", optionsX - currentDialog.padding, optionsY - currentDialog.padding, optionWidth + currentDialog.padding * 2, optionsH + currentDialog.padding * 2, currentDialog.rounding, currentDialog.rounding) + end + + love.graphics.setColor(currentDialog.messageColor) + love.graphics.print(optionText, optionsX, optionsY) + end + end + + -- Next message/continue indicator + if Talkies.showIndicator then + love.graphics.print(currentDialog.indicatorCharacter, boxX+boxW-(4*currentDialog.padding), boxY+boxH-currentDialog.fontHeight) + end + + --love.graphics.pop() +end + +function Talkies.prevOption() + local currentDialog = Talkies.dialogs:peek() + if currentDialog == nil or not currentDialog:showOptions() then return end + currentDialog.optionIndex = currentDialog.optionIndex - 1 + if currentDialog.optionIndex < 1 then currentDialog.optionIndex = #currentDialog.options end + playSound(currentDialog.optionSwitchSound) +end + +function Talkies.nextOption() + local currentDialog = Talkies.dialogs:peek() + if currentDialog == nil or not currentDialog:showOptions() then return end + currentDialog.optionIndex = currentDialog.optionIndex + 1 + if currentDialog.optionIndex > #currentDialog.options then currentDialog.optionIndex = 1 end + playSound(currentDialog.optionSwitchSound) +end + +function Talkies.onAction() + local currentDialog = Talkies.dialogs:peek() + if currentDialog == nil then return end + local currentMessage = currentDialog.messages:peek() + + if currentMessage.paused then currentMessage:resume() + elseif not currentMessage.complete then currentMessage:finish() + else + if currentDialog:showOptions() then + currentDialog.options[currentDialog.optionIndex][2]() -- Execute the selected function + playSound(currentDialog.optionOnSelectSound) + end + Talkies.advanceMsg() + end +end + +function Talkies.clearMessages() + Talkies.dialogs = Fifo.new() +end + +return Talkies diff --git a/birb/modules/timers/libs/tween.lua b/birb/libs/tween.lua similarity index 100% rename from birb/modules/timers/libs/tween.lua rename to birb/libs/tween.lua diff --git a/birb/modules/assets/init.lua b/birb/modules/assets/init.lua index 9a116f0..b9d7247 100644 --- a/birb/modules/assets/init.lua +++ b/birb/modules/assets/init.lua @@ -1,5 +1,5 @@ --- modules/assets/import :: a simple assets importer, to import easily everything into --- the asset manager. +-- modules/assets :: a simple assets manager, aim to put every assets in a simple +-- serie of table in order to find them easily. --[[ Copyright © 2019 Kazhnuz @@ -36,241 +36,262 @@ local Tileset = require(cwd .. "tileset") local Autotile = require(cwd .. "autotile") local Background = require(cwd .. "background") -local SFX = require(cwd .. "sfx") +local SFX = require(cwd .. "sfx") -- INIT FUNCTIONS -- Initilizing and configuring option -function Assets:new(isGlobal) - self.isGlobal = isGlobal +function Assets:new() + self:clear() + + self.isActive = true end function Assets:clear() - if (self.isGlobal) then - core.assets:clear() - else - core.assets:clearLocal() - end + -- TODO: destroy individually each texture/image when assets are cleared + self:clearSprites() + self:clearSFX() + self:clearFonts() + self:resetMusic() + self:clearBackgrounds() + self:clearFonts() + self:clearTileset() + + self:clearImages() end --- WRAPPER FUNCTIONS --- Basic wrappers to ensure compatibility - -function Assets:get(key) - return core.assets:get(key) -end - -function Assets:getFont(key) - return self:getWithType(key, "font") -end - -function Assets:getWithType(key, type) - return core.assets:get(key) -end - -function Assets:draw(name, x, y, r, sx, sy, ox, oy, kx, ky) - core.assets:draw(name, x, y, r, sx, sy, ox, oy, kx, ky) -end - -function Assets:newSFX(name, filepath) - self:addSFX(name, filepath) -end - -function Assets:addImage(name, filename) - self:addTexture(name, filename) -end - -function Assets:playSFX(name) - core.assets:playSFX(name) -end - -function Assets:drawImage(name, x, y, r, sx, sy, ox, oy, kx, ky) - self:draw(name, x, y, r, sx, sy, ox, oy, kx, ky) -end - --- Music - -function Assets:setMusic(filename, loop) - core.debug:logDebug("assets", "Assets:setMusic is deprecated") - core.music:addMusic(filename, true) -end - -function Assets:silence() - core.debug:logDebug("assets", "Assets:silence is deprecated") - core.music:silence() -end - -function Assets:resetMusic() - core.debug:logDebug("assets", "Assets:resetMusic is deprecated") - core.music:purge() -end - -function Assets:playMusic() - core.debug:logDebug("assets", "Assets:playMusic is deprecated") - core.music:playMusic() -end - --- Activity - -function Assets:setActivity(activity) - core.assets:setActivity(activity) -end - -function Assets:switchActivity() - core.assets:switchActivity() -end - -function Assets:getActivity() - core.assets:getActivity() +function Assets:update(dt) + if (self.isActive) then + self:animationsUpdate(dt) + end end -- IMPORT FUNCTIONS -- Easilly import assets function Assets:batchImport(datafile) - local datas = require(datafile) + local datas = require(datafile) - for asset_type, assets in pairs(datas) do - if (asset_type == "autotiles") then - self:importAutotiles(assets) - elseif (asset_type == "backgrounds") then - self:importBackgrounds(assets) - elseif (asset_type == "fonts") then - self:importFonts(assets) - elseif (asset_type == "imagefonts") then - self:importImageFonts(assets) - elseif (asset_type == "images") then - self:importTextures(assets) - elseif (asset_type == "sprites") then - self:importSprites(assets) - elseif (asset_type == "textures") then - self:importTextures(assets) - elseif (asset_type == "tilesets") then - self:importTilesets(assets) - elseif (asset_type == "sfx") then - self:importSFX(assets) - else - core.debug:logWarn("assets/importer", "unkown asset type " .. asset_type) - end + for asset_type, assets in pairs(datas) do + if (asset_type == "autotiles") then + self:importAutotiles(assets) + elseif (asset_type == "backgrounds") then + self:importBackgrounds(assets) + elseif (asset_type == "fonts") then + self:importFonts(assets) + elseif (asset_type == "imagefonts") then + self:importImageFonts(assets) + elseif (asset_type == "images") then + self:importTextures(assets) + elseif (asset_type == "sprites") then + self:importSprites(assets) + elseif (asset_type == "textures") then + self:importTextures(assets) + elseif (asset_type == "tilesets") then + self:importTilesets(assets) + elseif (asset_type == "sfx") then + self:importSFX(assets) + else + core.debug:warning("assets/importer", "unkown asset type " .. asset_type) end + end end function Assets:importAutotiles(assets) - for i, asset in ipairs(assets) do - self:addAutotile(asset[1], asset[2]) - end + for i, asset in ipairs(assets) do + self:addAutotile(asset[1], asset[2]) + end end function Assets:importBackgrounds(assets) - for i, asset in ipairs(assets) do - self:addBackground(asset[1], asset[2]) - end + for i, asset in ipairs(assets) do + self:addBackground(asset[1], asset[2]) + end end function Assets:importFonts(assets) - for i, asset in ipairs(assets) do - self:addFont(asset[1], asset[2], asset[3]) - end + for i, asset in ipairs(assets) do + self:addFont(asset[1], asset[2], asset[3]) + end end function Assets:importImageFonts(assets) - for i, asset in ipairs(assets) do - self:addImageFont(asset[1], asset[2], asset[3]) - end + for i, asset in ipairs(assets) do + self:addImageFont(asset[1], asset[2], asset[3]) + end end function Assets:importSprites(assets) - for i, asset in ipairs(assets) do - self:addSprite(asset[1], asset[2]) - end + for i, asset in ipairs(assets) do + self:addSprite(asset[1], asset[2]) + end end function Assets:importTextures(assets) - for i, asset in ipairs(assets) do - self:addImage(asset[1], asset[2]) - end + for i, asset in ipairs(assets) do + self:addImage(asset[1], asset[2]) + end end function Assets:importTilesets(assets) - for i, asset in ipairs(assets) do - self:addTileset(asset[1], asset[2]) - end + for i, asset in ipairs(assets) do + self:addTileset(asset[1], asset[2]) + end end function Assets:importSFX(assets) - for i, asset in ipairs(assets) do - self:addSFX(asset[1], asset[2]) - end + for i, asset in ipairs(assets) do + self:addSFX(asset[1], asset[2]) + end end --- ADD FUNCTIONS --- Different wrapper to create easily asset objects - -function Assets:add(name, assetObject) - core.assets:add(name, assetObject, self.isGlobal) -end - -function Assets:addBackground(name, filepath) - self:add(name, Background(filepath)) -end - -function Assets:addSprite(name, filepath) - self:add(name, Sprite(filepath)) -end - -function Assets:addFont(key, filename, size) - self:add(key, Font(filename, size)) -end - -function Assets:addImageFont(key, filename, extraspacing) - self:add(key, ImageFont(filename, extraspacing)) -end - -function Assets:addTileset(name, filepath) - self:add(name, Tileset(filepath)) -end - -function Assets:addAutotile(name, tilesize) - self:add(name, Autotile(name, tilesize)) -end +-- SFX & MUSICS +-- Handle sound effects and musics function Assets:addSFX(name, filepath) - self:add(name, SFX(filepath)) + self:newSFX(name, filepath) end -function Assets:addTexture(name, filename) - self:add(name, Texture(filename)) -end - --- DEPRECATED FUNCTIONS --- Don't do anything and will be removed soon - -function Assets:clearFonts() - core.debug:logDebug("assets", "Assets:clearFonts is deprecated") -end - -function Assets:clearTileset() - core.debug:logDebug("assets", "Assets:clearTileset is deprecated") -end - -function Assets:clearAutotile() - core.debug:logDebug("assets", "Assets:clearAutotile is deprecated") +function Assets:newSFX(name, filepath) + self.sfx[name] = SFX( filepath ) end function Assets:clearSFX() - core.debug:logDebug("assets", "Assets:clearSFX is deprecated") + love.audio.stop( ) + self.sfx = {} end -function Assets:clearBackgrounds() - core.debug:logDebug("assets", "Assets:clearBackgrounds is deprecated") +function Assets:playSFX(filename) + if not (self.sfx[filename] == nil) then + self.sfx[filename]:play() + end end -function Assets:clearSprites() - core.debug:logDebug("assets", "Assets:clearSprites is deprecated") +-- MUSIC FUNCTIONS +-- All thse functions are deprecated, prefer core.music + +function Assets:setMusic(filename, loop) + core.debug:warning("assets", "Assets:setMusic is deprecated") + core.music:skip() + core.music:addMusic(filename, (loop ~= false)) + core.music:playMusic() +end + +function Assets:silence() + core.debug:warning("assets", "Assets:silence is deprecated") + core.music:silence() +end + +function Assets:resetMusic() + core.debug:warning("assets", "Assets:resetMusic is deprecated") + core.music:purge() +end + +function Assets:playMusic() + core.debug:warning("assets", "Assets:playMusic is deprecated") + core.music:playMusic() +end + +-- IMAGES FUNCTIONS +-- Create directly texture items + +function Assets:addImage(name, filename) + self.images[name] = Texture(filename) +end + +function Assets:drawImage(name, x, y, r, sx, sy, ox, oy, kx, ky) + self.images[name]:draw(x, y, r, sx, sy, ox, oy, kx, ky) end function Assets:clearImages() - core.debug:logDebug("assets", "Assets:clearImages is deprecated") + self.images = {} +end + +-- BACKGROUNDS FUNCTIONS +-- Automatic tiling texture + +function Assets:addBackground(name, filepath) + -- TODO: rework entirely background to work at any size + self.backgrounds[name] = Background(filepath) +end + +function Assets:clearBackgrounds() + self.backgrounds = {} +end + +-- SPRITES FUNCTIONS +-- Animated tileset + +function Assets:addSprite(name, filepath) + self.sprites[name] = Sprite(filepath) +end + +function Assets:animationsUpdate(dt) + for i,v in pairs(self.sprites) do + v:update(dt) + end +end + +function Assets:clearSprites() + self.sprites = {} +end + +-- FONTS FUNCTIONS +-- Handles fonts and imagesfonts + +function Assets:addFont(key, filename, size) + local font = Font(filename, size) + self.fonts[key] = font +end + +function Assets:addImageFont(key, filename, extraspacing) + local font = ImageFont(filename, extraspacing) + self.fonts[key] = font +end + +function Assets:getFont(filename) + return self.fonts[filename] +end + +function Assets:clearFonts() + self.fonts = {} +end + +-- TILESET FUNCTIONS +-- Automatically create quads for a texture + +function Assets:addTileset(name, filepath) + self.tileset[name] = Tileset(filepath) +end + +function Assets:clearTileset() + self.tileset = {} +end + +-- AUTOTILE FUNCTIONS +-- Automatically draw tiles + +function Assets:addAutotile(name, tilesize) + self.autotile[name] = Autotile(name, tilesize) +end + +function Assets:clearAutotile() + self.autotile = {} +end + +-- ACTIVITY FUNCTIONS +-- Handle activity + +function Assets:setActivity(activity) + self.isActive = activity +end + +function Assets:switchActivity() + self.isActive = (self.isActive == false) +end + +function Assets:getActivity() + return self.isActive end return Assets diff --git a/birb/modules/assets/types/animator.lua b/birb/modules/assets/types/animator.lua index c5e322f..38a7f3f 100644 --- a/birb/modules/assets/types/animator.lua +++ b/birb/modules/assets/types/animator.lua @@ -35,6 +35,7 @@ function Animator:new(sprite) self.animationData = {} self.customSpeed = 0 + self.speedFactor = 1 self:changeToDefaultAnimation() end @@ -43,12 +44,16 @@ function Animator:setCustomSpeed(customSpeed) self.customSpeed = customSpeed or 0 end +function Animator:setSpeedFactor(speedFactor) + self.speedFactor = speedFactor or 1 +end + -- UPDATE FUNCTIONS -- Update the animation of the animator function Animator:update(dt) if (self.currentAnimation == "") then - core.debug:logWarn("animator", "no current animation data") + core.debug:warning("animator", "no current animation data") return 0 end @@ -56,16 +61,17 @@ function Animator:update(dt) if (self.animationData.speed) == -1 then speed = self.customSpeed --math.abs(self.xsp / 16) end - self.frameTimer = self.frameTimer + (speed * dt) + self.frameTimer = self.frameTimer + (speed * dt * self.speedFactor) if self.frameTimer > 1 then self.frameTimer = 0 if self.frame == self.animationData.endAt then - self:sendCallback() if not (self.animationData.pauseAtEnd) then self.frame = self.animationData.loop end + self:sendCallback() else self.frame = self.frame + 1 + self:sendFrameSignal() end end end @@ -124,17 +130,39 @@ end -- CALLBACK FUNCTIONS -- Handle getting a calback from the animation system -function Animator:setCallbackTarget(callbackTarget) - self.callbackTarget = callbackTarget +function Animator:setCallbackTarget(actor) + self.actor = actor +end + +function Animator:setCallback(actor) + core.debug:warning("Animator", "Animator:setCallback is deprecated, prefer Animator:setCallbackTarget instead") + self:setCallbackTarget(actor) end function Animator:sendCallback() - if (self.callbackTarget ~= nil) then - if (self.callbackTarget.animationEnded ~= nil) then - self.callbackTarget:animationEnded(self.currentAnimation) + if (self.actor ~= nil) then + self.actor:animationEnded(self.currentAnimation) + end +end + +function Animator:sendFrameSignal() + if (self.animationData.signal ~= nil) then + if (type(self.animationData.signal[1]) ~= "table") then + self:trySendSignal(self:getRelativeFrame(), self.animationData.signal) + else + for _, signal in ipairs(self.animationData.signal) do + self:trySendSignal(self:getRelativeFrame(), signal) + end end end end + +function Animator:trySendSignal(frame, signal) + if (signal[1] == frame) and (self.actor ~= nil) and (self.actor.receiveFrameSignal ~= nil) then + self.actor:receiveFrameSignal(signal[2]) + end +end + -- DRAW FUNCTIONS -- Draw animations using these functions diff --git a/birb/modules/assets/types/fonts.lua b/birb/modules/assets/types/fonts.lua index a0f052a..ab09919 100644 --- a/birb/modules/assets/types/fonts.lua +++ b/birb/modules/assets/types/fonts.lua @@ -64,7 +64,6 @@ function Font:setAlign(align) end function Font:setFilter(filter) - local filter = filter or "" self.filter = filter end @@ -94,14 +93,6 @@ function Font:getColor() return self.color end -function Font:getFilter() - return self.filter -end - -function Font:haveFilter() - return ((self.filter ~= "") and (self.filter ~= nil)) -end - -- DRAW FUNCTIONS -- print text using theses functions @@ -149,8 +140,8 @@ function Font:applyFilter(text, x, y, limit, align, r, sx, sy, ox, oy, kx, ky) end function Font:applyFilterShadow(text, x, y, limit, align, r, sx, sy, ox, oy, kx, ky) - love.graphics.setColor(0, 0, 0, 1) - self:printf(text, x+1, y+1, limit, align, align, r, sx, sy, ox, oy, kx, ky) + love.graphics.setColor(0, 0, 0, self.color.a) + self:printf(text, x+1, y+1, limit, align, r, sx, sy, ox, oy, kx, ky) utils.graphics.resetColor() end diff --git a/birb/modules/assets/types/sfx.lua b/birb/modules/assets/types/sfx.lua index 2660f33..5b04c02 100644 --- a/birb/modules/assets/types/sfx.lua +++ b/birb/modules/assets/types/sfx.lua @@ -1,7 +1,7 @@ --- assets/sfx :: the sfx object, essentially used to be able to just have an sfx +-- assets/sfx :: the sfx object --[[ - Copyright © 2020 Kazhnuz + Copyright © 2021 Kazhnuz 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 @@ -20,21 +20,31 @@ 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 SFX = Object:extend() -- INIT FUNCTIONS -- Initilizing and configuring option function SFX:new(filepath) - self.sound = love.audio.newSource(filepath, "static") + self.source = love.audio.newSource(filepath, "static") end +-- INFO FUNCTIONS +-- get information with these functions + +-- None for the moment + +-- DRAW FUNCTIONS +-- Draw texture using these functions + function SFX:play() - self.sound:stop() - self.sound:setVolume(core.options.data.audio.sfx / 100) - love.audio.play(self.sound) + self.source:stop() + self.source:setVolume(core.options.data.audio.sfx / 100) + love.audio.play(self.source) +end + +function SFX:stop() + self.source:stop() end return SFX diff --git a/birb/modules/assets/types/sprites.lua b/birb/modules/assets/types/sprites.lua index f33b919..7f21a22 100644 --- a/birb/modules/assets/types/sprites.lua +++ b/birb/modules/assets/types/sprites.lua @@ -63,6 +63,10 @@ function Sprite:changeAnimation(name, restart) self.animator:changeAnimation(name, restart) end +function Sprite:setSpeedFactor(speedFactor) + self.animator:setSpeedFactor(speedFactor) +end + -- INFO FUNCTIONS -- get information with these functions @@ -93,11 +97,11 @@ end -- DRAW FUNCTIONS -- Draw sprites using these functions -function Sprite:drawAnimation(x, y, r, sx, sy, ox, oy, kx, ky) +function Sprite:draw(x, y, r, sx, sy, ox, oy, kx, ky) self.animator:draw(x, y, r, sx, sy, ox, oy, kx, ky) end -function Sprite:drawAnimationMask(x, y, r, sx, sy, ox, oy, kx, ky) +function Sprite:drawMask(x, y, r, sx, sy, ox, oy, kx, ky) self.animator:drawMask(x, y, r, sx, sy, ox, oy, kx, ky) end @@ -118,7 +122,7 @@ function Sprite:drawPart(x, y, w, h, r, sx, sy, ox, oy, kx, ky) end love.graphics.setScissor(x - ox, y - oy, w, h) - self:drawAnimation(x, y, r, sx, sy, ox, oy, kx, ky) + self:draw(x, y, r, sx, sy, ox, oy, kx, ky) love.graphics.setScissor( ) end diff --git a/birb/modules/gamesystem/init.lua b/birb/modules/gamesystem/init.lua deleted file mode 100644 index 5841f16..0000000 --- a/birb/modules/gamesystem/init.lua +++ /dev/null @@ -1,144 +0,0 @@ --- game :: The main game subsystem. Basically a big object that handle all the --- game-related data like characters, monsters, etc. While the core aim to be --- reusable at will, the game is specifically made for the current game. - --- It's also what handle the savedata for games - ---[[ - Copyright © 2019 Kazhnuz - - Permission is hereby granted, free of charge, to any person obtaining a copy of - this software and associated documentation files (the "Software"), to deal in - the Software without restriction, including without limitation the rights to - use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - the Software, and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -]] - -local cwd = (...):gsub('%.init$', '') .. "." - -local GameSystem = Object:extend() -local binser = require("birb.libs.binser") - -local DEFAULT_SAVENUMBER = 3 - -function GameSystem:new() - self.currentSlot = -1 - - self.submodules = {} - self.playtime = 0 - self:register() -end - -function GameSystem:register() - core:registerGameSystem(self) -end - -function GameSystem:registerSubmodules(submodule) - local name = submodule.name - self.submodules[name] = submodule -end - --- UPDATE FUNCTIONS --- Update every submodules - -function GameSystem:update(dt) - self.playtime = self.playtime + dt - for k, submodule in pairs(self.submodules) do - submodule:update(dt) - end -end - --- DATA MANAGEMENT FUNCTIONS --- Get and set data in the gamesystem object - -function GameSystem:setData(data) - local data = data - self.playtime = data.playtime - for k, submodule in pairs(self.submodules) do - submodule:setData(data[k]) - end -end - -function GameSystem:getData() - local data = {} - data.playtime = self.playtime - for k, submodule in pairs(self.submodules) do - data[k] = submodule:getData() - end - return data -end - --- SAVE MANAGEMENT FUNCTIONS --- Get and set data in the gamesystem object - -function GameSystem:getSaveNumber() - return DEFAULT_SAVENUMBER -end - -function GameSystem:resetSave(saveid) - if utils.filesystem.exists("save" .. saveid .. ".save") then - love.filesystem.remove( "save" .. saveid .. ".save" ) - end -end - -function GameSystem:resetAllSaves() - for i=1, self:getSaveNumber() do - self:resetSave(i) - end -end - -function GameSystem:getSavePath(saveid, absolute) - local saveDir = "" - if (absolute) then - saveDir = love.filesystem.getSaveDirectory() .. "/" - if not utils.filesystem.exists(saveDir) then - love.filesystem.createDirectory( "" ) - end - end - - local filepath = saveDir .. self:getSaveName(saveid) - - return filepath -end - -function GameSystem:getSaveName(saveid) - return "save" .. saveid .. ".save" -end - -function GameSystem:saveFileExist(saveid) - return utils.filesystem.exists(self:getSaveName(saveid)) -end - -function GameSystem:read(saveid) - self.currentSlot = saveid or self.currentSlot - if (self.currentSlot > 0) then - local savepath = self:getSavePath(self.currentSlot, true) - if self:saveFileExist(self.currentSlot) then - local datas = binser.readFile(savepath) - - self:setData(datas[1]) - end - end -end - -function GameSystem:write() - if (self.currentSlot > 0) then - local data = self:getData() - - local savepath = self:getSavePath(self.currentSlot, true) - binser.writeFile(savepath, data) - end -end - -return GameSystem diff --git a/birb/modules/gamesystem/submodule.lua b/birb/modules/gamesystem/submodule.lua deleted file mode 100644 index 5ea5486..0000000 --- a/birb/modules/gamesystem/submodule.lua +++ /dev/null @@ -1,23 +0,0 @@ -local SubModule = Object:extend() - -function SubModule:new(game, name) - self.name = name or error("SUBMODULE must have a name") - self.game = game - self.data = {} - - self:register() -end - -function SubModule:register() - self.game:registerSubmodules(self) -end - -function SubModule:getData() - return self.data -end - -function SubModule:setData(data) - self.data = data -end - -return SubModule diff --git a/birb/modules/gui/elements/assets.lua b/birb/modules/gui/elements/assets.lua new file mode 100644 index 0000000..b12ca50 --- /dev/null +++ b/birb/modules/gui/elements/assets.lua @@ -0,0 +1,16 @@ +local Parent = require "birb.modules.gui.elements.drawable" +local AssetElement = Parent:extend() + +function AssetElement:new(name, assetType, assetName, x, y,r,sx,sy,ox,oy, opacity) + self:initWrapper() + local asset = self.assets[assetType][assetName] + assert(asset ~= nil, assetName .. ' (' .. assetType .. ") doesn't exist") + + AssetElement.super.new(self, name, asset, x, y,r,sx,sy,ox,oy, opacity) +end + +function AssetElement:draw() + self.drawable:draw(self.x,self.y,self.r,self.sx,self.sy,self.ox,self.oy) +end + +return AssetElement \ No newline at end of file diff --git a/birb/modules/gui/elements/canvas.lua b/birb/modules/gui/elements/canvas.lua new file mode 100644 index 0000000..7fb1e23 --- /dev/null +++ b/birb/modules/gui/elements/canvas.lua @@ -0,0 +1,96 @@ +local Parent = require "birb.modules.gui.elements.parent" +local CanvasElement = Parent:extend() + +function CanvasElement:new(name, x, y, w, h, r,sx,sy,ox,oy, opacity) + self:initCanvas() + CanvasElement.super.new(self, name, x, y, w, h) + self.r = r or 0 + self.sx, self.sy = sx or 1, sy or 1 + self.ox, self.oy = self:parseOrigin(ox, w), self:parseOrigin(oy, h) + self.opacity = opacity or 1 +end + +function CanvasElement:initCanvas() + self.canvas = {} + self.canvas.needRedraw = true + self.canvas.texture = nil + self.canvas.isAnimated = false + self.canvas.padding = 8 + self.canvas.final = nil + self.canvas.dual = false +end + +function CanvasElement:updateElement(dt) + CanvasElement.super.updateElement(self, dt) +end + +function CanvasElement:getCanvasDimensions() + return self:getDimensions() +end + +function CanvasElement:redraw() + if (self.canvas.needRedraw or self.canvas.isAnimated) then + self:generateTexture() + end + + if (self.canvas.dual) then + local w, h = self:getDimensions() + local canvas = love.graphics.newCanvas(w + (self.canvas.padding*2), h + (self.canvas.padding*2)) + love.graphics.setCanvas(canvas) + + love.graphics.draw(self.canvas.texture, 0, 0) + self:drawFinalTexture() + + self.canvas.final = canvas + love.graphics.setCanvas() + end +end + +function CanvasElement:generateTexture() + local w, h = self:getDimensions() + + local canvas = love.graphics.newCanvas(w + (self.canvas.padding*2), h + (self.canvas.padding*2)) + love.graphics.setCanvas(canvas) + + self:drawTexture() + self.canvas.needRedraw = false + love.graphics.setCanvas() + if (self.canvas.isAnimated) then + self.canvas.texture = canvas + else + local imageData = canvas:newImageData() + self.canvas.texture = love.graphics.newImage(imageData) + canvas:release() + imageData:release() + end +end + +function CanvasElement:drawTexture() + +end + +function CanvasElement:drawFinalTexture() + +end + +function CanvasElement:parseOrigin(origin, size) + if (origin == "center") then + return size/2 + elseif (origin == "end") then + return size + else + return origin or 0 + end +end + +function CanvasElement:draw() + love.graphics.setColor(1, 1, 1, self.opacity) + local texture = self.canvas.texture + if (self.canvas.dual) then + texture = self.canvas.final + end + love.graphics.draw(texture, self.x - self.canvas.padding,self.y - self.canvas.padding,self.r,self.sx,self.sy,self.ox,self.oy) + love.graphics.setColor(1, 1, 1, 1) +end + +return CanvasElement \ No newline at end of file diff --git a/birb/modules/gui/elements/color.lua b/birb/modules/gui/elements/color.lua new file mode 100644 index 0000000..f1aa94f --- /dev/null +++ b/birb/modules/gui/elements/color.lua @@ -0,0 +1,19 @@ +local Parent = require "birb.modules.gui.elements.parent" +local ColorElement = Parent:extend() + +function ColorElement:new(name, r, g, b, opacity) + local w, h = core.screen:getDimensions() + ColorElement.super.new(self, name, self.x, self.y, w, h) + self.r = r or 1 + self.g = g or 1 + self.b = b or 1 + self.opacity = opacity or 1 +end + +function ColorElement:draw() + love.graphics.setColor(self.r, self.g, self.b, self.opacity) + love.graphics.rectangle("fill", 0, 0, self.w, self.h) + utils.graphics.resetColor() +end + +return ColorElement \ No newline at end of file diff --git a/birb/modules/gui/elements/composite.lua b/birb/modules/gui/elements/composite.lua new file mode 100644 index 0000000..d4d9aff --- /dev/null +++ b/birb/modules/gui/elements/composite.lua @@ -0,0 +1,35 @@ +local Parent = require "birb.modules.gui.elements.parent" +local CompositeElement = Parent:extend() + +function CompositeElement:new(name, x, y, childrenList) + self.children = {} + self:addChildren(childrenList) + CompositeElement.super.new(self, name, x, y, 1, 1) + self.isVisible = true +end + +function CompositeElement:addChildren(list) + for _, childData in ipairs(list) do + self:addChild(childData[1], childData[2], childData[3]) + end +end + +function CompositeElement:addChild(children, relx, rely) + local child = {} + child.name = children.name + child.relx = relx + child.rely = rely + table.insert(self.children, child) +end + +function CompositeElement:update(dt) + for _, child in ipairs(self.children) do + local childElement = self.gui.elements[child.name] + childElement.x = self.x + child.relx + childElement.y = self.y + child.rely + childElement.isVisible = self.isVisible + childElement.depth = self.depth + end +end + +return CompositeElement \ No newline at end of file diff --git a/birb/modules/gui/elements/counter.lua b/birb/modules/gui/elements/counter.lua new file mode 100644 index 0000000..2730996 --- /dev/null +++ b/birb/modules/gui/elements/counter.lua @@ -0,0 +1,13 @@ +local Parent = require "birb.modules.gui.elements.variable" +local CounterElement = Parent:extend() + +function CounterElement:new(name, fontName, object, varName, nbrs, x, y, align) + CounterElement.super.new(self, name, fontName, object, varName, x, y, align) + self.nbrs = nbrs or 0 +end + +function CounterElement:getText() + return utils.math.numberToString(CounterElement.super.getText(self), self.nbrs) +end + +return CounterElement \ No newline at end of file diff --git a/birb/modules/gui/elements/drawable.lua b/birb/modules/gui/elements/drawable.lua new file mode 100644 index 0000000..e2ac258 --- /dev/null +++ b/birb/modules/gui/elements/drawable.lua @@ -0,0 +1,31 @@ +local Parent = require "birb.modules.gui.elements.parent" +local DrawableElement = Parent:extend() + +function DrawableElement:new(name, drawable, x, y,r,sx,sy,ox,oy, opacity) + self.drawable = drawable + + local w, h = self.drawable:getDimensions() + DrawableElement.super.new(self, name, x, y, w, h) + self.r = r or 0 + self.sx, self.sy = sx or 1, sy or 1 + self.ox, self.oy = self:parseOrigin(ox, w), self:parseOrigin(oy, h) + self.opacity = opacity or 1 +end + +function DrawableElement:parseOrigin(origin, size) + if (origin == "center") then + return size/2 + elseif (origin == "end") then + return size + else + return origin or 0 + end +end + +function DrawableElement:draw() + love.graphics.setColor(1, 1, 1, self.opacity) + love.graphics.draw(self.drawable, self.x,self.y,self.r,self.sx,self.sy,self.ox,self.oy) + love.graphics.setColor(1, 1, 1, 1) +end + +return DrawableElement \ No newline at end of file diff --git a/birb/modules/gui/elements/parent.lua b/birb/modules/gui/elements/parent.lua new file mode 100644 index 0000000..aa73138 --- /dev/null +++ b/birb/modules/gui/elements/parent.lua @@ -0,0 +1,157 @@ +local Rect = require "birb.classes.2D.rect" +local GuiElement = Rect:extend() + +local TweenManager = require "birb.classes.time" + +function GuiElement:new(name, x, y, w, h) + GuiElement.super.new(self, x, y, w, h) + self.name = name + + self.isVisible = true + self.screen = nil + + self.depth = 10 + + self.tweens = TweenManager(self) + self:initWrapper() + + self:register() +end + +function GuiElement:initWrapper() + self.scene = core.scenemanager.nextScene or core.scenemanager.currentScene + self.gui = self.scene.gui + self.assets = self.scene.assets +end + +function GuiElement:setKeyPressAction(func) + self.func = func +end + +function GuiElement:register() + self.creationId = self.gui:addElement(self.name, self) +end + +function GuiElement:destroy() + self.gui:deleteElement(self.name) + if (self.screen ~= nil) then + self.screen:deleteElement(self.name) + end +end + +-- VISIBILITY/ACTIVITY +-- Handle drawing and how we interact with + +function GuiElement:setDepth(depth) + self.depth = depth or 0 +end + +function GuiElement:getVisibility() + if (self.screen ~= nil) then + return (self.isVisible and self.screen.isVisible) + else + return self.isVisible + end +end + +function GuiElement:setVisibility(visibility) + self.isVisible = visibility +end + +function GuiElement:getFocus(widgetId, page) + self.gui:setFocus(self.name, widgetId, page) +end + +function GuiElement:haveFocus() + return (self.gui.focusedElement == self.name) +end + +function GuiElement:looseFocus() + if (self:haveFocus()) then + self.gui:removeFocus() + end +end + +function GuiElement:setSubFocus() + -- Useless for basic element +end + +function GuiElement:isTransforming() + return self.tweens:haveTween() +end + +-- UPDATE FUNCTIONS +-- Update the menu every game update + +-- External update function +function GuiElement:updateElement(dt) + self:update(dt) + self.tweens:update(dt) +end + +-- Internal update function +function GuiElement:update(dt) + -- Cette fonction ne contient rien par défaut +end + +-- TWEEN FUNCTIONS +-- Handle tweening + +function GuiElement:newTween(start, duration, target, easing) + self.tweens:newTween(start, duration, target, easing) +end + +function GuiElement:newMovement(start, duration, x, y, easing) + self:newTween(start, duration, {x = x, y = y}, easing) +end + +function GuiElement:newSwitch(start, bools) + self.tweens:newSwitch(start, bools) +end + +function GuiElement:newFunc(start, name, func) + self.tweens:newFunc(start, name, func) +end + +function GuiElement:delayFocus(start) + self.tweens:newFunc(start, "focus", function () + self:getFocus() + end) +end + +-- DRAW FUNCTIONS +-- Draw the menu and its content + +function GuiElement:redraw() + +end + +function GuiElement:drawElement() + self:draw() +end + +function GuiElement:draw() + -- nothing here +end + +-- KEYBOARD FUNCTIONS +-- Handle key press + +function GuiElement:keypressed(key) + if (self.func ~= nil) then + self.func(key) + end +end + +-- MOUSE FUNCTIONS +-- Handle pointers (clic/touch) + +function GuiElement:mousemoved(x, y) + -- Cette fonction ne contient rien par défaut +end + +function GuiElement:mousepressed(x, y, button, istouch) + -- Cette fonction ne contient rien par défaut +end + +return GuiElement \ No newline at end of file diff --git a/birb/modules/gui/elements/text.lua b/birb/modules/gui/elements/text.lua new file mode 100644 index 0000000..0db3ec0 --- /dev/null +++ b/birb/modules/gui/elements/text.lua @@ -0,0 +1,23 @@ +local Parent = require "birb.modules.gui.elements.parent" +local TextElement = Parent:extend() + +function TextElement:new(name, fontName, text, x, y, align) + TextElement.super.new(self, name, x, y, 1, 1) + self.text = text + self.font = self.assets.fonts[fontName] + + self.align = align + self.opacity = 1 +end + +function TextElement:getText() + return self.text +end + +function TextElement:draw() + self.font:setColor(1, 1, 1, self.opacity) + self.font:draw(self:getText(), self.x, self.y, -1, self.align) + love.graphics.setColor(1, 1, 1, 1) +end + +return TextElement \ No newline at end of file diff --git a/birb/modules/gui/elements/tile.lua b/birb/modules/gui/elements/tile.lua new file mode 100644 index 0000000..8ae9f46 --- /dev/null +++ b/birb/modules/gui/elements/tile.lua @@ -0,0 +1,19 @@ +local Parent = require "birb.modules.gui.elements.drawable" +local TileElement = Parent:extend() + +function TileElement:new(name, assetName, id, x, y,r,sx,sy,ox,oy, opacity) + self:initWrapper() + local asset = self.assets.tileset[assetName] + assert(asset ~= nil, assetName .. " ( tileset ) doesn't exist") + self.tileId = id + + TileElement.super.new(self, name, asset, x, y,r,sx,sy,ox,oy, opacity) +end + +function TileElement:draw() + love.graphics.setColor(1, 1, 1, self.opacity) + self.drawable:drawTile(self.tileId, self.x,self.y,self.r,self.sx,self.sy,self.ox,self.oy) + utils.graphics.resetColor() +end + +return TileElement \ No newline at end of file diff --git a/birb/modules/gui/elements/variable.lua b/birb/modules/gui/elements/variable.lua new file mode 100644 index 0000000..32a95b4 --- /dev/null +++ b/birb/modules/gui/elements/variable.lua @@ -0,0 +1,14 @@ +local Parent = require "birb.modules.gui.elements.text" +local VariableElement = Parent:extend() + +function VariableElement:new(name, fontName, object, varName, x, y, align) + VariableElement.super.new(self, name, fontName, "", x, y, align) + self.object = object + self.variable = varName +end + +function VariableElement:getText() + return self.object[self.variable] +end + +return VariableElement \ No newline at end of file diff --git a/birb/modules/gui/init.lua b/birb/modules/gui/init.lua new file mode 100644 index 0000000..2f2d7ce --- /dev/null +++ b/birb/modules/gui/init.lua @@ -0,0 +1,187 @@ +-- modules/gui :: a simple gui system, that manage all overhead elements of the game. + +--[[ + Copyright © 2021 Kazhnuz + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +]] + +local Gui = Object:extend() + +local ElementList = require "birb.modules.gui.mixins.elements" +local ScreenList = require "birb.modules.gui.mixins.screens" +Gui:implement(ScreenList) +Gui:implement(ElementList) + +local TransformDataStruct = require "birb.structures.tween" + +function Gui:new(scene) + self.scene = scene + self:reset() + self.sfx = {} +end + +function Gui:reset() + self:initElements() + self:initScreens() +end + +function Gui:update(dt) + for _, element in pairs(self.elements) do + if (element ~= nil) then + element:updateElement(dt) + end + end + for _, screen in pairs(self.screens) do + if (screen ~= nil) then + screen:update(dt) + end + end +end + +-- TWEEN FUNCTIONS +-- Handle tweening + +function Gui:transform(data, delay) + delay = delay or 0 + + local time = 0 + for _, rawTransform in ipairs(data) do + local newTime = self:transformOne(rawTransform, delay) + time = math.max(time, newTime) + end + return time +end + +function Gui:playScreenTransform(screenname, name, delay) + return self.screens[screenname]:playTransform(name, delay) +end + +function Gui:transformOne(rawTransform, delay) + delay = delay or 0 + + local struct = TransformDataStruct[rawTransform[2]] + assert(struct ~= nil, "Structure " .. rawTransform[1] .. " doesn't exists ") + local transform = utils.table.parse(rawTransform, struct, 0) + + local time = transform.start + delay + + if transform.type == "tween" then + self:newTween(transform.name, time, transform.duration, transform.target, transform.easing) + elseif transform.type == "movement" then + self:newMovement(transform.name, time, transform.duration, transform.x, transform.y, transform.easing) + elseif transform.type == "switch" then + self:newSwitch(transform.name, time, transform.bools) + elseif transform.type == "delayFocus" then + self:delayFocus(transform.name, time) + end + + if (transform.duration ~= nil) then + time = time + transform.duration + end + return time +end + +function Gui:newTween(element, start, duration, target, easing) + assert(self.elements[element] ~= nil, element .. " does not exists") + self.elements[element]:newTween(start, duration, target, easing) +end + +function Gui:newMovement(element, start, duration, x, y, easing) + assert(self.elements[element] ~= nil, element .. " does not exists") + self.elements[element]:newMovement(start, duration, x, y, easing) +end + +function Gui:newSwitch(element, start, bools) + assert(self.elements[element] ~= nil, element .. " does not exists") + self.elements[element]:newSwitch(start, bools) +end + +function Gui:delayFocus(element, start) + assert(self.elements[element] ~= nil, element .. " does not exists") + self.elements[element]:delayFocus(start) +end + +function Gui:hideScreen(screenname) + self.screens[screenname]:hide() +end + + +function Gui:showScreen(screenname, focusElement, widgetId, page, arbitraryDatas) + self.screens[screenname]:show(focusElement, widgetId, page) + self.screens[screenname]:setDatas(arbitraryDatas) +end + +-- SOUND FUNCTIONS +-- Handle SFX + +function Gui:addSFX(guiName, sfxName) + self.sfx[guiName] = sfxName +end + +function Gui:playSFX(type) + local sfxName = self.sfx[type] + if (sfxName ~= nil) then + local sfx = self.scene.assets.sfx[sfxName] + if (sfx ~= nil) then + sfx:play() + end + end +end + +-- KEYBOARD FUNCTIONS +-- Handle keyboard + +function Gui:keycheck(keys) + local haveFocus = self:haveFocus() + if (haveFocus) then + local elem = self:getFocusedElement() + for key,_ in pairs(keys) do + if (keys[key].isPressed and not elem:isTransforming()) then + elem:keypressed(key) + end + end + end + return haveFocus +end + +-- DRAW FUNCTIONS +-- Draw the menu and its content + +function Gui:redraw() + for _, element in pairs(self:getVisibleElement(true)) do + element:redraw() + end + for _, element in pairs(self:getVisibleElement(false)) do + element:redraw() + end +end + +function Gui:drawTop() + for _, element in ipairs(self:getVisibleElement(true)) do + element:drawElement() + end +end + +function Gui:drawBottom() + for _, element in ipairs(self:getVisibleElement(false)) do + element:drawElement() + end +end + +return Gui \ No newline at end of file diff --git a/birb/modules/menusystem/menus/flowbox.lua b/birb/modules/gui/menus/flowbox.lua similarity index 92% rename from birb/modules/menusystem/menus/flowbox.lua rename to birb/modules/gui/menus/flowbox.lua index 5fcde9b..a963122 100644 --- a/birb/modules/menusystem/menus/flowbox.lua +++ b/birb/modules/gui/menus/flowbox.lua @@ -31,9 +31,9 @@ local View2D = require(cwd .. "views.view2D") -- INIT FUNCTIONS -- Initialize and configure the flowbox -function FlowBox:new(menusystem, name, x, y, w, h, slots_hor, slots_vert) +function FlowBox:new(name, x, y, w, h, slots_hor, slots_vert) self.view = View2D(slots_hor, slots_vert) - FlowBox.super.new(self, menusystem, name, x, y, w, h) + FlowBox.super.new(self, name, x, y, w, h) self:setRealSize() end @@ -85,18 +85,22 @@ function FlowBox:moveByKeys(key) local col, line = self.view:getCoord(self.widget:getSelected()) if key == 'left' then self:moveCursor2D(col - 1, line) + self:playNavigationSound() end if key == 'right' then self:moveCursor2D(col + 1, line) + self:playNavigationSound() end if key == 'up' then self:moveCursor2D(col, line - 1) + self:playNavigationSound() end if key == 'down' then self:moveCursor2D(col, line + 1) + self:playNavigationSound() end end @@ -112,10 +116,10 @@ end -- DRAW FUNCTIONS -- Draw the menu and its content -function FlowBox:draw() +function FlowBox:drawTexture() self.view:updateFirstSlot(self.widget:getSelected()) - local widgety = self.y - local widgetx = self.x + local widgety = self.canvas.padding + local widgetx = self.canvas.padding local listWidget = self.widget:getList(self.view.firstSlot, self.view.slotNumber) @@ -138,7 +142,7 @@ function FlowBox:getGraphicalCursorPosition() local col, line = self.view:getCoord(self.widget:getSelected()) local x = (col) * h local y = (line - beginline) * h - return self.x + x, self.y + y, w, h + return x, y, w, h end return FlowBox diff --git a/birb/modules/menusystem/menus/grid.lua b/birb/modules/gui/menus/grid.lua similarity index 93% rename from birb/modules/menusystem/menus/grid.lua rename to birb/modules/gui/menus/grid.lua index 7ba675f..afbd4c2 100644 --- a/birb/modules/menusystem/menus/grid.lua +++ b/birb/modules/gui/menus/grid.lua @@ -26,14 +26,14 @@ local cwd = (...):gsub('%.grid$', '') .. "." local Menu = require(cwd .. "parent") local GridBox = Menu:extend() -local View2D = require "birb.modules.menusystem.menus.views.view2D" +local View2D = require "birb.modules.gui.menus.views.view2D" -- INIT FUNCTIONS -- Initialize and configure the menu -function GridBox:new(menusystem, name, x, y, w, h, colNumber, lineNumber) +function GridBox:new(name, x, y, w, h, colNumber, lineNumber) self.view = View2D(colNumber, lineNumber) - GridBox.super.new(self, menusystem, name, x, y, w, h) + GridBox.super.new(self, name, x, y, w, h) self.h = lineNumber * self.widgetSize.h -- On fait en sorte que la hauteur self.w = colNumber * self.widgetSize.w -- et la largeur -- soit un multiple du nombre de slot et de leur dimensions @@ -150,18 +150,22 @@ function GridBox:keyreleased(key, code) local col, line = self.cursor.x, self.cursor.y if key == 'left' then self:moveCol(-1) + self:playNavigationSound() end if key == 'right' then self:moveCol(1) + self:playNavigationSound() end if key == 'up' then self:moveLine(-1) + self:playNavigationSound() end if key == 'down' then self:moveLine(1) + self:playNavigationSound() end if key == "A" and self.widget:getSelected() <= self.widget:lenght() then @@ -247,12 +251,12 @@ end -- DRAW FUNCTIONS -- Draw the menu and its content -function GridBox:draw() +function GridBox:drawTexture() for i,v in ipairs(self.slots) do if self:haveWidget(i) then - local widgetx = self.x + (v.x * self.widgetSize.w) - local widgety = self.y + (v.y * self.widgetSize.h) + local widgetx = self.canvas.padding + (v.x * self.widgetSize.w) + local widgety = self.canvas.padding + (v.y * self.widgetSize.h) if self.widget:getSelected() == v.widgetID and self:haveFocus() == true then self.widget.list[v.widgetID]:drawSelected(widgetx, widgety) else @@ -269,7 +273,7 @@ function GridBox:drawCursor() local w, h = self:getWidgetSize(slot) local x = self.slots[slot].x * self.widgetSize.w local y = self.slots[slot].y * self.widgetSize.h - self:drawGraphicalCursor(self.x + x, self.y + y, w, h) + self:drawGraphicalCursor(x, y, w, h) end end diff --git a/birb/modules/menusystem/menus/hlistbox.lua b/birb/modules/gui/menus/hlistbox.lua similarity index 87% rename from birb/modules/menusystem/menus/hlistbox.lua rename to birb/modules/gui/menus/hlistbox.lua index c8a853f..fe4a594 100644 --- a/birb/modules/menusystem/menus/hlistbox.lua +++ b/birb/modules/gui/menus/hlistbox.lua @@ -31,9 +31,9 @@ local View1D = require(cwd .. "views.view1D") -- INIT FUNCTIONS -- Initialize and configure functions. -function HListBox:new(menusystem, name, x, y, w, h, slotNumber) +function HListBox:new(name, x, y, w, h, slotNumber) self.view = View1D(slotNumber) - HListBox.super.new(self, menusystem, name, x, y, w, h) + HListBox.super.new(self, name, x, y, w, h) self.w = slotNumber * self.widgetSize.w -- On fait en sorte que la hauteur -- soit un multiple du nombre de slot et de leur hauteur end @@ -60,10 +60,14 @@ end function HListBox:moveByKeys(key, code) if key == 'left' then self.widget:moveCursor(-1) + self.canvas.needRedraw = true + self:playNavigationSound() end if key == 'right' then self.widget:moveCursor(1) + self.canvas.needRedraw = true + self:playNavigationSound() end end @@ -77,15 +81,15 @@ end -- DRAW FUNCTIONS -- Draw the menu and its content -function HListBox:draw() +function HListBox:drawTexture() self.view:updateFirstSlot(self.widget:getSelected()) - local widgetx = self.x + local widgetx = self.canvas.padding local listWidget = self.widget:getList(self.view.firstSlot, self.view.slotNumber) for _, widget in ipairs(listWidget) do - widget:drawWidget(widgetx, self.y, self.widgetSize.w, self.h) + widget:drawWidget(widgetx, self.canvas.padding, self.widgetSize.w, self.h) widgetx = widgetx + self.widgetSize.w end end @@ -95,7 +99,7 @@ function HListBox:getGraphicalCursorPosition() local w, h = self:getWidgetSize() local x = (self.widget:getSelected() - self.view.firstSlot) * w - return self.x + x,self.y, w, h + return x, 0, w, h end return HListBox diff --git a/birb/modules/menusystem/menus/listbox.lua b/birb/modules/gui/menus/listbox.lua similarity index 68% rename from birb/modules/menusystem/menus/listbox.lua rename to birb/modules/gui/menus/listbox.lua index 828ade8..41abf2a 100644 --- a/birb/modules/menusystem/menus/listbox.lua +++ b/birb/modules/gui/menus/listbox.lua @@ -31,11 +31,13 @@ local View1D = require(cwd .. "views.view1D") -- INIT FUNCTIONS -- Initialize and configure functions. -function ListBox:new(menusystem, name, x, y, w, h, slotNumber) +function ListBox:new(name, x, y, w, h, slotNumber) self.view = View1D(slotNumber) - ListBox.super.new(self, menusystem, name, x, y, w, h) + ListBox.super.new(self, name, x, y, w, h) self.h = slotNumber * self.widgetSize.h -- On fait en sorte que la hauteur -- soit un multiple du nombre de slot et de leur hauteur + self.lateralFunc = nil + self.packAtEnd = false end -- UPDATE FUNCTIONS @@ -54,16 +56,28 @@ function ListBox:resetView() self.view:reset() end +function ListBox:addLateralAction(func) + self.lateralFunc = func +end + -- KEYBOARD FUNCTIONS -- Handle input from keyboard/controllers. function ListBox:moveByKeys(key) if key == 'up' then self.widget:moveCursor(-1) + self:playNavigationSound() + self.canvas.needRedraw = true end if key == 'down' then self.widget:moveCursor(1) + self:playNavigationSound() + self.canvas.needRedraw = true + end + + if (self.lateralFunc ~= nil and (key == 'left' or key == 'right')) then + self.widget:lateralAction(self.lateralFunc, key) end end @@ -77,24 +91,26 @@ end -- DRAW FUNCTIONS -- draw the menu and the rest of content. -function ListBox:draw() - self.view:updateFirstSlot(self.widget:getSelected()) - local widgety = self.y +function ListBox:getListPart(relativeNumber) + if (self.packAtEnd) then relativeNumber = relativeNumber + math.max(0, self.view.slotNumber - self.widget:lenght()) end + return 0, (relativeNumber) * self.widgetSize.h, self.w, self.widgetSize.h +end +function ListBox:drawTexture() + self.view:updateFirstSlot(self.widget:getSelected()) local listWidget = self.widget:getList(self.view.firstSlot, self.view.slotNumber) - for _, widget in ipairs(listWidget) do - widget:drawWidget(self.x, widgety, self.w, self.widgetSize.h) - widgety = widgety + self.widgetSize.h + for i, widget in ipairs(listWidget) do + local x, y, w, h = self:getListPart(i - 1) + self:drawWidgetBackground(x + self.canvas.padding, y + self.canvas.padding, w, h) + widget:drawWidget(x + self.canvas.padding, y + self.canvas.padding, w, h) end end function ListBox:getGraphicalCursorPosition() - self.view:updateFirstSlot(self.widget:getSelected()) - local w, h = self:getWidgetSize() - local y = (self.widget:getSelected() - self.view.firstSlot) * h + local x, y, w, h = self:getListPart(self.widget:getSelected() - self.view.firstSlot) - return self.x,self.y + y, w, h + return self:getListPart(self.widget:getSelected() - self.view.firstSlot) end return ListBox diff --git a/birb/modules/menusystem/menus/model/init.lua b/birb/modules/gui/menus/model/init.lua similarity index 80% rename from birb/modules/menusystem/menus/model/init.lua rename to birb/modules/gui/menus/model/init.lua index 179c87f..95ebeb1 100644 --- a/birb/modules/menusystem/menus/model/init.lua +++ b/birb/modules/gui/menus/model/init.lua @@ -1,5 +1,5 @@ local MenuModel = Object:extend() -local Page = require "birb.modules.menusystem.menus.model.page" +local Page = require "birb.modules.gui.menus.model.page" local function updateWidgetByOrder(a, b) if a.order ~= b.order then @@ -21,6 +21,7 @@ function MenuModel:new() self.cancel = 0 self.limit = -1 -- self:updateWidgetSize() + self.hoverFunc = nil end function MenuModel:clear() @@ -33,6 +34,7 @@ end function MenuModel:addPage(pageName) local page = Page() + page.name = pageName self.pages[pageName] = page self.currentPage = pageName return page @@ -58,6 +60,7 @@ end function MenuModel:switch(pageName) if (self:pageExists(pageName)) then self.currentPage = pageName + self:hoverAction() end end @@ -70,6 +73,10 @@ function MenuModel:getCurrentPage() return self:getPage(self.currentPage) end +function MenuModel:getCurrentPageName() + return self.currentPage +end + -- UPDATE/DRAW FUNCTIONS -- All the update functions @@ -91,6 +98,10 @@ end -- ACTION FUNCTIONS -- All the actions callback used by the widgets +function MenuModel:addHoverAction(func) + self.hoverFunc = func +end + function MenuModel:cancelAction() local page = self:getCurrentPage() page:cancelAction() @@ -106,6 +117,19 @@ function MenuModel:selectedAction() page:selectedAction() end +function MenuModel:hoverAction() + local page = self:getCurrentPage() + if (self.hoverFunc ~= nil) then + page:hoverAction(self.hoverFunc) + end +end + +function MenuModel:lateralAction(func, key) + local page = self:getCurrentPage() + page:lateralAction(func, key) +end + + -- WIDGET FUNCTIONS -- All the functions to handle widgets @@ -142,9 +166,9 @@ end -- CANCEL FUNCTIONS -- Add a widget as a "cancel" function -function MenuModel:setCancelWidget() +function MenuModel:setCancelWidget(id) local page = self:getCurrentPage() - page:setCancelWidget() + page:setCancelWidget(id) end function MenuModel:getCancelWidget() @@ -167,22 +191,36 @@ end function MenuModel:trySelectWidget(cursorid) local page = self:getCurrentPage() - return page:trySelectWidget(cursorid) + local isSuccess = page:trySelectWidget(cursorid) + if (isSuccess) then + self:hoverAction() + end + return isSuccess end function MenuModel:setCursor(cursorid) local page = self:getCurrentPage() page:setCursor(cursorid) + self:hoverAction() end function MenuModel:moveCursorAbsolute(newSelected) local page = self:getCurrentPage() page:moveCursorAbsolute(newSelected) + self:hoverAction() end function MenuModel:moveCursor(relative) local page = self:getCurrentPage() page:moveCursor(relative) + self:hoverAction() +end + +-- DRAW +-- Draw widget +function MenuModel:redraw() + local page = self:getCurrentPage() + page:redraw() end diff --git a/birb/modules/menusystem/menus/model/page.lua b/birb/modules/gui/menus/model/page.lua similarity index 82% rename from birb/modules/menusystem/menus/model/page.lua rename to birb/modules/gui/menus/model/page.lua index e6a0496..93f60ab 100644 --- a/birb/modules/menusystem/menus/model/page.lua +++ b/birb/modules/gui/menus/model/page.lua @@ -66,14 +66,15 @@ end -- All the actions callback used by the widgets function Page:cancelAction() - if (self.cancel ~= 0) then - self:action(self.cancel, "key") + if (self:getCancelWidget() ~= 0) then + self:action(self:getCancelWidget(), "key") end end function Page:action(id, type) if (self:widgetExist(id)) then self.widgets[id]:action(type) + self.widgets[id]:playSFX() end end @@ -83,6 +84,18 @@ function Page:selectedAction() end end +function Page:hoverAction(func) + if (self:widgetExist(self.selected)) then + func(self.widgets[self.selected]) + end +end + +function Page:lateralAction(func, key) + if (self:widgetExist(self.selected)) then + func(key, self.widgets[self.selected], self.selected, self.name) + end +end + -- WIDGET FUNCTIONS -- All the functions to handle widgets @@ -133,11 +146,18 @@ end -- Add a widget as a "cancel" function function Page:setCancelWidget(id) - self.cancel = #self.widgets + if (id == nil) then + id = #self.widgets + end + self.cancel = id end -function Page:getCancelWidget(id) - return self.cancel +function Page:getCancelWidget() + if (self.cancel == "last") then + return #self.widgets + else + return self.cancel + end end -- CURSOR FUNCTIONS @@ -181,5 +201,11 @@ function Page:moveCursor(relative) self:moveCursorAbsolute(self.selected + relative) end +-- DRAW +function Page:redraw() + for _, widget in ipairs(self.widgets) do + widget:redraw() + end +end return Page diff --git a/birb/modules/menusystem/menus/parent.lua b/birb/modules/gui/menus/parent.lua similarity index 75% rename from birb/modules/menusystem/menus/parent.lua rename to birb/modules/gui/menus/parent.lua index 57ea23c..65ca974 100644 --- a/birb/modules/menusystem/menus/parent.lua +++ b/birb/modules/gui/menus/parent.lua @@ -21,30 +21,46 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ]] -local GuiElement = require "birb.modules.menusystem.parent" +local GuiElement = require "birb.modules.gui.elements.canvas" local Menu = GuiElement:extend() -local MenuModel = require "birb.modules.menusystem.menus.model" +local MenuModel = require "birb.modules.gui.menus.model" + +local menuUtils = require "birb.modules.gui.utils" -local menuUtils = require "birb.modules.menusystem.utils" -- INIT FUNCTIONS -- Initialize and configure functions. -function Menu:new(menusystem, name, x, y, w, h) +function Menu:new(name, x, y, w, h) Menu.super.new(self, name, x, y, w, h) - self.menusystem = self:getGui() + + --TODO: remove this + self.menusystem = self.gui self.widget = MenuModel() self.widgetSize = {} self:updateWidgetSize() - self:resetSound() + self:initCanvas() + self.cancelFunc = nil + self.canvas.dual = true +end + +-- FUNCTIONS FUNCTIONS +-- Add functions to the menu system + +function Menu:addCancelAction(func) + self.cancelFunc = func +end + +function Menu:addHoverAction(func) + self.widget:addHoverAction(func) end -- INTERACTION FUNCTIONS -- Keyboard and mouse -function Menu:keyreleased(key) +function Menu:keypressed(key) self:moveByKeys(key) self:actionAndCancel(key) end @@ -77,10 +93,12 @@ end function Menu:actionAndCancel(key) if key == "A" then self.widget:selectedAction() + self.canvas.needRedraw = true end if key == "B" then - self.widget:cancelAction() + self:cancelAction() + self.canvas.needRedraw = true end end @@ -107,21 +125,38 @@ function Menu:getPage(pageName) self.widget:getPage(pageName) end +function Menu:getCurrentPageName() + return self.widget:getCurrentPageName() +end + function Menu:switch(pageName) self.widget:switch(pageName) self:resetView() + self.canvas.needRedraw = true end function Menu:back() self.widget:back() self:resetView() + self.canvas.needRedraw = true +end + +function GuiElement:setSubFocus(widgetId, pageName) + if (pageName ~= nil) then + self.widget:switch(pageName) + end + self.widget:trySelectWidget(widgetId) end -- ACTION FUNCTIONS -- Send actions to the widgets function Menu:cancelAction() - self.widget:cancelAction() + if (self.cancelFunc ~= nil) then + self.cancelFunc(self) + else + self.widget:cancelAction() + end end function Menu:clear() @@ -137,8 +172,8 @@ end -- UPDATE FUNCTIONS function Menu:updateElement(dt) - self:update(dt) self.widget:update(dt) + Menu.super.updateElement(self, dt) end -- DRAW FUNCTIONS @@ -146,9 +181,12 @@ end function Menu:drawElement() self:draw() +end + +function Menu:drawFinalTexture() if (self:haveFocus()) then local x, y, w, h = self:getGraphicalCursorPosition() - self:drawGraphicalCursor(x, y, w, h) + self:drawGraphicalCursor(self.canvas.padding + x, self.canvas.padding + y, w, h) end end @@ -160,11 +198,21 @@ function Menu:drawCanvas() end +function Menu:drawWidgetBackground(x, y, w, h) + +end + +function Menu:redraw() + self.widget:redraw() + Menu.super.redraw(self) +end + -- WIDGET FUNCTIONS -- Handle widgets of the functions function Menu:addWidget(newwidget) self.widget:addWidget(newwidget) + self.canvas.needRedraw = true end function Menu:setCancelWidget(id) @@ -193,35 +241,23 @@ end function Menu:setCursor(cursorid) self.widget:setCursor(cursorid) + self.canvas.needRedraw = true end function Menu:moveCursor(new_selected) - self:playNavigationSound() self.widget:moveCursorAbsolute(new_selected) + self.canvas.needRedraw = true end -- SOUND FUNCTION -- Handle SFX -function Menu:resetSound() - self.sound = {} - self.sound.active = false - self.sound.asset = nil -end - -function Menu:setSoundFromSceneAssets(name) - self:setSound(self.menusystem.scene.assets:getWithType(name, "sfx")) -end - -function Menu:setSound(soundasset) - self.sound.active = true - self.sound.asset = soundasset -end - function Menu:playNavigationSound() - if self.sound.active == true then - self.sound.asset:play() - end + self:playSFX("navigate") +end + +function Menu:playSFX(name) + self.gui:playSFX(name) end -- VIEW FUNCTIONS diff --git a/birb/modules/menusystem/menus/views/view1D.lua b/birb/modules/gui/menus/views/view1D.lua similarity index 98% rename from birb/modules/menusystem/menus/views/view1D.lua rename to birb/modules/gui/menus/views/view1D.lua index 563c602..e5c0e07 100644 --- a/birb/modules/menusystem/menus/views/view1D.lua +++ b/birb/modules/gui/menus/views/view1D.lua @@ -31,7 +31,6 @@ end function View1D:reset() self.firstSlot = 1 - print("reset") end function View1D:updateFirstSlot(widgetID) diff --git a/birb/modules/menusystem/menus/views/view2D.lua b/birb/modules/gui/menus/views/view2D.lua similarity index 96% rename from birb/modules/menusystem/menus/views/view2D.lua rename to birb/modules/gui/menus/views/view2D.lua index 77e8823..feecf25 100644 --- a/birb/modules/menusystem/menus/views/view2D.lua +++ b/birb/modules/gui/menus/views/view2D.lua @@ -21,7 +21,7 @@ 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 View1D = require "birb.modules.menusystem.menus.views.view1D" +local View1D = require "birb.modules.gui.menus.views.view1D" local View2D = View1D:extend() function View2D:new(colNumber, lineNumber) diff --git a/birb/modules/menusystem/menus/widgets/base.lua b/birb/modules/gui/menus/widgets/base.lua similarity index 79% rename from birb/modules/menusystem/menus/widgets/base.lua rename to birb/modules/gui/menus/widgets/base.lua index 0ff1212..d2f5356 100644 --- a/birb/modules/menusystem/menus/widgets/base.lua +++ b/birb/modules/gui/menus/widgets/base.lua @@ -26,8 +26,8 @@ local BaseWidget = Object:extend() -- Initialize and configure the widget function BaseWidget:new(menuName) + self:initWrapper() self.menu = self:getMenuByName(menuName) - self.assets = self:getAssets() self.destroyed = false self.selectable = false @@ -37,23 +37,35 @@ function BaseWidget:new(menuName) self.canvas = {} self.canvas.texture = nil self.canvas.needRedraw = true + self.canvas.isAnimated = false self.order = 0 self:register() + self.func = nil + self.type = "select" +end + +function BaseWidget:initWrapper() + self.scene = core.scenemanager.nextScene or core.scenemanager.currentScene + self.gui = self.scene.gui + self.assets = self.scene.assets +end + +function BaseWidget:setFunc(func) + self.func = func end function BaseWidget:getMenuByName(name) - local gui = self:getGui() - return gui:getMenu(name) + assert(name ~= nil, "Name cant be nil") + return self.gui.elements[name] end -function BaseWidget:getGui() - local scene = core.scenemanager.currentScene - return scene.menusystem +function BaseWidget:getScene() + return core.scenemanager.nextScene or core.scenemanager.currentScene end function BaseWidget:getAssets() - local scene = core.scenemanager.currentScene + local scene = core.scenemanager.nextScene or core.scenemanager.currentScene return scene.assets end @@ -62,7 +74,13 @@ function BaseWidget:register() self.menu:addWidget(self) end -function BaseWidget:redrawCanvas() +function BaseWidget:redraw() + if (self.canvas.needRedraw or self.canvas.isAnimated) then + self:generateTexture() + end +end + +function BaseWidget:generateTexture() self.width, self.height = self.menu:getWidgetSize(self.id) local canvas = love.graphics.newCanvas(self.width, self.height) @@ -123,9 +141,6 @@ end -- Update the widget function BaseWidget:update(dt) - if (self.canvas.needRedraw) then - self:redrawCanvas() - end -- N/A end @@ -139,8 +154,14 @@ end -- ACTION FUNCTION -- Functions to handle actions and selection. +function BaseWidget:playSFX() + self.menu:playSFX(self.type) +end + function BaseWidget:action(source) - --self:destroy() + if (self.func ~= nil) then + self.func(self) + end end function BaseWidget:destroy() diff --git a/birb/modules/menusystem/menus/widgets/init.lua b/birb/modules/gui/menus/widgets/init.lua similarity index 89% rename from birb/modules/menusystem/menus/widgets/init.lua rename to birb/modules/gui/menus/widgets/init.lua index f1c11a2..0c8c4e8 100644 --- a/birb/modules/menusystem/menus/widgets/init.lua +++ b/birb/modules/gui/menus/widgets/init.lua @@ -24,7 +24,7 @@ local Widget = {} -- Add the widget as subvariable to the returned table -Widget.Base = require "birb.modules.menusystem.menus.widgets.base" -Widget.Text = require "birb.modules.menusystem.menus.widgets.text" +Widget.Base = require "birb.modules.gui.menus.widgets.base" +Widget.Text = require "birb.modules.gui.menus.widgets.text" return Widget diff --git a/birb/modules/menusystem/menus/widgets/text.lua b/birb/modules/gui/menus/widgets/text.lua similarity index 67% rename from birb/modules/menusystem/menus/widgets/text.lua rename to birb/modules/gui/menus/widgets/text.lua index e14e096..7809d04 100644 --- a/birb/modules/menusystem/menus/widgets/text.lua +++ b/birb/modules/gui/menus/widgets/text.lua @@ -20,7 +20,7 @@ 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 BaseWidget = require "birb.modules.menusystem.menus.widgets.base" +local BaseWidget = require "birb.modules.gui.menus.widgets.base" local TextWidget = BaseWidget:extend() -- TEXT WIDGET @@ -35,13 +35,14 @@ function TextWidget:new(menuName, font, label, position, padding) -- We add the first label local position = position or "center" self:addLabel(label, position) - self:setSelectedColor(1, 1, 1) + self:setColor(1, 1, 1) end function TextWidget:addLabel(label, position) local complexLabel = {} + assert(label ~= nil, "Label can't be nil") complexLabel.label = label - complexLabel.position = position + complexLabel.position = position or "left" table.insert(self.labels, complexLabel) end @@ -49,6 +50,13 @@ function TextWidget:replaceLabel(id, newLabel) self.labels[id].label = newLabel end +function TextWidget:setColor(r, g, b) + self.color = {} + self.color.r = r + self.color.g = g + self.color.b = b +end + function TextWidget:setSelectedColor(r, g, b) self.selectedColor = {} self.selectedColor.r = r @@ -61,13 +69,29 @@ function TextWidget:getFont() end function TextWidget:getSelectedColor() - return self.selectedColor.r, self.selectedColor.g, self.selectedColor.b + if (self.selectedColor ~= nil) then + return self.selectedColor.r, self.selectedColor.g, self.selectedColor.b + else + return self:getColor() + end +end + +function TextWidget:getColor() + return self.color.r, self.color.g, self.color.b end function TextWidget:getPadding() return self.padding end +function TextWidget:getPaddingLeft() + return self.paddingLeft or self:getPadding() +end + +function TextWidget:getPaddingRight() + return self.paddingRight or self:getPadding() +end + function TextWidget:drawCanvas() local w, h local font = self:getFont() @@ -77,18 +101,31 @@ function TextWidget:drawCanvas() if (complexLabel.position == "center") then w = math.floor(self.width / 2) elseif (complexLabel.position == "left") then - w = self:getPadding() + w = self:getPaddingLeft() elseif (complexLabel.position == "right") then - w = math.floor(self.width - self:getPadding()) + w = math.floor(self.width - self:getPaddingRight()) + else + error("Position " .. complexLabel.position .. " is unknown for label " .. complexLabel.label) end font:draw(complexLabel.label, w, h, -1, complexLabel.position) end end +function TextWidget:draw(x, y, w, h) + local r, g, b = self:getColor() + love.graphics.setColor(r, g, b, 1) + if self.canvas.texture ~= nil then + love.graphics.draw(self.canvas.texture, x, y) + end + utils.graphics.resetColor() +end + function TextWidget:drawSelected(x, y, w, h) local r, g, b = self:getSelectedColor() love.graphics.setColor(r, g, b, 1) - self:draw(x, y) + if self.canvas.texture ~= nil then + love.graphics.draw(self.canvas.texture, x, y) + end utils.graphics.resetColor() end diff --git a/birb/modules/gui/mixins/elements.lua b/birb/modules/gui/mixins/elements.lua new file mode 100644 index 0000000..147a5c1 --- /dev/null +++ b/birb/modules/gui/mixins/elements.lua @@ -0,0 +1,94 @@ +local ElementList = Object:extend() + +function ElementList:initElements() + self.elements = {} + self.focusedElement = nil + self.lastFocused = nil + self.nbrElement = 0 +end + +function ElementList:addElement(name, element) + self.nbrElement = self.nbrElement + 1 + self.elements[name] = element + return self.nbrElement +end + +function ElementList:deleteElement(name) + self.elements[name] = nil +end + +function ElementList:setFocus(name, widgetId, page) + assert(self:elementExists(name), "Element " .. name .. " doesn't exists") + self:storeLastFocus() + self.focusedElement = name + self.elements[name].isVisible = true + if (widgetId ~= nil) then + self.elements[name]:setSubFocus(widgetId, page) + end +end + +function ElementList:removeFocus() + self:storeLastFocus() + self.focusedElement = nil +end + +function ElementList:storeLastFocus() + if (self.focusedElement ~= nil) then + self.lastFocused = self.focusedElement + end +end + +function ElementList:setLastFocus() + if (self:elementExists(self.lastFocused)) then + self:setFocus(self.lastFocused) + end +end + +function ElementList:elementExists(name) + return (self:getElement(name) ~= nil) +end + +function ElementList:haveFocus() + return self:elementIsVisible(self.focusedElement) +end + +function ElementList:getFocusedElement() + return self:getElement(self.focusedElement) +end + +function ElementList:getElement(name) + if (not utils.string.isEmpty(name)) then + return self.elements[name] + end + return nil +end + +function ElementList:getVisibleElement(topLayer) + local visibleList = {} + for _, element in pairs(self.elements) do + if (element ~= nil) then + if (element:getVisibility() and ((element.depth) < 0 == topLayer)) then + table.insert(visibleList, element) + end + end + end + + table.sort(visibleList, function (a, b) + if (a.depth == b.depth) then + return (a.creationId < b.creationId) + else + return (a.depth > b.depth) + end + end) + + return visibleList +end + +function ElementList:elementIsVisible(name) + if (self:elementExists(name)) then + return self.elements[name]:getVisibility() + end + return false +end + +return ElementList \ No newline at end of file diff --git a/birb/modules/gui/mixins/screens.lua b/birb/modules/gui/mixins/screens.lua new file mode 100644 index 0000000..f41a502 --- /dev/null +++ b/birb/modules/gui/mixins/screens.lua @@ -0,0 +1,20 @@ +local ScreenList = Object:extend() + +function ScreenList:initScreens() + self.screens = {} +end + +function ScreenList:addScreen(name, screen) + self.screens[name] = screen +end + +function ScreenList:deleteScreen(name) + self.screens[name]:purgeElements() + self.screens[name] = nil +end + +function ScreenList:getScreen(name) + return self.screens[name] +end + +return ScreenList \ No newline at end of file diff --git a/birb/modules/gui/screen/init.lua b/birb/modules/gui/screen/init.lua new file mode 100644 index 0000000..e95bd14 --- /dev/null +++ b/birb/modules/gui/screen/init.lua @@ -0,0 +1,160 @@ +local GuiScreen = Object:extend() +local ElementList = require "birb.modules.gui.mixins.elements" +GuiScreen:implement(ElementList) + +local TweenManager = require "birb.classes.time" +local ScreenSet = require "birb.modules.gui.screen.screenset" + +local elementDataStruct = require "birb.structures.elementData" + +function GuiScreen:new(name) + self:initWrapper() + self.name = name + self.isVisible = false + self.transforms = {} + self.tweens = TweenManager(self) + + self:reset() + self:registerElements() + self.gui:addScreen(name, self) + + self.defaultFocus = nil +end + +function GuiScreen:initWrapper() + local scene = core.scenemanager.nextScene or core.scenemanager.currentScene + self.scene = scene + self.gui = scene.gui + -- Présent pour la compatibilité + self.controller = self.gui + self.assets = scene.assets +end + +function GuiScreen:update(dt) + self.tweens:update(dt) +end + +function GuiScreen:show(focusElement, widgetId, page) + self:showSimple(focusElement, widgetId, page) + if (self.set ~= nil) then + self.set.owner:show() + end +end + +function GuiScreen:showSimple(focusElement, widgetId, page) + focusElement = focusElement or self.defaultFocus + if (not self.isVisible) then + self.isVisible = true + local delay = 0 + if (self.set ~= nil) then + delay = self.set:setCurrentScreen(self.name) + end + + if (self.transforms["show"] ~= nil) then + if (delay == 0) then + self:showWithSubScreen(focusElement, widgetId, page) + else + self.tweens:newFunc(delay, "focus", function () self:showWithSubScreen(focusElement, widgetId, page) end) + end + end + end +end + +function GuiScreen:showWithSubScreen(focusElement, widgetId, page) + self:playTransform("show") + if (focusElement ~= nil) then + self.gui:setFocus(focusElement, widgetId, page) + end + + if (self.subscreens ~= nil) then + self.subscreens:show() + end +end + +function GuiScreen:setDatas(datas) + +end + +function GuiScreen:hide() + local time = 0 + if (self.isVisible) then + if (self.transforms["hide"] ~= nil) then + time = self:playTransform("hide") + self.tweens:newFunc(time, "hide", function () + self.isVisible = false + end) + end + + if (self.subscreens ~= nil) then + self.subscreens:hideCurrent() + end + end + return time +end + +function GuiScreen:addTransform(name, transform) + self.transforms[name] = transform +end + +function GuiScreen:playTransform(name, delay) + return self.gui:transform(self.transforms[name], delay) +end + +function GuiScreen:reset() + self:initElements() +end + +function GuiScreen:registerElements() + local elementList = self:createElements() + for _, rawElement in ipairs(elementList) do + if (rawElement.is ~= nil) then + self:addElement(rawElement.name, rawElement) + rawElement.screen = self + else + local elemData = utils.table.parse(rawElement, elementDataStruct, 3) + local element = elemData.element + self:addElement(element.name, element) + if (elemData.focus == true) then + element:getFocus() + end + if (elemData.delay > 0) then + element.isVisible = false + element:newSwitch(elemData.delay, {"isVisible"}) + end + if (elemData.depth ~= nil) then + element.depth = elemData.depth + end + if (elemData.keypress ~= nil) then + element:setKeyPressAction(elemData.keypress) + end + element.screen = self + end + end +end + +function GuiScreen:createElements() + -- Empty function +end + +function GuiScreen:setParentSet(set) + self.set = set +end + +function GuiScreen:addSubscreen(screen) + self:initSubscreen() + self.subscreens:add(screen) +end + +function GuiScreen:showSubscreen(screenname) + if (self.subscreens ~= nil) then + self.subscreens:show(screenname) + end +end + +function GuiScreen:initSubscreen() + if (self.subscreens == nil) then + self.subscreens = ScreenSet(self) + end +end + +return GuiScreen \ No newline at end of file diff --git a/birb/modules/gui/screen/screenset.lua b/birb/modules/gui/screen/screenset.lua new file mode 100644 index 0000000..78143d0 --- /dev/null +++ b/birb/modules/gui/screen/screenset.lua @@ -0,0 +1,73 @@ +-- screens/screenset :: a set of exclusive screens +-- Useful to handle a complexe menu with several screens + +--[[ + Copyright © 2021 Kazhnuz + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +]] + +local ScreenSet = Object:extend() + +function ScreenSet:new(owner) + self.set = {} + self.defaultScreen = "" + self.currentScreen = "" + self.owner = owner + self.delay = 0 +end + +function ScreenSet:show(screenName) + local screenName = screenName + if (screenName == nil) then + if self.currentScreen == "" then + screenName = self.defaultScreen + else + return + end + end + if screenName ~= "" then + self.set[screenName]:showSimple() + end +end + +function ScreenSet:setCurrentScreen(screenName) + screenName = screenName or self.defaultScreen + local time = self:hideCurrent() + self.delay + self.currentScreen = screenName + return time +end + +function ScreenSet:hideCurrent() + local time = 0 + if (self.currentScreen ~= "") then + time = self.set[self.currentScreen]:hide() + self.currentScreen = "" + end + return time +end + +function ScreenSet:add(screen, setAsDefault) + self.set[screen.name] = screen + if (setAsDefault == true or self.defaultScreen == "") then + self.defaultScreen = screen.name + end + screen:setParentSet(self) +end + +return ScreenSet \ No newline at end of file diff --git a/birb/modules/menusystem/textmenu/init.lua b/birb/modules/gui/textmenu/init.lua similarity index 60% rename from birb/modules/menusystem/textmenu/init.lua rename to birb/modules/gui/textmenu/init.lua index a466a52..b80898f 100644 --- a/birb/modules/menusystem/textmenu/init.lua +++ b/birb/modules/gui/textmenu/init.lua @@ -24,24 +24,49 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ]] -local ListBox = require "birb.modules.menusystem.menus.listbox" +local ListBox = require "birb.modules.gui.menus.listbox" local TextMenu = ListBox:extend() -TextMenu.baseWidgets = require "birb.modules.menusystem.textmenu.widgets" +TextMenu.baseWidgets = require "birb.modules.gui.textmenu.widgets" local BASE_PADDING = 8 -function TextMenu:new(name, font, x, y, w, slotNumber, padding) +function TextMenu:new(name, font, x, y, w, slotNumber, padding, lineSize) + lineSize = lineSize or 1 self:setFont(font) + self.lineHeight = self.font:getHeight() * lineSize self.name = name - local h = self.font:getHeight() * slotNumber + self.padding = padding or BASE_PADDING - self:setSelectedColor(1,1,1) - TextMenu.super.new(self, nil, name, x, y, w, h, slotNumber) + TextMenu.super.new(self, name, x, y, w, (self.lineHeight * slotNumber), slotNumber) +end + +function TextMenu:addItem(text, position, func, type, additionnalItems, color, additionnalDatas) + local widget = TextMenu.baseWidgets.Base(self.name, text, position) + widget:setFunc(func) + widget.type = type or "select" + if (additionnalItems ~= nil) then + for _, item in ipairs(additionnalItems) do + widget:addLabel(item[1], item[2]) + end + end + if (color ~= nil) then + widget:setColor(color[1], color[2], color[3]) + end + if (additionnalDatas ~= nil) then + widget.datas = additionnalDatas + end +end + +function TextMenu:generateSubmenu(pageName, label, parent, list, func, backWidget) + self:addSubmenu(pageName, label, parent, backWidget) + for _, data in ipairs(list) do + self:addItem(func(data)) + end end function TextMenu:setFont(fontName) - local scene = core.scenemanager.currentScene + local scene = core.scenemanager.nextScene or core.scenemanager.currentScene self.font = scene.assets:getFont(fontName) end @@ -57,13 +82,22 @@ function TextMenu:setSelectedColor(r, g, b) end function TextMenu:getSelectedColor() - return self.selectedColor.r, self.selectedColor.g, self.selectedColor.b + return self.selectedColor end function TextMenu:getPadding() return self.padding end +function TextMenu:getPaddingLeft() + return self.paddingLeft or self:getPadding() +end + +function TextMenu:getPaddingRight() + return self.paddingRight or self:getPadding() +end + + function TextMenu:addSubmenu(pageName, label, parent, backWidget) local label = label or pageName local parent = parent or "main" @@ -72,6 +106,7 @@ function TextMenu:addSubmenu(pageName, label, parent, backWidget) TextMenu.super.addSubmenu(self, pageName, parent) if (backWidget ~= false) then TextMenu.baseWidgets.Back(self.name) + self:setCancelWidget("last") end end diff --git a/birb/modules/menusystem/textmenu/widgets/back.lua b/birb/modules/gui/textmenu/widgets/back.lua similarity index 93% rename from birb/modules/menusystem/textmenu/widgets/back.lua rename to birb/modules/gui/textmenu/widgets/back.lua index f9e87a8..ad053dd 100644 --- a/birb/modules/menusystem/textmenu/widgets/back.lua +++ b/birb/modules/gui/textmenu/widgets/back.lua @@ -21,7 +21,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ]] -local TextMenuWidget = require "birb.modules.menusystem.textmenu.widgets.basic" +local TextMenuWidget = require "birb.modules.gui.textmenu.widgets.basic" local BackWidget = TextMenuWidget:extend() diff --git a/birb/modules/menusystem/textmenu/widgets/basic.lua b/birb/modules/gui/textmenu/widgets/basic.lua similarity index 76% rename from birb/modules/menusystem/textmenu/widgets/basic.lua rename to birb/modules/gui/textmenu/widgets/basic.lua index 6af157f..a69470e 100644 --- a/birb/modules/menusystem/textmenu/widgets/basic.lua +++ b/birb/modules/gui/textmenu/widgets/basic.lua @@ -23,7 +23,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ]] -local TextWidget = require "birb.modules.menusystem.menus.widgets.text" +local TextWidget = require "birb.modules.gui.menus.widgets.text" local TextMenuWidget = TextWidget:extend() @@ -37,11 +37,24 @@ function TextMenuWidget:getFont() end function TextMenuWidget:getSelectedColor() - return self.menu:getSelectedColor() + local selectedColor = self.menu:getSelectedColor() + if (selectedColor ~= nil) then + return selectedColor.r, selectedColor.g, selectedColor.b + else + return self:getColor() + end end function TextMenuWidget:getPadding() return self.menu:getPadding() end +function TextWidget:getPaddingLeft() + return self.menu:getPaddingLeft() or self:getPadding() +end + +function TextWidget:getPaddingRight() + return self.menu:getPaddingRight() or self:getPadding() +end + return TextMenuWidget \ No newline at end of file diff --git a/birb/modules/menusystem/textmenu/widgets/init.lua b/birb/modules/gui/textmenu/widgets/init.lua similarity index 84% rename from birb/modules/menusystem/textmenu/widgets/init.lua rename to birb/modules/gui/textmenu/widgets/init.lua index 96ecd7c..5c5e761 100644 --- a/birb/modules/menusystem/textmenu/widgets/init.lua +++ b/birb/modules/gui/textmenu/widgets/init.lua @@ -24,8 +24,8 @@ local Widget = {} -- Add the widget as subvariable to the returned table -Widget.Base = require "birb.modules.menusystem.textmenu.widgets.basic" -Widget.SubMenu= require "birb.modules.menusystem.textmenu.widgets.submenu" -Widget.Back = require "birb.modules.menusystem.textmenu.widgets.back" +Widget.Base = require "birb.modules.gui.textmenu.widgets.basic" +Widget.SubMenu= require "birb.modules.gui.textmenu.widgets.submenu" +Widget.Back = require "birb.modules.gui.textmenu.widgets.back" return Widget diff --git a/birb/modules/menusystem/textmenu/widgets/submenu.lua b/birb/modules/gui/textmenu/widgets/submenu.lua similarity index 93% rename from birb/modules/menusystem/textmenu/widgets/submenu.lua rename to birb/modules/gui/textmenu/widgets/submenu.lua index ca26e45..a38d390 100644 --- a/birb/modules/menusystem/textmenu/widgets/submenu.lua +++ b/birb/modules/gui/textmenu/widgets/submenu.lua @@ -22,7 +22,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ]] -local TextMenuWidget = require "birb.modules.menusystem.textmenu.widgets.basic" +local TextMenuWidget = require "birb.modules.gui.textmenu.widgets.basic" local SubmenuWidget = TextMenuWidget:extend() diff --git a/birb/modules/menusystem/utils.lua b/birb/modules/gui/utils.lua similarity index 100% rename from birb/modules/menusystem/utils.lua rename to birb/modules/gui/utils.lua diff --git a/birb/modules/init.lua b/birb/modules/init.lua deleted file mode 100644 index c9ebd04..0000000 --- a/birb/modules/init.lua +++ /dev/null @@ -1,33 +0,0 @@ --- modules : different modules that are usable as part of birb - ---[[ - Copyright © 2019 Kazhnuz - - Permission is hereby granted, free of charge, to any person obtaining a copy of - this software and associated documentation files (the "Software"), to deal in - the Software without restriction, including without limitation the rights to - use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - the Software, and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -]] - -local modules = {} - -local cwd = (...):gsub('%.init$', '') .. "." - -modules.Assets = require(cwd .. "assets") -modules.GameSystem = require(cwd .. "gamesystem") -modules.MenuSystem = require(cwd .. "menusystem") -modules.Timers = require(cwd .. "timers") - -return modules diff --git a/birb/modules/menusystem/init.lua b/birb/modules/menusystem/init.lua deleted file mode 100644 index eb44205..0000000 --- a/birb/modules/menusystem/init.lua +++ /dev/null @@ -1,285 +0,0 @@ --- menusystem :: the controller of the menu system. This object handle the --- different menu objects - ---[[ - Copyright © 2019 Kazhnuz - - Permission is hereby granted, free of charge, to any person obtaining a copy of - this software and associated documentation files (the "Software"), to deal in - the Software without restriction, including without limitation the rights to - use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - the Software, and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -]] - -local cwd = (...):gsub('%.init$', '') .. "." - -local MenuSystem = Object:extend() - --- Load the differents menu object to get an easy access -MenuSystem.Parent = require(cwd .. "menus.parent") -MenuSystem.ListBox = require(cwd .. "menus.listbox") -MenuSystem.FlowBox = require(cwd .. "menus.flowbox") -MenuSystem.Grid = require(cwd .. "menus.grid") - --- load widgets object -MenuSystem.Widget = require(cwd .. "menus.widgets") - --- INIT FUNCTIONS --- Initialize and configure the menu controller - -function MenuSystem:new(scene) - self.scene = scene - self.menus = {} - self.focusedMenu = "" - self.isActive = true - self.lockWorld = false - self.lockAssets = false -end - -function MenuSystem:reset() - self.menus = {} -end - --- ACTIVATION FUNCTIONS --- Activate and deactivate the whole menusystem - -function MenuSystem:activate() - self.isActive = true - - if (self.lockWorld) then - if (self.scene.world ~= nil) then - self.scene.world:setActivity(false) - end - end - - if (self.lockAssets) then - if (self.scene.assets ~= nil) then - self.scene.assets:setActivity(false) - end - end -end - -function MenuSystem:deactivate() - self.isActive = false - - if (self.lockWorld) then - if (self.scene.world ~= nil) then - self.scene.world:setActivity(true) - end - end - - if (self.lockAssets) then - if (self.scene.assets ~= nil) then - self.scene.assets:setActivity(true) - end - end -end - -function MenuSystem:getActiveState() - return self.isActive -end - -function MenuSystem:lockWorldWhenActive(state) - self.lockWorld = state -end - -function MenuSystem:lockAssetsWhenActive(state) - self.lockAssets = state -end - - --- MENUS FUNCTIONS --- Controle the menus of the menusystem - -function MenuSystem:addMenu(name, menu) - self.menus[name] = menu -end - -function MenuSystem:getMenu(name) - return self.menus[name] -end - -function MenuSystem:menuExist(name) - return (self.menus[name] ~= nil) -end - -function MenuSystem:switchMenu(menuName) - for name, guiElement in pairs(self.menus) do - if (name == menuName) then - guiElement:getFocus() - guiElement:setVisibility(true) - guiElement:setActivity(true) - else - guiElement:setVisibility(false) - guiElement:setActivity(false) - end - end -end - -function MenuSystem:lockMenu(menu, lock) - local lock = lock or true - if self:menuExist(menu) then - self.menus[menu]:lock(lock) - end -end - -function MenuSystem:lockMenuVisibility(menu, lock) - local lock = lock or true - if self:menuExist(menu) then - self.menus[menu]:lockVisibility(lock) - end -end - -function MenuSystem:setMenuActivity(menu, activity) - local activity = activity or true - if self:menuExist(menu) then - self.menus[menu]:setActivity(activity) - if activity == true then - -- if we make the menu active, he have to be visible too - self.menus[menu]:setVisibility(true) - end - end -end - -function MenuSystem:setMenuVisibility(menu, visibility) - local visibility = visibility or true - if self:menuExist(menu) then - self.menus[menu]:setVisibility(visibility) - end -end - -function MenuSystem:setAllMenuVisibility(visibility) - for _, guiElement in pairs(self.menus) do - guiElement:setVisibility(visibility) - end -end - -function MenuSystem:setAllMenuActivity(activity) - for _, guiElement in pairs(self.menus) do - guiElement.isActive = activity - end -end - -function MenuSystem:removeDestroyedMenus() - -- On retire les entitées marquées comme supprimées - for name, guiElement in pairs(self.menus) do - if (guiElement.isDestroyed == true) then - self.menus[name] = nil - end - end -end - --- SOUND FUNCTIONS --- Add sounds to every menus --- TODO: rework to be used directly by widgets later - -function MenuSystem:setSoundFromSceneAssets(soundname) - for _, guiElement in pairs(self.menus) do - guiElement:setSoundFromSceneAssets(soundname) - end -end - -function MenuSystem:setSound(soundasset) - for _, guiElement in pairs(self.menus) do - guiElement:setSound(soundasset) - end -end - --- UPDATE FUNCTIONS --- Update the menus of the menusystem - -function MenuSystem:update(dt) - if (self.isActive) then - self:removeDestroyedMenus() - for _, guiElement in pairs(self.menus) do - guiElement:updateElement(dt) - end - - if self.menus[self.focusedMenu] ~= nil then - -- Only check buttons if the current focused menu is actually active - if self.menus[self.focusedMenu].isActive then - for keyname, keydata in pairs(self.keys) do - if self.keys[keyname].isPressed then - self.menus[self.focusedMenu]:keyreleased(keyname) - end - end - end - end - end -end - --- MOUSE FUNCTIONS --- Send mouse inputs to the menu - -function MenuSystem:mousemoved(x, y, dx, dy) - if (self.isActive) then - - for _, guiElement in pairs(self.menus) do - if guiElement.isActive then - if guiElement:areCoordInside(x, y) then - local xx, yy = guiElement:getRelativeCoordinate(x, y) - guiElement:mousemoved(xx, yy) - break; - end - end - end - - end -end - -function MenuSystem:mousepressed( x, y, button, istouch ) - if (self.isActive) then - for _, guiElement in pairs(self.menus) do - if guiElement.isActive then - if guiElement:areCoordInside(x, y) then - local xx, yy = guiElement:getRelativeCoordinate(x, y) - guiElement:mousepressed(xx, yy, button, istouch ) - break; - end - end - end - end -end - --- DRAW FUNCTIONS --- All functions to draw the menus of the menusystem - -function MenuSystem:getDrawList() - local drawList = {} - for name, guiElement in pairs(self.menus) do - local drawObject = {} - drawObject.name = name - drawObject.depth = guiElement.depth - table.insert(drawList, drawObject) - end - table.sort(drawList, function(a,b) return a.depth > b.depth end) - - return drawList -end - -function MenuSystem:draw(dt) - if (self.isActive) then - -- Draw all the menus - self.drawList = self:getDrawList() - - for _, drawObject in ipairs(self.drawList) do - local guiElement = self.menus[drawObject.name] - if (guiElement.isVisible) then - guiElement:drawElement(dt) - end - end - end -end - -return MenuSystem diff --git a/birb/modules/menusystem/parent.lua b/birb/modules/menusystem/parent.lua deleted file mode 100644 index 059fd34..0000000 --- a/birb/modules/menusystem/parent.lua +++ /dev/null @@ -1,119 +0,0 @@ -local Rect = require "birb.objects.2D.rect" - -local GuiElement = Rect:extend() - -function GuiElement:new(name, x, y, w, h) - GuiElement.super.new(self, x, y, w, h) - self.name = name - - self.isDestroyed = false - self.isVisible = true - self.isActive = true - self.isLocked = false - self.isAlwaysVisible = false - - self.depth = 0 - - self:register() -end - -function GuiElement:getGui() - local scene = core.scenemanager.currentScene - return scene.menusystem -end - -function GuiElement:register() - local gui = self:getGui() - gui:addMenu(self.name, self) -end - -function GuiElement:destroy() - self.destroyed = true -end - --- VISIBILITY/ACTIVITY --- Handle drawing and how we interact with - -function GuiElement:setDepth(depth) - self.depth = depth or 0 -end - -function GuiElement:setVisibility(visibility) - if self.isLocked == false and self.isAlwaysVisible == false then - self.isVisible = visibility - else - -- if the element is locked (thus is always active), it should also - -- be always visible. - self.isVisible = true - end -end - -function GuiElement:setActivity(activity) - if self.isLocked == false then - self.isActive = activity - else - self.isActive = true - end -end - -function GuiElement:lock(lock) - self.isLocked = lock -end - -function GuiElement:lockVisibility(lock) - self.isAlwaysVisible = lock -end - -function GuiElement:getFocus() - local gui = self:getGui() - gui.focusedMenu = self.name -end - -function GuiElement:haveFocus() - local gui = self:getGui() - return (gui.focusedMenu == self.name) -end - --- UPDATE FUNCTIONS --- Update the menu every game update - --- External update function -function GuiElement:updateElement(dt) - self:update(dt) -end - --- Internal update function -function GuiElement:update(dt) - -- Cette fonction ne contient rien par défaut -end - --- DRAW FUNCTIONS --- Draw the menu and its content - -function GuiElement:drawElement() - self:draw() -end - -function GuiElement:draw() - -- nothing here -end - --- KEYBOARD FUNCTIONS --- Handle key press - -function GuiElement:keyreleased(key) - -- Cette fonction ne contient rien par défaut -end - --- MOUSE FUNCTIONS --- Handle pointers (clic/touch) - -function GuiElement:mousemoved(x, y) - -- Cette fonction ne contient rien par défaut -end - -function GuiElement:mousepressed(x, y, button, istouch) - -- Cette fonction ne contient rien par défaut -end - -return GuiElement diff --git a/birb/modules/scenes.lua b/birb/modules/scenes.lua index f78e0aa..59ddeb8 100644 --- a/birb/modules/scenes.lua +++ b/birb/modules/scenes.lua @@ -27,35 +27,29 @@ local cwd = (...):gsub('%.scenes$', '') .. "." local Scene = Object:extend() local Assets = require(cwd .. "assets") -local MenuSystem = require(cwd .. "menusystem") +local Gui = require (cwd .. "gui") -- INIT FUNCTIONS -- Initialize and configure the scene -function Scene:new(args) +function Scene:new() self.mouse = {} self.mouse.x, self.mouse.y = core.screen:getMousePosition() self.assets = Assets() - self.menusystem = MenuSystem(self) self.sources = core.input:getSources() + self.gui = Gui(self) self.inputLocked = true self.inputLockedTimer = 2 - self:flushKeys() - self.isActive = false - self.args = args + self.dialog = nil self:initWorld() self:register() end -function Scene:start() - -- Empty function -end - function Scene:register() core.scenemanager:setScene(self) end @@ -64,13 +58,18 @@ function Scene:clear() -- TODO: send automatic cleanups to the different elements of the scene end +function Scene:restored() + +end + -- UPDATE FUNCTIONS -- Handle stuff that happens every steps function Scene:updateScene(dt) self:updateStart(dt) self:setKeys() - self.menusystem:update(dt) + self.assets:update(dt) + self:updateGUI(dt) self:updateWorld(dt) self:update(dt) self:updateEnd(dt) @@ -89,11 +88,20 @@ function Scene:updateEnd(dt) end function Scene:updateWorld(dt) - if (self.world ~= nil) and (self.world.isActive) then + if ((self.world ~= nil) and (self.world.isActive) and (self.dialog == nil)) then self.world:update(dt) end end +function Scene:updateGUI(dt) + if (self.gui ~= nil) then + self.gui:update(dt) + if (core.screen:isActive()) then + self.gui:keycheck(self:getKeys(1)) + end + end +end + -- MOUSE FUNCTIONS -- Make the scene support the pointer @@ -130,12 +138,19 @@ end -- DRAW FUNCTIONS -- Draw the scene and its content +function Scene:redraw() + self.gui:redraw() +end + function Scene:drawScene() self:drawStart() self:drawWorld() self:draw() - self.menusystem:draw() + self.gui:drawBottom() self:drawEnd() + core.screen:drawTransition() + self.gui:drawTop() + self:drawOverTransition() end function Scene:drawStart() @@ -150,6 +165,10 @@ function Scene:drawEnd() end +function Scene:drawOverTransition() + +end + function Scene:drawWorld(dt) if (self.world ~= nil) then self.world:draw() @@ -160,36 +179,35 @@ end -- Handle inputs from keyboard/controllers function Scene:setKeys() - if (self.inputLocked) or (not self.isActive) then + if (self.inputLocked) then self.inputLockedTimer = self.inputLockedTimer - 1 if (self.inputLockedTimer <= 0 ) then self.inputLocked = false end - self.menusystem.keys = self:getKeys(1) else self.sources = core.input.sources - self.menusystem.keys = self:getKeys(1) end end function Scene:getKeys(sourceid) if sourceid == nil then - core.debug:logWarn("scene", "no sourceid detected, will default to 1") + core.debug:warning("scene", "no sourceid detected, will default to 1") end local sourceid = sourceid or 1 - if (self.inputLocked) or (not self.isActive) then - core.debug:logDebug("scene", "inputs are currently locked") + + if (self.inputLocked) then + core.debug:print("scene", "inputs are currently locked") return core.input.fakekeys else return self.sources[sourceid].keys end end -function Scene:flushKeys(timer) +function Scene:flushKeys() core.input:flushKeys() - self.sources = core.input.sources - self.inputLockedTimer = timer or 2 + self.sources = core.input:getSources() + self.inputLockedTimer = 2 self.inputLocked = true end diff --git a/birb/modules/transitions/canvas.lua b/birb/modules/transitions/canvas.lua new file mode 100644 index 0000000..04df3bd --- /dev/null +++ b/birb/modules/transitions/canvas.lua @@ -0,0 +1,33 @@ +local TransitionParent = require "birb.modules.transitions.parent" +local CanvasTransition = TransitionParent:extend() + +function CanvasTransition:new(func, ox, oy, fadeOut, easeIn, easeOut, duration, wait) + CanvasTransition.super.new(self, func, ox, oy, fadeOut, easeIn, easeOut, duration, wait) + self:generateCanvas(0) +end + +function CanvasTransition:update(dt) + CanvasTransition.super.update(self, dt) + self:generateCanvas(dt) +end + +function CanvasTransition:generateCanvas(dt) + self.canvas = love.graphics.newCanvas(424, 240) + love.graphics.setCanvas(self.canvas) + self:drawCanvas(dt) + love.graphics.setCanvas() +end + +function CanvasTransition:drawCanvas(dt) + +end + +function CanvasTransition:draw() + if (self.canvas ~= nil) then + love.graphics.setBlendMode("multiply", "premultiplied") + love.graphics.draw(self.canvas, 0, 0) + love.graphics.setBlendMode("alpha") + end +end + +return CanvasTransition \ No newline at end of file diff --git a/birb/modules/transitions/circle.lua b/birb/modules/transitions/circle.lua new file mode 100644 index 0000000..360063d --- /dev/null +++ b/birb/modules/transitions/circle.lua @@ -0,0 +1,16 @@ +local TransitionParent = require "birb.modules.transitions.canvas" +local DefaultTransition = TransitionParent:extend() + +function DefaultTransition:new(func, ox, oy, fadeOut) + DefaultTransition.super.new(self, func, ox, oy, fadeOut, "inQuad", "outQuad", 0.8, 0.1) +end + +function DefaultTransition:drawCanvas() + love.graphics.setColor(0,0,0,1) + love.graphics.rectangle("fill", 0, 0, 424, 240) + utils.graphics.resetColor() + local value = 1 - self.value + love.graphics.circle("fill",self.ox, self.oy, (424/2) * 1.5 * value) +end + +return DefaultTransition \ No newline at end of file diff --git a/birb/modules/transitions/decal.lua b/birb/modules/transitions/decal.lua new file mode 100644 index 0000000..7be07b2 --- /dev/null +++ b/birb/modules/transitions/decal.lua @@ -0,0 +1,22 @@ +local TransitionParent = require "birb.modules.transitions.canvas" +local DecalTransition = TransitionParent:extend() + +function DecalTransition:new(func, ox, oy, fadeOut, decal) + self.decal = decal + DecalTransition.super.new(self, func, ox, oy, fadeOut, "inQuad", "outQuad", 0.8, 0.1) +end + +function DecalTransition:loadResources() + self.decalDrawable = love.graphics.newImage("assets/transitions/" .. self.decal .. ".png") +end + +function DecalTransition:drawCanvas() + love.graphics.setColor(0,0,0,1) + love.graphics.rectangle("fill", 0, 0, 424, 240) + utils.graphics.resetColor() + local w, h = self.decalDrawable:getDimensions() + local value = (1 - self.value) * (240 / h) * 4 + love.graphics.draw(self.decalDrawable,self.ox,self.oy,0,value, value, w / 2, h / 2) +end + +return DecalTransition \ No newline at end of file diff --git a/birb/modules/transitions/default.lua b/birb/modules/transitions/default.lua new file mode 100644 index 0000000..4727a34 --- /dev/null +++ b/birb/modules/transitions/default.lua @@ -0,0 +1,14 @@ +local TransitionParent = require "birb.modules.transitions.parent" +local DefaultTransition = TransitionParent:extend() + +function DefaultTransition:new(func, ox, oy, fadeOut) + DefaultTransition.super.new(self, func, ox, oy, fadeOut, "inQuad", "outQuad", 0.35, 0.1) +end + +function DefaultTransition:draw() + love.graphics.setColor(0,0,0,self.value) + love.graphics.rectangle("fill", 0, 0, 424, 240) + utils.graphics.resetColor() +end + +return DefaultTransition \ No newline at end of file diff --git a/birb/modules/transitions/init.lua b/birb/modules/transitions/init.lua new file mode 100644 index 0000000..0a28aef --- /dev/null +++ b/birb/modules/transitions/init.lua @@ -0,0 +1,4 @@ +return { + default = require "birb.modules.transitions.default", + circle = require "birb.modules.transitions.circle" +} \ No newline at end of file diff --git a/birb/modules/transitions/parent.lua b/birb/modules/transitions/parent.lua new file mode 100644 index 0000000..32dd61f --- /dev/null +++ b/birb/modules/transitions/parent.lua @@ -0,0 +1,42 @@ +local TransitionParent = Object:extend() +local TweenManager = require "birb.classes.time" + +function TransitionParent:new(func, ox, oy, fadeOut, easeIn, easeOut, duration, wait) + self.tween = TweenManager(self) + self:loadResources() + self.func = func + self.ox = ox or 0 + self.oy = oy or 0 + self.fadeOut = fadeOut + if (self.fadeOut) then + self.value = 1 + self.tween:newTween(wait, duration, {value = 0}, easeOut) + else + self.value = 0 + self.tween:newTween(0, duration, {value = 1}, easeIn) + end + self.tween:newTimer(duration + wait, "isOver") +end + +function TransitionParent:loadResources() + --vide par defaut +end + +function TransitionParent:update(dt) + self.tween:update(dt * 1.5) +end + +function TransitionParent:timerResponse(timer) + if (timer == "isOver") then + if (self.func ~= nil) then + self.func() + end + core.screen:transitionOver(self.fadeOut) + end +end + +function TransitionParent:draw() + +end + +return TransitionParent \ No newline at end of file diff --git a/birb/modules/world/actors/actor2D.lua b/birb/modules/world/actors/actor2D.lua index 393edc9..90e4b0b 100644 --- a/birb/modules/world/actors/actor2D.lua +++ b/birb/modules/world/actors/actor2D.lua @@ -21,10 +21,9 @@ 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 Rect = require "birb.classes.2D.rect" -local Rect = require "birb.objects.2D.rect" - -local BaseActor = require("birb.modules.world.actors.mixins.base") +local BaseActor = require "birb.modules.world.actors.mixins.base" local SpritedActor = require("birb.modules.world.actors.mixins.sprites") local TimedActor = require("birb.modules.world.actors.mixins.timers") local InputActor = require("birb.modules.world.actors.mixins.inputs") @@ -37,13 +36,14 @@ Actor2D:implement(TimedActor) Actor2D:implement(InputActor) Actor2D:implement(PhysicalActor) -local Hitbox = require("birb.modules.world.actors.utils.hitbox2D") +local Hitbox = require "birb.modules.world.actors.utils.hitbox2D" -- INIT FUNCTIONS -- Initialise the actor and its base functions function Actor2D:new(world, type, x, y, w, h, isSolid) Actor2D.super.new(self, x, y, w, h) + self:init(world, type) self:initPhysics(Hitbox, isSolid) self:initTimers() @@ -51,10 +51,6 @@ function Actor2D:new(world, type, x, y, w, h, isSolid) self:initKeys() end -function Actor2D:packForHitbox() - return {0, 0, self.w, self.h} -end - function Actor2D:destroy() self.world:removeActor(self) self.mainHitbox:destroy() @@ -134,6 +130,13 @@ function Actor2D:getViewCenter() return x, y end +-- HITBOXES FUNCTIONS +-- Functions related to actor hitboxes + +function Actor2D:packForHitbox() + return {0, 0, self.w, self.h} +end + -- DRAW FUNCTIONS -- Draw the actors. diff --git a/birb/modules/world/actors/actor3D.lua b/birb/modules/world/actors/actor3D.lua index 7a479bd..e99964c 100644 --- a/birb/modules/world/actors/actor3D.lua +++ b/birb/modules/world/actors/actor3D.lua @@ -22,7 +22,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ]] -local BasicBox = require "birb.objects.3D.box" +local Hitbox = require("birb.modules.world.actors.utils.hitbox3D") +local Boxes = require("birb.modules.world.actors.utils.boxes") +local BasicBox = require "birb.classes.3D.box" local BaseActor = require("birb.modules.world.actors.mixins.base") local SpritedActor = require("birb.modules.world.actors.mixins.sprites") @@ -39,9 +41,6 @@ Actor3D:implement(InputActor) Actor3D:implement(PhysicalActor) Actor3D:implement(Shape3DActor) -local Hitbox = require("birb.modules.world.actors.utils.hitbox3D") -local Boxes = require("birb.modules.world.actors.utils.boxes") - -- INIT FUNCTIONS -- Initialise the actor and its base functions @@ -51,6 +50,7 @@ function Actor3D:new(world, type, x, y, z, w, h, d, isSolid) self:initPhysics(Hitbox, isSolid) self:initTimers() self:initSprite() + self:initKeys() self:initShape(Boxes, true) end @@ -61,11 +61,6 @@ function Actor3D:destroy() self.isDestroyed = true end -function Actor3D:packForHitbox() - return {0, 0, 0, self.w, self.h, self.d} -end - - -- PHYSICS FUNCTIONS -- Handle movement and collisions. @@ -152,6 +147,13 @@ function Actor3D:getViewCenter() return x, y - (self.d/2) end +-- HITBOXES FUNCTIONS +-- Functions related to actor hitboxes + +function Actor3D:packForHitbox() + return {0, 0, 0, self.w, self.h, self.d} +end + -- DRAW FUNCTIONS -- Draw the actors. @@ -161,10 +163,6 @@ function Actor3D:drawShadow(x, y) utils.graphics.resetColor() end -function Actor3D:getShape() - return (self.x), (self.y - self.z - self.d), self.w, (self.h + self.d) -end - function Actor3D:draw() self:drawStart() if (self.box ~= nil) then diff --git a/birb/modules/world/actors/gfx2D.lua b/birb/modules/world/actors/gfx2D.lua index e352310..955170a 100644 --- a/birb/modules/world/actors/gfx2D.lua +++ b/birb/modules/world/actors/gfx2D.lua @@ -26,15 +26,14 @@ local Actor2D = require(cwd .. "actor2D") local GFX = Actor2D:extend() function GFX:new(world, x, y, spritename) - local baseSprite = world.scene.assets:getWithType(spritename, "sprite") - local width, height = baseSprite:getDimensions() + local width, height = world.scene.assets.sprites[spritename]:getDimensions() GFX.super.new(self, world, "gfx", x - (width/2), y - (height/2), width, height) self:setSprite(spritename, true) end function GFX:animationEnded(animation) - core.debug:logDebug("gfx2D", 'Current animation "' .. animation .. '" have ended, destroying gfx') + core.debug:print("gfx2D", 'Current animation "' .. animation .. '" have ended, destroying gfx') self:destroy() end diff --git a/birb/modules/world/actors/gfx3D.lua b/birb/modules/world/actors/gfx3D.lua index fe271d4..c7e0325 100644 --- a/birb/modules/world/actors/gfx3D.lua +++ b/birb/modules/world/actors/gfx3D.lua @@ -26,15 +26,14 @@ local Actor3D = require(cwd .. "actor3D") local GFX = Actor3D:extend() function GFX:new(world, x, y, z, spritename) - local baseSprite = world.scene.assets:getWithType(spritename, "sprite") - local width, height = baseSprite:getDimensions() + local width, height = world.scene.assets.sprites[spritename]:getDimensions() GFX.super.new(self, world, "gfx", x - (width/2), y - (width/2), z - (height/2), width, width, height) self:setSprite(spritename, true) end function GFX:animationEnded(animation) - core.debug:logDebug("gfx3D", 'Current animation "' .. animation .. '" have ended, destroying gfx') + core.debug:print("gfx3D", 'Current animation "' .. animation .. '" have ended, destroying gfx') self:destroy() end diff --git a/birb/modules/world/actors/mixins/base.lua b/birb/modules/world/actors/mixins/base.lua index cdbb49a..0bfcee3 100644 --- a/birb/modules/world/actors/mixins/base.lua +++ b/birb/modules/world/actors/mixins/base.lua @@ -31,13 +31,27 @@ function BaseActor:init(world, type) self.type = type or "" self.depth = 0 + self.updateFunctions = {} + self:setManagers(world) - self:initKeys() self:setDebugColor(1, 1, 1) self:register() + self.useTileCollision = true +end - self.updateFunctions = {} +function BaseActor:setProperties(properties) + -- Do something here +end + +function BaseActor:addUpdateFunction(func) + table.insert(self.updateFunctions, func) +end + +function BaseActor:applyUpdateFunctions(dt) + for key, func in ipairs(self.updateFunctions) do + func(self, dt) + end end function BaseActor:setManagers(world) @@ -77,16 +91,6 @@ function BaseActor:update(dt) self:updateEnd(dt) end -function BaseActor:addUpdateFunction(func) - table.insert(self.updateFunctions, func) -end - -function BaseActor:applyUpdateFunctions(dt) - for key, func in ipairs(self.updateFunctions) do - func(self, dt) - end -end - function BaseActor:updateEnd(dt) end @@ -107,8 +111,4 @@ function BaseActor:drawEnd() end -function BaseActor:drawHUD(id, height, width) - -end - return BaseActor diff --git a/birb/modules/world/actors/mixins/inputs.lua b/birb/modules/world/actors/mixins/inputs.lua index cc4a1b3..ae9b41e 100644 --- a/birb/modules/world/actors/mixins/inputs.lua +++ b/birb/modules/world/actors/mixins/inputs.lua @@ -1,4 +1,4 @@ --- SpritedActor.lua :: Get input from the world object. +-- InputActor.lua :: Get input from the world object. --[[ Copyright © 2019 Kazhnuz diff --git a/birb/modules/world/actors/mixins/physics.lua b/birb/modules/world/actors/mixins/physics.lua index d6c5e2b..2b99ed5 100644 --- a/birb/modules/world/actors/mixins/physics.lua +++ b/birb/modules/world/actors/mixins/physics.lua @@ -1,10 +1,11 @@ PhysicalActor = Object:extend() +local hitboxStructure = require "birb.structures.hitbox" -- PHYSICS FUNCTIONS -- Raw implementation of everything common in physics function PhysicalActor:initPhysics(hitboxObj, isSolid) - self.isSolid = isSolid or false + self.isSolid = isSolid or false self.xsp = 0 self.ysp = 0 @@ -143,7 +144,8 @@ function PhysicalActor:initHitboxes(hitboxObj) end function PhysicalActor:initMainHitbox() - -- Empty function : don't load ANY real hitbox function into PhysicalActor + self.mainHitbox = self.Hitbox(self, self.type, self:packForHitbox(), 0, 0, self.isSolid) + self.mainHitbox:advertiseAsMainHitbox() end function PhysicalActor:setHitboxFile(file) @@ -175,28 +177,22 @@ end function PhysicalActor:addHitboxFromFrameData(framedata, animationID, frameID, hitboxID) local sx, sy = self.sprite:getScalling() - local type = framedata[1] - local box = framedata[2] - local isSolid = framedata[3] or false + local hitbox = utils.table.parse(framedata, hitboxStructure, 1) local anim = animationID or "null" local frame = frameID or 0 local id = hitboxID or 0 - if (type == "main") then - self.mainHitbox:setFromData(box, sx, sy) + if (hitbox.type == "main") then + self.mainHitbox:setFromData(hitbox.box, sx, sy) else - local hitboxName = anim .. frame .. type .. id - self:addHitbox(hitboxName, type, box, sx, sy, isSolid) + local hitboxName = anim .. frame .. hitbox.type .. id + self:addHitbox(hitboxName, hitbox.type, hitbox.box, sx, sy, hitbox.isSolid) return hitboxName end end -function PhysicalActor:initMainHitbox() - self.mainHitbox = self.Hitbox(self, self.type, self:packForHitbox(), 0, 0, self.isSolid) - self.mainHitbox:advertiseAsMainHitbox() -end - function PhysicalActor:addHitbox(name, type, data, sx, sy, isSolid) + isSolid = (isSolid == true) if (self.hitboxes[name] ~= nil) then core.debug:logWarn("PhysicalActor", "the hitbox " .. name .. " already exists") else @@ -222,7 +218,7 @@ function PhysicalActor:updateHitboxes() end end -function PhysicalActor:checkHitboxesCollisions(filter) +function PhysicalActor:applyHitboxesCollisions(filter) for k, v in pairs(self.hitboxes) do self:applyHitboxCollisions(k, filter) end @@ -232,12 +228,12 @@ function PhysicalActor:applyHitboxCollisions(name, filter) local cols, colNumber = {}, 0 local filter = filter or self.filter if (self.isDestroyed == false) and (self.hitboxes[name] ~= nil) then - cols, colNumber = self.hitboxes[name]:checkCollision(filter) - local type = self.hitboxes[name].type + cols, colNumber = self.hitboxes[name]:checkCollision(filter) + local type = self.hitboxes[name].type - for i, col in ipairs(cols) do - self:hitboxResponse(name, type, col) - end + for i, col in ipairs(cols) do + self:hitboxResponse(name, type, col) + end end return cols, colNumber @@ -274,4 +270,4 @@ function PhysicalActor:drawMainHitbox() end end -return PhysicalActor +return PhysicalActor \ No newline at end of file diff --git a/birb/modules/world/actors/mixins/shapes.lua b/birb/modules/world/actors/mixins/shapes.lua index 9bd7f5a..05a1d21 100644 --- a/birb/modules/world/actors/mixins/shapes.lua +++ b/birb/modules/world/actors/mixins/shapes.lua @@ -94,4 +94,4 @@ function ShapedActor:redrawShadowCanvas() end end -return ShapedActor \ No newline at end of file +return ShapedActor diff --git a/birb/modules/world/actors/mixins/sprites.lua b/birb/modules/world/actors/mixins/sprites.lua index 51bf449..4641190 100644 --- a/birb/modules/world/actors/mixins/sprites.lua +++ b/birb/modules/world/actors/mixins/sprites.lua @@ -37,7 +37,7 @@ end function SpritedActor:changeAnimation(animation, restart) if (self.sprite ~= nil) then - core.debug:logWarn("actor", "the function SpritedActor:changeAnimation is deprecated, prefer SpritedActor.sprite:changeAnimation()") + core.debug:warning("actor", "the function SpritedActor:changeAnimation is deprecated, prefer SpritedActor.sprite:changeAnimation()") self.sprite:changeAnimation(animation, restart) end end @@ -48,7 +48,7 @@ end function SpritedActor:setCustomSpeed(customSpeed) if (self.sprite ~= nil) then - core.debug:logWarn("actor", "the function SpritedActor:setCustomSpeed is deprecated, prefer SpritedActor.sprite:setCustomSpeed()") + core.debug:warning("actor", "the function SpritedActor:setCustomSpeed is deprecated, prefer SpritedActor.sprite:setCustomSpeed()") self.sprite:setCustomSpeed(customSpeed) end end @@ -61,33 +61,33 @@ end function SpritedActor:getCurrentAnimation() if (self.sprite ~= nil) then - core.debug:logWarn("actor", "the function SpritedActor:getCurrentAnimation is deprecated, prefer SpritedActor.sprite:getCurrentAnimation()") + core.debug:warning("actor", "the function SpritedActor:getCurrentAnimation is deprecated, prefer SpritedActor.sprite:getCurrentAnimation()") return self.sprite:getCurrentAnimation() end end function SpritedActor:getSpriteScalling() - core.debug:logWarn("actor", "the function SpritedActor:getSpriteScalling is deprecated, prefer SpritedActor.sprite:getScalling()") + core.debug:warning("actor", "the function SpritedActor:getSpriteScalling is deprecated, prefer SpritedActor.sprite:getScalling()") return self.sprite:getScalling() end function SpritedActor:getFrame() if (self.sprite ~= nil) then - core.debug:logWarn("actor", "the function SpritedActor:getFrame is deprecated, prefer SpritedActor.sprite:getFrame()") + core.debug:warning("actor", "the function SpritedActor:getFrame is deprecated, prefer SpritedActor.sprite:getFrame()") return self.sprite:getFrame() end end function SpritedActor:getRelativeFrame() if (self.sprite ~= nil) then - core.debug:logWarn("actor", "the function SpritedActor:getRelativeFrame is deprecated, prefer SpritedActor.sprite:getRelativeFrame()") + core.debug:warning("actor", "the function SpritedActor:getRelativeFrame is deprecated, prefer SpritedActor.sprite:getRelativeFrame()") return self.sprite:getRelativeFrame() end end function SpritedActor:getAnimationDuration() if (self.sprite ~= nil) then - core.debug:logWarn("actor", "the function SpritedActor:getAnimationDuration is deprecated, prefer SpritedActor.sprite:getAnimationDuration()") + core.debug:warning("actor", "the function SpritedActor:getAnimationDuration is deprecated, prefer SpritedActor.sprite:getAnimationDuration()") return self.sprite:getAnimationDuration() end end diff --git a/birb/modules/world/actors/mixins/timers.lua b/birb/modules/world/actors/mixins/timers.lua index 7e045b0..4dacbfb 100644 --- a/birb/modules/world/actors/mixins/timers.lua +++ b/birb/modules/world/actors/mixins/timers.lua @@ -23,16 +23,18 @@ local TimedActor = Object:extend() +local TweenManager = require "birb.classes.time" + -- TIMER FUNCTIONS -- Control the integrated timers of the actor function TimedActor:initTimers() - self.timers = core.modules.Timers(self) + self.timers = TweenManager(self) self:addUpdateFunction(self.updateTimers) end function TimedActor:addTimer(name, t) - core.debug:logWarn("actor", "function actor:addTimer is deprecated, prefer actor.timers:newTimer") + core.debug:warning("actor", "function actor:addTimer is deprecated, prefer actor.timers:newTimer") self.timers:newTimer(t, name) end diff --git a/birb/modules/world/actors/utils/boxes/mapped.lua b/birb/modules/world/actors/utils/boxes/mapped.lua index dc0cc04..e733cab 100644 --- a/birb/modules/world/actors/utils/boxes/mapped.lua +++ b/birb/modules/world/actors/utils/boxes/mapped.lua @@ -37,7 +37,7 @@ end function MappedBox:drawTextureContent() local tx, ty = self.x, self.y - (self.z + self.d) - core.debug:logInfo("mappedbox", "getting map layers at position " .. tx .. ";" .. ty) + core.debug:print("mappedbox", "getting map layers at position " .. tx .. ";" .. ty) love.graphics.push() love.graphics.origin() love.graphics.translate(math.floor(-tx), math.floor(-ty)) diff --git a/birb/modules/world/actors/utils/boxes/textured.lua b/birb/modules/world/actors/utils/boxes/textured.lua index df6de22..1b79162 100644 --- a/birb/modules/world/actors/utils/boxes/textured.lua +++ b/birb/modules/world/actors/utils/boxes/textured.lua @@ -29,8 +29,8 @@ local TexturedBox = Box3D:extend() function TexturedBox:new(owner, w, h, d, topTexture, bottomTexture) local bottomTexture = bottomTexture or topTexture - self.topTexture = owner.assets:getWithType(topTexture, "texture") - self.bottomTexture = owner.assets:getWithType(bottomTexture, "texture") + self.topTexture = owner.assets.images[topTexture] + self.bottomTexture = owner.assets.images[bottomTexture] TexturedBox.super.new(self, owner, w, h, d) self.haveLine = false diff --git a/birb/modules/world/actors/utils/hitbox2D.lua b/birb/modules/world/actors/utils/hitbox2D.lua index 74412b6..cd9571a 100644 --- a/birb/modules/world/actors/utils/hitbox2D.lua +++ b/birb/modules/world/actors/utils/hitbox2D.lua @@ -23,6 +23,7 @@ ]] local Hitbox2D = Object:extend() +local rectStructure = require "birb.structures.rect" -- INIT FUNCTIONS -- Initialise the actor and its base functions @@ -42,24 +43,6 @@ function Hitbox2D:new(owner, type, data, sx, sy, isSolid) self:register() end -function Hitbox2D:setFromData(data, sx, sy) - local sx = sx or 0 - local sy = sy or 0 - - self.ox = data[1] - self.oy = data[2] - self.w = data[3] - self.h = data[4] - - if (sx < 0) then - self.ox = self.owner.w - self.ox - self.w - end - - if (sy < 0) then - self.oy = self.owner.h - self.oy - self.h - end -end - function Hitbox2D:advertiseAsMainHitbox() self.isMainHitBox = true end @@ -72,6 +55,30 @@ function Hitbox2D:modify(ox, oy, w, h) self.h = h end +function Hitbox2D:setFromData(data, sx, sy) + local rect = utils.table.parse(data, rectStructure) + + self.ox = rect.x + self.oy = rect.y + self.w = rect.w + self.h = rect.h + + self:applyScale(sx, sy) +end + +function Hitbox2D:applyScale(sx, sy) + local sx = sx or 1 + local sy = sy or 1 + + if (sx < 0) then + self.ox = self.owner.w - self.ox - self.w + end + + if (sy < 0) then + self.oy = self.owner.h - self.oy - self.h + end +end + function Hitbox2D:setDebugColor(r,g,b) self.debug = {} self.debug.r = r @@ -123,13 +130,41 @@ end function Hitbox2D:checkCollisionAtPoint(dx, dy, filter) self:updatePosition() - local dx, dy = self.ox + dx, self.oy + dy - local x, y, cols, colNumber = self.world:checkCollision(self, dx, dy, filter) + local nx, ny = self.ox + dx, self.oy + dy + if (self.owner.useTileCollision and self.world.map.supportTileCollision) then + if (self:checkTileCollision(nx, self.y)) then + nx = self.x + local relx = dx - self.x + for i = 1, math.ceil(math.abs(relx)), 1 do + local nnx = self.x + i * utils.math.sign(relx) + if (not self:checkTileCollision(nnx, self.y)) then + nx = nnx + end + end + self.owner.xsp = 0 + end + if (self:checkTileCollision(self.x, ny)) then + ny = self.y + local rely = dy - self.y + for i = 1, math.ceil(math.abs(rely)), 1 do + local nny = self.y + i * utils.math.sign(rely) + if (not self:checkTileCollision(self.x, nny)) then + ny = nny + end + end + self.owner.ysp = 0 + end + end + local x, y, cols, colNumber = self.world:checkCollisionAtPoint(self, nx, ny, filter) local newx, newy = self:getNewOwnerPosition(x, y) return newx, newy, cols, colNumber end +function Hitbox2D:checkTileCollision(dx, dy) + return self.world:haveTileTypeInRect(dx + 1, dy + 1, self.w - 2, self.h - 2, "solid") +end + -- DRAW FUNCTIONS -- Just some debug function to draw hitbox @@ -137,8 +172,6 @@ function Hitbox2D:draw() local x, y = self:getPosition() love.graphics.setColor(self.debug.r, self.debug.g, self.debug.b, 1) utils.graphics.box(x, y, self.w, self.h) - love.graphics.setColor(1, 1, 1, 1) - love.graphics.points(x, y) utils.graphics.resetColor() end diff --git a/birb/modules/world/actors/utils/hitbox3D.lua b/birb/modules/world/actors/utils/hitbox3D.lua index 8d7467e..261e104 100644 --- a/birb/modules/world/actors/utils/hitbox3D.lua +++ b/birb/modules/world/actors/utils/hitbox3D.lua @@ -23,6 +23,7 @@ ]] local Hitbox3D = Object:extend() +local boxStructure = require "birb.structures.box" -- INIT FUNCTIONS -- Initialise the actor and its base functions @@ -42,25 +43,6 @@ function Hitbox3D:new(owner, type, data, sx, sy, isSolid) self:register() end -function Hitbox3D:setFromData(data, sx, sy) - local sx = sx or 0 - local sy = sy or 0 - - self.ox = data[1] - self.oy = data[2] - self.oz = data[3] - self.w = data[4] - self.h = data[5] - self.d = data[6] - - if (sx < 0) then - self.ox = self.owner.w - self.ox - self.w - end - if (sy < 0) then - self.oz = self.owner.d - self.oz - self.d - end -end - function Hitbox3D:advertiseAsMainHitbox() self.isMainHitBox = true end @@ -75,6 +57,32 @@ function Hitbox3D:modify(ox, oy, oz, w, h, d) self.d = d end +function Hitbox3D:setFromData(data, sx, sy) + local box = utils.table.parse(data, boxStructure) + + self.ox = box.x + self.oy = box.y + self.oz = box.z + self.w = box.w + self.h = box.h + self.d = box.d + + self:applyScale(sx, sy) +end + +function Hitbox3D:applyScale(sx, sy) + local sx = sx or 1 + local sy = sy or 1 + + if (sx < 0) then + self.ox = self.owner.w - self.ox - self.w + end + + if (sy < 0) then + self.oy = self.owner.h - self.oy - self.h + end +end + function Hitbox3D:setDebugColor(r,g,b) self.debug = {} self.debug.r = r @@ -126,8 +134,8 @@ end function Hitbox3D:checkCollisionAtPoint(dx, dy, dz, filter) self:updatePosition() - local dx, dy = self.ox + dx, self.oy + dy, self.oz + dz - local x, y, z, cols, colNumber = self.world:checkCollision(self, dx, dy, dz, filter) + local dx, dy, dz = self.ox + dx, self.oy + dy, self.oz + dz + local x, y, z, cols, colNumber = self.world:checkCollisionAtPoint(self, dx, dy, dz, filter) local newx, newy, newz = self:getNewOwnerPosition(x, y, z) return newx, newy, newz, cols, colNumber diff --git a/birb/modules/world/actors/utils/sprites.lua b/birb/modules/world/actors/utils/sprites.lua index bc11127..2a1012d 100644 --- a/birb/modules/world/actors/utils/sprites.lua +++ b/birb/modules/world/actors/utils/sprites.lua @@ -17,8 +17,7 @@ end function Sprite:clone() if self.name ~= nil then - local baseSprite = self.assets:getWithType(self.name, "sprite") - self.spriteClone = baseSprite:clone() + self.spriteClone = self.assets.sprites[self.name]:clone() self.spriteClone:setCallbackTarget(self.owner) end end @@ -49,14 +48,16 @@ function Sprite:update(dt) end end -function Sprite:setScalling(sx, sy) - if (sx ~= nil) then - self.sx = sx - end +function Sprite:setScallingX(sx) + local sx = sx or 1 - if (sy ~= nil) then - self.sy = sy - end + self.sx = sx +end + +function Sprite:setScallingY(sy) + local sy = sy or 1 + + self.sy = sy end function Sprite:getCurrentAnimation() @@ -111,10 +112,9 @@ function Sprite:draw(x, y, r, sx, sy, ox, oy, kx, ky) if (self.spriteClone ~= nil) then self.spriteClone:draw(x, y, r, sx, sy, ox, oy, kx, ky) else - local sprite = self.assets:getWithType(self.name, "sprite") - sprite:drawAnimation(x, y, r, sx, sy, ox, oy, kx, ky) + self.assets.sprites[self.name]:draw(x, y, r, sx, sy, ox, oy, kx, ky) end end end -return Sprite +return Sprite \ No newline at end of file diff --git a/birb/modules/world/baseworld.lua b/birb/modules/world/baseworld.lua index b68e6cb..a9374c9 100644 --- a/birb/modules/world/baseworld.lua +++ b/birb/modules/world/baseworld.lua @@ -102,17 +102,23 @@ function BaseWorld:initActors( ) self.currentCreationID = 0 end -function BaseWorld:newActor(name, x, y, z) +function BaseWorld:newActor(name, x, y, z, properties, mapname) local debugstring = " at (" .. x .. ";" .. y .. ")." - core.debug:logInfo("world2D", "adding actor " .. name .. debugstring) - self.obj.index[name](self, x, y) + core.debug:print("world2D", "adding actor " .. name .. debugstring) + local actor = self.obj.index[name](self, x, y) + if (mapname ~= nil) then + actor.mapname = mapname + end + if (properties ~= nil) then + actor:setProperties(properties) + end end function BaseWorld:newCollision(name, x, y, z, w, h, d) local debugstringpos = "at (" .. x .. ";" .. y .. ")" local debugstringsize = "size is (" .. w .. ";" .. h .. ")" local debugstring = " " .. debugstringpos .. ". " .. debugstringsize .. "." - core.debug:logInfo("world2D", "creating collision " .. name .. debugstring) + core.debug:print("world2D", "creating collision " .. name .. debugstring) self.obj.collisions[name](self, x, y, w, h) end @@ -202,7 +208,7 @@ function BaseWorld:moveActor(actor, x, y, filter) return x, y, {}, 0 end -function BaseWorld:checkCollision(actor, x, y, filter) +function BaseWorld:checkCollisionAtPoint(actor, x, y, filter) -- as the baseworld have no collision function, we return empty collision -- datas, but from the same type than bump2D will return return x, y, {}, 0 @@ -252,9 +258,10 @@ function BaseWorld:newPlayer(x, y, z) end function BaseWorld:sendInputToPlayers(actor) - for i, player in ipairs(self.players) do - local keys = self.scene:getKeys(player.sourceid) - player.actor:getInput(keys) + for i,v in ipairs(self.players) do + --TODO: make the player get from a selected source inputs + local keys = self.scene.sources[v.sourceid].keys + v.actor:getInput(keys) end end @@ -351,9 +358,11 @@ end -- All update functions function BaseWorld:update(dt) - self:updateMap(dt) - self:sendInputToPlayers(dt) - self:updateActors(dt) + if (core.screen:isActive()) then + self:updateMap(dt) + self:sendInputToPlayers(dt) + self:updateActors(dt) + end self.cameras:update(dt) end @@ -370,6 +379,19 @@ function BaseWorld:updateMap(dt) end end +function BaseWorld:getTileTypeAtPoint(x, y) + if (self.map.getTileTypeAtPoint ~= nil) then + return self.map:getTileTypeAtPoint(x, y) + end +end + +function BaseWorld:haveTileTypeInRect(x, y, x2, y2, type) + if (self.map.haveTileTypeInRect ~= nil) then + return self.map:haveTileTypeInRect(x, y, x2, y2, type) + end +end + + -- DRAW FUNCTIONS -- All function to draw the map, world and actors @@ -378,13 +400,15 @@ function BaseWorld:draw(dt) local camNumber = self.cameras:getViewNumber() if (camNumber == 0) then - self:drawMap() + self:drawLowerLayers() self:drawActors() + self:drawUpperLayers() else for i=1, camNumber do self.cameras:attachView(i) - self:drawMap(i) + self:drawLowerLayers(i) self:drawActors(i) + self:drawUpperLayers(i) self.cameras:detachView(i) end end @@ -398,6 +422,18 @@ function BaseWorld:drawActors(id) end end +function BaseWorld:drawUpperLayers() + if (self.map ~= nil) then + self.map:drawUpperLayers() + end +end + +function BaseWorld:drawLowerLayers() + if (self.map ~= nil) then + self.map:drawLowerLayers() + end +end + function BaseWorld:drawMap(id) if (self.map ~= nil) then self.map:draw() diff --git a/birb/modules/world/camera/init.lua b/birb/modules/world/camera/init.lua index 7d23816..3044ecf 100644 --- a/birb/modules/world/camera/init.lua +++ b/birb/modules/world/camera/init.lua @@ -50,7 +50,7 @@ end function CameraSystem:setMode(mode) self.mode = mode - core.debug:logInfo("camera", "mode is now set to " .. mode) + core.debug:print("camera", "mode is now set to " .. mode) return mode end @@ -178,15 +178,17 @@ function CameraSystem:attachView(id) self.current_canvas = love.graphics.getCanvas() love.graphics.setCanvas(view.canvas) love.graphics.clear() - + local tx, ty, scale + if id ~= nil then -- Du à la manière dont fonctionne STI, on est obligé de récupérer les info -- de position de camera pour afficher la carte par rapport à ces infos - local tx, ty = self:getViewCoordinate(id) - local scale = self:getViewScale(id) or 1 - tx = math.floor(tx) * -1 - ty = math.floor(ty) * -1 + tx, ty = self:getViewCoordinate(id) + scale = self:getViewScale(id) or 1 + tx = math.floor(tx) * -1 + ty = math.floor(ty) * -1 - local w, h = core.screen:getDimensions() + local w, h = core.screen:getDimensions() + end love.graphics.push() love.graphics.origin() @@ -212,7 +214,6 @@ function CameraSystem:detachView(id) local unscale = 1 / view.scale love.graphics.scale(unscale, unscale) - self:drawHUD(id) love.graphics.pop() end @@ -385,15 +386,4 @@ function CameraSystem:followAllActors(id) end end - --- DRAW FUNCTIONS --- Basic callback to draw stuff - -function CameraSystem:drawHUD(id) - local view = self:getView(id) - local viewx, viewy, vieww, viewh = self:getOnScreenViewCoordinate(id) - - view.target:drawHUD(id, vieww, viewh) -end - return CameraSystem diff --git a/birb/modules/world/maps/init.lua b/birb/modules/world/maps/init.lua index 369bd99..12153c4 100644 --- a/birb/modules/world/maps/init.lua +++ b/birb/modules/world/maps/init.lua @@ -1,7 +1,7 @@ local cwd = (...):gsub('%.init$', '') .. "." local mapObjects = {} -mapObjects.Sti = require(cwd .. "sti") +mapObjects.Sti = require(cwd .. "tiled") mapObjects.Base = require(cwd .. "parent") return mapObjects diff --git a/birb/modules/world/maps/parent.lua b/birb/modules/world/maps/parent.lua index a1b445d..83adae5 100644 --- a/birb/modules/world/maps/parent.lua +++ b/birb/modules/world/maps/parent.lua @@ -11,6 +11,8 @@ function ParentMap:new(world, r, g, b) local b = b or 128 self.backgroundColor = {r, g, b} + self.supportTileCollision = false + self:setPadding() self:register() end @@ -58,6 +60,10 @@ function ParentMap:loadActors() -- Empty Placeholder function end +function ParentMap:getTileTypeAtPoint() + return nil +end + function ParentMap:setBackgroundColor(r, g, b) local r = r or 128 local g = g or 128 @@ -81,6 +87,10 @@ function ParentMap:getDimensions() return core.screen:getDimensions() end +function ParentMap:drawLowerLayers() + self:draw() +end + function ParentMap:getBox() local x1, y1, x2, y2 = self:getPadding() local w, h = self:getDimensions() diff --git a/birb/modules/world/maps/sti.lua b/birb/modules/world/maps/sti.lua deleted file mode 100644 index 7de6837..0000000 --- a/birb/modules/world/maps/sti.lua +++ /dev/null @@ -1,150 +0,0 @@ -local cwd = (...):gsub('%.sti$', '') .. "." - -local Parent = require(cwd .. "parent") -local STI = require(cwd .. "libs.sti") - -local StiMap = Parent:extend() - -function StiMap:new(world, mapfile) - self.sti = STI(mapfile) - StiMap.super.new(self, world) - self:setBackgroundColorFromTable(self.sti.backgroundcolor) -end - -function StiMap:getDimensions() - return self.sti.width * self.sti.tilewidth, - self.sti.height * self.sti.tileheight -end - --- UPDATE FUNCTION --- Update or modify the map - -function StiMap:resize(w, h) - self.sti:resize(w, h) -end - -function StiMap:update(dt) - self.sti:update(dt) -end - --- LOADING FUNCTION --- Load actors directly into the world - -function StiMap:loadCollisions() - for k, objectlayer in pairs(self.sti.layers) do - if self.world:isCollisionIndexed(objectlayer.name) then - local debugstring = "loading " .. #objectlayer.objects .. " objects in " .. objectlayer.name .. " collision layer" - core.debug:logDebug("map/sti", debugstring) - for k, object in pairs(objectlayer.objects) do - self:newCollision(objectlayer, object) - end - self.sti:removeLayer(objectlayer.name) - end - end -end - -function StiMap:loadActors() - for k, objectlayer in pairs(self.sti.layers) do - if self.world:isActorIndexed(objectlayer.name) then - local debugstring = "loading " .. #objectlayer.objects .. " objects in " .. objectlayer.name .. " actor layer" - core.debug:logDebug("map/sti", debugstring) - for k, object in pairs(objectlayer.objects) do - if (object.properties.batchActor) then - self:batchActor(objectlayer, object) - else - self:newActor(objectlayer, object) - end - end - self.sti:removeLayer(objectlayer.name) - end - end -end - -function StiMap:loadPlayers() - for k, objectlayer in pairs(self.sti.layers) do - if (objectlayer.name == "player") then - local debugstring = "loading at most " .. #objectlayer.objects .. " actors in " .. objectlayer.name .. " actor layer" - core.debug:logDebug("map/sti", debugstring) - local i = 1 - for k, object in pairs(objectlayer.objects) do - self:newPlayer(object, i) - i = i + 1 - end - self.sti:removeLayer(objectlayer.name) - end - end -end - -function StiMap:batchActor(objectlayer, object) - local name = objectlayer.name - local gwidth = object.properties.gwidth or self.sti.tilewidth - local gheight = object.properties.gheight or self.sti.tileheight - local x = object.x - local y = object.y - local z = object.properties.z or 0 - local w = object.width - local h = object.height - - local cellHor = math.ceil(w / gwidth) - local cellVert = math.ceil(h / gheight) - - for i=1, cellHor do - for j=1, cellVert do - self.world:newActor(name, x + (i-1)*gwidth, y + (j-1)*gheight, z) - end - end -end - -function StiMap:newActor(objectlayer, object) - local z = object.properties.z or 0 - local adaptPosition = object.properties.adaptPosition or false - - local y = object.y - if (adaptPosition) then - y = y + z - end - - self.world:newActor(objectlayer.name, object.x, y, z) -end - -function StiMap:newCollision(objectlayer, object) - local z = object.properties.z or 0 - local d = object.properties.d or 16 - local fromTop = object.properties.fromTop or false - - local y = object.y - if (fromTop) then - local poschange = z .. ";" .. y .. " => " .. z-d .. ";" .. y+z - core.debug:logDebug("map/sti", "create from top, set z and y: " .. poschange) - y = y + z - z = z - d - end - - self.world:newCollision(objectlayer.name, object.x, y, z, object.width, object.height, d) -end - -function StiMap:newPlayer(object, i) - local z = object.properties.z or 0 - local adaptPosition = object.properties.adaptPosition or false - - local y = object.y - if (adaptPosition) then - core.debug:logDebug("map/sti", "adapting position, set y: " .. y .. " => ", y+z) - y = y + z - end - - self.world:addPlayer(object.x, y, z, i) -end - --- DRAW FUNCTIONS --- Draw the map - -function StiMap:draw() - for _, layer in ipairs(self.sti.layers) do - if layer.visible and layer.opacity > 0 and (layer.type == "tilelayer") then - self.sti:drawLayer(layer) - end - end -end - -return StiMap diff --git a/birb/modules/world/maps/tiled/init.lua b/birb/modules/world/maps/tiled/init.lua new file mode 100644 index 0000000..23dc460 --- /dev/null +++ b/birb/modules/world/maps/tiled/init.lua @@ -0,0 +1,62 @@ +local Parent = require "birb.modules.world.maps.parent" +local TiledMap = Parent:extend() +local StiWrapper = require "birb.modules.world.maps.tiled.stiwrapper" + +local TiledMixins = require "birb.modules.world.maps.tiled.mixins" + +TiledMap:implement(TiledMixins) + +function TiledMap:new(world, mapfile) + self.wrapper = StiWrapper(self, mapfile, 0, 0) + TiledMap.super.new(self, world) + self.supportTileCollision = true + + self:setBackgroundColorFromTable(self.wrapper.sti.backgroundcolor) + self.mapname = self:getMapName(mapfile) +end + +function TiledMap:getMapName(mapfile) + local filepath = utils.string.split(mapfile, "/") + local filenameMap = utils.string.split(filepath[#filepath], ".") + return filepath[#filepath - 1] .. "." .. filenameMap[1] +end + +function TiledMap:getDimensions() + return self.wrapper:getDimensions() +end + +function TiledMap:loadObjects() + --self.wrapper:loadObjects() +end + +-- TILE FUNCTIONS +-- Get tiles + +function TiledMap:haveTileTypeInRect(x, y, w, h, type) + return self.wrapper:haveTileTypeInRect(x, y, w, h, type) +end + +-- UPDATE FUNCTION +-- Update or modify the map + +function TiledMap:resize(w, h) + self.wrapper:resize(w, h) +end + +function TiledMap:update(dt) + self.wrapper:update(dt) +end + +-- DRAW FUNCTIONS +-- Handle drawing the wrapper + + +function TiledMap:drawUpperLayers() + self.wrapper:drawUpperLayers() +end + +function TiledMap:drawLowerLayers() + self.wrapper:drawLowerLayers() +end + +return TiledMap diff --git a/birb/modules/world/maps/libs/sti/graphics.lua b/birb/modules/world/maps/tiled/libs/sti/graphics.lua similarity index 100% rename from birb/modules/world/maps/libs/sti/graphics.lua rename to birb/modules/world/maps/tiled/libs/sti/graphics.lua diff --git a/birb/modules/world/maps/libs/sti/init.lua b/birb/modules/world/maps/tiled/libs/sti/init.lua similarity index 99% rename from birb/modules/world/maps/libs/sti/init.lua rename to birb/modules/world/maps/tiled/libs/sti/init.lua index de1bd16..81a33f6 100644 --- a/birb/modules/world/maps/libs/sti/init.lua +++ b/birb/modules/world/maps/tiled/libs/sti/init.lua @@ -745,10 +745,12 @@ end --- Draw an individual Layer -- @param layer The Layer to draw -function Map.drawLayer(_, layer) +function Map.drawLayer(_, layer, x, y) local r,g,b,a = lg.getColor() lg.setColor(r, g, b, a * layer.opacity) + lg.translate(x, y) layer:draw() + lg.translate(-x, -y) lg.setColor(r,g,b,a) end diff --git a/birb/modules/world/maps/libs/sti/plugins/box2d.lua b/birb/modules/world/maps/tiled/libs/sti/plugins/box2d.lua similarity index 100% rename from birb/modules/world/maps/libs/sti/plugins/box2d.lua rename to birb/modules/world/maps/tiled/libs/sti/plugins/box2d.lua diff --git a/birb/modules/world/maps/libs/sti/plugins/bump.lua b/birb/modules/world/maps/tiled/libs/sti/plugins/bump.lua similarity index 100% rename from birb/modules/world/maps/libs/sti/plugins/bump.lua rename to birb/modules/world/maps/tiled/libs/sti/plugins/bump.lua diff --git a/birb/modules/world/maps/libs/sti/utils.lua b/birb/modules/world/maps/tiled/libs/sti/utils.lua similarity index 100% rename from birb/modules/world/maps/libs/sti/utils.lua rename to birb/modules/world/maps/tiled/libs/sti/utils.lua diff --git a/birb/modules/world/maps/tiled/mixins.lua b/birb/modules/world/maps/tiled/mixins.lua new file mode 100644 index 0000000..a809931 --- /dev/null +++ b/birb/modules/world/maps/tiled/mixins.lua @@ -0,0 +1,81 @@ +local TiledMixins = Object:extend() + +-- ACTOR ADDING FUNCTIONS +-- Add actor related to the map + +function TiledMixins:batchActor(objectlayer, object, layerx, layery) + local name = objectlayer.name + local gwidth = object.properties.gwidth or self.wrapper.sti.tilewidth + local gheight = object.properties.gheight or self.wrapper.sti.tileheight + local x = object.x + layerx + local y = object.y + layery + local z = object.properties.z or 0 + local w = object.width + local h = object.height + + local cellHor = math.ceil(w / gwidth) + local cellVert = math.ceil(h / gheight) + + for i = 1, cellHor do + for j = 1, cellVert do + self.world:newActor(name, x + (i - 1) * gwidth, y + (j - 1) * gheight, z, object.properties) + end + end +end + +function TiledMixins:newActor(objectlayer, object, layerx, layery) + local z = object.properties.z or 0 + local adaptPosition = object.properties.adaptPosition or false + + local x = object.x + layerx + local y = object.y + layery + if (adaptPosition) then + y = y + z + end + + self.world:newActor(objectlayer.name, x, y, z, object.properties, self.mapname) +end + +function TiledMixins:newCollision(objectlayer, object, layerx, layery) + local z = object.properties.z or 0 + local d = object.properties.d or 16 + local fromTop = object.properties.fromTop or false + local x = object.x + layerx + local y = object.y + layery + if (fromTop) then + local poschange = z .. ";" .. y .. " => " .. z - d .. ";" .. y + z + core.debug:print("map/sti", "create from top, set z and y: " .. poschange) + y = y + z + z = z - d + end + + self.world:newCollision(objectlayer.name, x, y, z, object.width, object.height, d) +end + +function TiledMixins:newPlayer(object, i, layerx, layery) + local z = object.properties.z or 0 + local adaptPosition = object.properties.adaptPosition or false + + local x = object.x + layerx + + local y = object.y + layery + if (adaptPosition) then + core.debug:print("map/sti", "adapting position, set y: " .. y .. " => ", y + z) + y = y + z + end + + self.world:addPlayer(x, y, z, i) +end + +-- INDEXATION FUNCTIONS +-- Verify if something is indexed + +function TiledMixins:isCollisionIndexed(name) + return self.world:isCollisionIndexed(name) +end + +function TiledMixins:isActorIndexed(name) + return self.world:isActorIndexed(name) +end + +return TiledMixins diff --git a/birb/modules/world/maps/tiled/stiwrapper.lua b/birb/modules/world/maps/tiled/stiwrapper.lua new file mode 100644 index 0000000..a6ae593 --- /dev/null +++ b/birb/modules/world/maps/tiled/stiwrapper.lua @@ -0,0 +1,246 @@ +local StiWrapper = Object:extend() +local STI = require "birb.modules.world.maps.tiled.libs.sti" + +function StiWrapper:new(owner, mapfile, x, y, canLoadPlayer) + self.sti = STI(mapfile) + self.owner = owner + self.x = x or 0 + self.y = y or 0 + self.canLoadPlayer = (canLoadPlayer ~= false) + + self.objectlayer = 0 + self.isLoaded = false +end + +function StiWrapper:getRect() + local w, h = self:getDimensions() + return self.x, self.y, w, h +end + +function StiWrapper:getDimensions() + return self.sti.width * self.sti.tilewidth, self.sti.height * self.sti.tileheight +end + +-- UPDATE FUNCTION +-- Update or modify the map + +function StiWrapper:resize(w, h) + self.sti:resize(w, h) +end + +function StiWrapper:update(dt) + self:lazyLoad() + self.sti:update(dt) +end + +-- OBJECT FUNCTIONS +-- Handle objets + +function StiWrapper:lazyLoad() + if (not self.isLoaded) then + self:loadObjects() + self.isLoaded = true + end +end + +function StiWrapper:loadObjects() + self:loadCollisions() + self:loadPlayers() + self:loadActors() + self.objectlayer = self:getObjectLayer() +end + +function StiWrapper:loadCollisions() + for _, objectlayer in pairs(self.sti.layers) do + if self.owner:isCollisionIndexed(objectlayer.name) then + local debugstring = + "loading " .. #objectlayer.objects .. " objects in " .. objectlayer.name .. " collision layer" + core.debug:print("map/sti", debugstring) + for _, object in pairs(objectlayer.objects) do + self.owner:newCollision(objectlayer, object, self.x, self.y) + end + self.sti:removeLayer(objectlayer.name) + end + end +end + +function StiWrapper:loadActors() + for k, objectlayer in pairs(self.sti.layers) do + if self.owner:isActorIndexed(objectlayer.name) then + local debugstring = + "loading " .. #objectlayer.objects .. " objects in " .. objectlayer.name .. " actor layer" + core.debug:print("map/sti", debugstring) + for k, object in pairs(objectlayer.objects) do + if (object.properties.batchActor) then + self.owner:batchActor(objectlayer, object, self.x, self.y) + else + self.owner:newActor(objectlayer, object, self.x, self.y) + end + end + self.sti:removeLayer(objectlayer.name) + end + end +end + +function StiWrapper:loadPlayers() + for k, objectlayer in pairs(self.sti.layers) do + if (objectlayer.name == "player") then + if (self.canLoadPlayer) then + local debugstring = + "loading at most " .. #objectlayer.objects .. " actors in " .. objectlayer.name .. " actor layer" + core.debug:print("map/sti", debugstring) + local i = 1 + for k, object in pairs(objectlayer.objects) do + self.owner:newPlayer(object, i, self.x, self.y) + i = i + 1 + end + end + self.sti:removeLayer(objectlayer.name) + end + end +end + +function StiWrapper:getObjectLayer() + local objectlayer = 0 + for i, layer in ipairs(self.sti.layers) do + if (layer.name == "objects") then + objectlayer = i + end + self.nbrLayer = i + end + return objectlayer +end + +-- TILE FUNCTIONS +-- Handle tiles + +function StiWrapper:haveTileTypeInRect(x, y, w, h, type) + local x1, y1, x2, y2 = self:getTileRectangle(x, y, x + w, y + h) + local isSolid = false + for i = x1, x2, 1 do + for j = y1, y2, 1 do + if (self:getTileTypeAtCoord(i, j) == type) then + isSolid = true + end + end + end + return isSolid +end + +function StiWrapper:getTileRectangle(x, y, x2, y2) + local xx, yy = self:convertPixelToTile(x, y) + local xx2, yy2 = self:convertPixelToTile(x2, y2) + return xx, yy, xx2, yy2 +end + +function StiWrapper:getTileTypeAtPoint(x, y) + local xx, yy = self:convertPixelToTile(x, y) + return self:getTileTypeAtCoord(xx, yy) +end + +function StiWrapper:haveUpperLayerAtCoord(x, y) + local xx, yy = self:convertPixelToTile(x, y) + local haveLayer = false + if (self.objectlayer > 0) then + for i = self.objectlayer, self.nbrLayer, 1 do + local layer = self.sti.layers[i] + if layer.visible and layer.opacity > 0 and (layer.type == "tilelayer") then + local _, tileid = self:getTileId(layer.name, xx, yy) + if (tileid > 0) then + haveLayer = true + end + end + end + end + return haveLayer +end + +function StiWrapper:getTileTypeAtCoord(x, y) + local canSearch = true + local currentType = nil + for _, layer in ipairs(self.sti.layers) do + if (canSearch) then + if (layer.type == "tilelayer") then + local tileset, tileid = self:getTileId(layer.name, x, y) + local type = self:getTileType(tileset, tileid) + if (type ~= nil) then + currentType = type + end + else + if (layer.name == "objects") then + canSearch = false + end + end + end + end + return currentType +end + +function StiWrapper:convertPixelToTile(x, y) + local xx, yy = self.sti:convertPixelToTile(x - self.x, y - self.y) + return math.ceil(xx), math.ceil(yy) +end + +function StiWrapper:getTileType(tileset, id) + local tilesetData = self.sti.tilesets[tileset] + if ((tileset == -1) or (id == -1)) then + return nil + end + + if (tilesetData ~= nil) then + for i, tile in ipairs(tilesetData.tiles) do + if (tile.id == id) and (tile.type ~= nil) then + return tile.type + end + end + end + return "non-solid" +end + +function StiWrapper:getTileId(layer, x, y) + local line = self.sti.layers[layer].data[y] + if (line ~= nil) then + local tile = line[x] + if not tile then + return -1, -1 + end + return tile.tileset, tile.id + end + return -1, -1 +end + +-- DRAW FUNCTIONS +-- Draw the map + +function StiWrapper:drawUpperLayers() + self:lazyLoad() + if (self.objectlayer > 0) then + for i = self.objectlayer, self.nbrLayer, 1 do + self:drawLayer(i) + end + end +end + +function StiWrapper:drawLowerLayers() + self:lazyLoad() + if (self.objectlayer > 0) then + for i = 1, self.objectlayer, 1 do + self:drawLayer(i) + end + else + for i = 1, self.nbrLayer, 1 do + self:drawLayer(i) + end + end +end + +function StiWrapper:drawLayer(id) + local layer = self.sti.layers[id] + if (layer ~= nil) then + if layer.visible and layer.opacity > 0 and (layer.type == "tilelayer") then + self.sti:drawLayer(layer, self.x, self.y) + end + end +end + +return StiWrapper diff --git a/birb/modules/world/world2D.lua b/birb/modules/world/world2D.lua index 11417ef..6a34d2b 100644 --- a/birb/modules/world/world2D.lua +++ b/birb/modules/world/world2D.lua @@ -27,7 +27,6 @@ local BaseWorld = require(cwd .. "baseworld") local World2D = BaseWorld:extend() local Bump = require(cwd .. "libs.bump") -local CameraSystem = require(cwd .. "camera") function World2D:new(scene, actorlist, mapfile, maptype) World2D.super.new(self, scene, actorlist, mapfile, maptype) @@ -78,7 +77,7 @@ function World2D:removeBody(body) return self.bodies:remove(body) end -function World2D:checkCollision(body, x, y, filter) +function World2D:checkCollisionAtPoint(body, x, y, filter) return self.bodies:check(body, x, y, filter) end diff --git a/birb/modules/world/world3D.lua b/birb/modules/world/world3D.lua index e104123..42ee40b 100644 --- a/birb/modules/world/world3D.lua +++ b/birb/modules/world/world3D.lua @@ -108,7 +108,7 @@ function World3D:removeBody(body) return self.bodies:remove(body) end -function World3D:checkCollision(body, x, y, z, filter) +function World3D:checkCollisionAtPoint(body, x, y, z, filter) return self.bodies:check(body, x, y, z, filter) end @@ -183,7 +183,7 @@ end -- Functions to draw the world function World3D:zSortItems(items) - -- zSorting algorithm taken from bump3D example, adapted to birb. + -- zSorting algorithm taken from bump3D example, adapted to gamecore. local graph = Tsort.new() local noOverlap = {} @@ -202,17 +202,19 @@ function World3D:zSortItems(items) end local _, aY, aZ, _, aH, aD = self.bodies:getCube(itemA.mainHitbox) - local aDepth = itemA.depth - local aID = itemA.creationID - local aType = itemA.type + local aDepth, aID, aType + aDepth = itemA.depth + aID = itemA.creationID + aType = itemA.type aZ = math.ceil(aZ) aY = math.ceil(aY) for _, itemB in ipairs(overlapping) do local _, bY, bZ, _, bH, bD = self.bodies:getCube(itemB.mainHitbox) - local bDepth = itemB.depth - local bID = itemB.creationID - local bType = itemB.type + local bDepth, bID, bType + bDepth = itemB.depth + bID = itemB.creationID + bType = itemB.type bZ = math.ceil(bZ) bY = math.ceil(bY) diff --git a/birb/structures/box.lua b/birb/structures/box.lua new file mode 100644 index 0000000..572ae5d --- /dev/null +++ b/birb/structures/box.lua @@ -0,0 +1 @@ +return {"x", "y", "z", "w", "h", "d"} \ No newline at end of file diff --git a/birb/structures/elementData.lua b/birb/structures/elementData.lua new file mode 100644 index 0000000..63eff97 --- /dev/null +++ b/birb/structures/elementData.lua @@ -0,0 +1 @@ +return {"element", "delay", "depth", "focus", "keypress"} \ No newline at end of file diff --git a/birb/structures/hitbox.lua b/birb/structures/hitbox.lua new file mode 100644 index 0000000..21aad41 --- /dev/null +++ b/birb/structures/hitbox.lua @@ -0,0 +1 @@ +return {"type", "box", "isSolid"} \ No newline at end of file diff --git a/birb/structures/rect.lua b/birb/structures/rect.lua new file mode 100644 index 0000000..85032be --- /dev/null +++ b/birb/structures/rect.lua @@ -0,0 +1 @@ +return {"x", "y", "w", "h"} \ No newline at end of file diff --git a/birb/structures/tween.lua b/birb/structures/tween.lua new file mode 100644 index 0000000..cbc6147 --- /dev/null +++ b/birb/structures/tween.lua @@ -0,0 +1,6 @@ +return { + tween = {"name", "type", "start", "duration", "target", "easing"}, + movement = {"name", "type", "start", "duration", "x", "y", "easing"}, + switch = {"name", "type", "start", "bools"}, + delayFocus = {"name", "type", "start"}, +} \ No newline at end of file diff --git a/birb/utils/bools.lua b/birb/utils/bools.lua new file mode 100644 index 0000000..2f43829 --- /dev/null +++ b/birb/utils/bools.lua @@ -0,0 +1,15 @@ +local Bools = {} + +function Bools.either(bool, val1, val2) + if (bool) then + return val1 + else + return val2 + end +end + +function Bools.toString(bool) + return Bools.either(bool, "true", "false") +end + +return Bools diff --git a/birb/utils/datas.lua b/birb/utils/datas.lua new file mode 100644 index 0000000..c2d410a --- /dev/null +++ b/birb/utils/datas.lua @@ -0,0 +1,142 @@ +--- loveutils.datas : simple functions for data manipulation. + +--[[ + Copyright © 2021 Kazhnuz + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +]] + +local DataUtils = {} + +local DATADIR = "datas" +local GAMEDATADIR = "gamedata" + +--- Verify if a name correspond to a lua file +---@param name string the filename you want to test +---@return boolean isLua if the filename finish by .lua +function DataUtils.isLuaFile(name) + local extension = name:sub(#name - 3, #name) + return (extension == ".lua") +end + +--- Transform a lua filename to a module name +---@param luaFile string the filename you want to transform +---@return boolean moduleName the module name +function DataUtils.luaFileToModule(luaFile) + if (DataUtils.isLuaFile(luaFile)) then + return luaFile:sub(1, #luaFile - 4) + else + return luaFile + end +end + +--- Transform a list of lua filename to a list of module name +---@param luaFileList table the filename list you want to transform +---@return table moduleList the module name list +function DataUtils.luaFileListToModuleList(luaFileList) + local moduleList = {} + for i,luaFile in ipairs(luaFileList) do + table.insert(moduleList, DataUtils.luaFileToModule(luaFile)) + end + return moduleList +end + +--- Use "require" on a a composited filename +---@param parent string the parent filename +---@param filename string the filename of the file +---@return any data the content of the lua file +function DataUtils.require(parent, filename) + return require(DataUtils.concatFolder(parent, filename, true)) +end + +--- Require and copy the content of a lua file +--- It's mostly used for lua file containing data, for not having to copy their data +---@param filepath string the filepath of the file +---@return table data the copied content of the lua file +function DataUtils.copy(filepath) + local orig = require(filepath) + local orig_type = type(orig) + local copy + if orig_type == 'table' then + copy = {} + for orig_key, orig_value in pairs(orig) do + copy[orig_key] = orig_value + end + else -- number, string, boolean, etc + copy = orig + end + return copy +end + + +--- Require and copy the content of a lua file from it's parent folder +--- It's mostly used for lua file containing data, for not having to copy their data +---@param parent string the path of the parent +---@param filename string the filename of the file +---@return table data the copied content of the lua file +function DataUtils.copyDataset(parent, filename) + local orig = DataUtils.require(parent, filename) + local orig_type = type(orig) + local copy + if orig_type == 'table' then + copy = {} + for orig_key, orig_value in pairs(orig) do + copy[orig_key] = orig_value + end + else -- number, string, boolean, etc + copy = orig + end + return copy +end + +--- Get a data directory path from the gamedata dir +---@param folder string the folder name +---@param lua boolean if we are dealing with lua modules +---@return string path the data directory path +function DataUtils.concatDataFolder(folder, lua) + return DataUtils.concatFolder(DataUtils.getGameDataDir(lua), folder, lua) +end + +--- Get the game data directory +---@param lua boolean if we are dealing with lua modules +---@return string path the gamedirectory path +function DataUtils.getGameDataDir(lua) + return DataUtils.concatFolder(DATADIR, GAMEDATADIR, lua) +end + +--- Concat a folder path +---@param parent string the path of the parent folder +---@param filename string the name of the element you want to concat to the path +---@param lua boolean if we are dealing with lua modules +---@return string path the path +function DataUtils.concatFolder(parent, filename, lua) + return parent .. DataUtils.sep(lua) .. filename +end + +--- Return the separater character for lua modules or filesystem pathname +---@param lua boolean if we are dealing with lua modules +---@return string sep the separator +function DataUtils.sep(lua) + if (lua) then + return "." + else + return "/" + end +end + +return DataUtils diff --git a/birb/utils/enum.lua b/birb/utils/enum.lua new file mode 100644 index 0000000..a9b136e --- /dev/null +++ b/birb/utils/enum.lua @@ -0,0 +1,9 @@ +return function(tbl) + local length = #tbl + for i = 1, length do + local v = tbl[i] + tbl[v] = i + end + + return tbl +end \ No newline at end of file diff --git a/birb/utils/graphics.lua b/birb/utils/graphics.lua index 3587a38..826b5e3 100644 --- a/birb/utils/graphics.lua +++ b/birb/utils/graphics.lua @@ -27,6 +27,22 @@ local Graphics = {} -- COLOR FUNCTIONS -- Handle colors and scene colors +function Graphics.setColorHSV(h, s, v) + if s <= 0 then return v,v,v end + h, s, v = h*6, s, v + local c = v*s + local x = (1-math.abs((h%2)-1))*c + local m,r,g,b = (v-c), 0,0,0 + if h < 1 then r,g,b = c,x,0 + elseif h < 2 then r,g,b = x,c,0 + elseif h < 3 then r,g,b = 0,c,x + elseif h < 4 then r,g,b = 0,x,c + elseif h < 5 then r,g,b = x,0,c + else r,g,b = c,0,x + end + love.graphics.setColor((r+m),(g+m),(b+m),1) +end + function Graphics.resetColor() love.graphics.setColor(1,1,1,1) end @@ -75,37 +91,6 @@ function Graphics.printWithSpacing(text, spacing, align, x, y, r, sx, sy, ox, oy end end --- FILTER FUNCTIONS --- Basic filters to a drawable - -function Graphics.drawShadow(drawable, x, y, r, sx, sy, ox, oy, kx, ky) - local color = love.graphics.getColor() - love.graphics.setColor(0, 0, 0, 0) - love.graphics.draw(drawable, x+1, y+1, r, sx, sy, ox, oy, kx, ky) - love.graphics.setColor(color) - - love.graphics.draw(drawable, x, y, r, sx, sy, ox, oy, kx, ky) -end - -function Graphics.drawBorder(drawable, border, x, y, r, sx, sy, ox, oy, kx, ky) - local color = love.graphics.getColor() - local b = border or 1 - love.graphics.setColor(0, 0, 0, 0) - love.graphics.draw(drawable, x-b, y-b, r, sx, sy, ox, oy, kx, ky) - love.graphics.draw(drawable, x , y-b, r, sx, sy, ox, oy, kx, ky) - love.graphics.draw(drawable, x+b, y-b, r, sx, sy, ox, oy, kx, ky) - - love.graphics.draw(drawable, x+b, y , r, sx, sy, ox, oy, kx, ky) - love.graphics.draw(drawable, x-b, y , r, sx, sy, ox, oy, kx, ky) - - love.graphics.draw(drawable, x-b, y+b, r, sx, sy, ox, oy, kx, ky) - love.graphics.draw(drawable, x , y+b, r, sx, sy, ox, oy, kx, ky) - love.graphics.draw(drawable, x+b, y+b, r, sx, sy, ox, oy, kx, ky) - love.graphics.setColor(color) - - love.graphics.draw(drawable, x, y, r, sx, sy, ox, oy, kx, ky) -end - -- PLACEHOLDER GRAPHICS FUNCTIONS -- Ready-to-use placeolder and stuff @@ -116,7 +101,6 @@ function Graphics.box(x, y, w, h) local h = math.floor(h) local r, g, b, a = love.graphics.getColor( ) - a = a or 1 love.graphics.setColor(r, g, b, 0.3 * a) love.graphics.rectangle("fill", x, y, w, h) diff --git a/birb/utils/init.lua b/birb/utils/init.lua index 54c4dc0..4e7ee8f 100644 --- a/birb/utils/init.lua +++ b/birb/utils/init.lua @@ -1,4 +1,4 @@ --- loveutils : a set of basic functions and utility for love2D. +--- loveutils : a set of basic functions and utility for love2D. --[[ Copyright © 2019 Kazhnuz @@ -25,8 +25,11 @@ local cwd = (...):gsub('%.init$', '') .. "." -- load the different elements from loveutils return { - math = require(cwd .. "math"), - graphics = require(cwd .. "graphics"), - filesystem = require(cwd .. "filesystem"), - table = require(cwd .. "table") + math = require "birb.utils.math", + graphics = require "birb.utils.graphics", + filesystem = require "birb.utils.filesystem", + table = require "birb.utils.table", + string = require "birb.utils.string", + time = require "birb.utils.time", + datas = require "birb.utils.datas" } diff --git a/birb/utils/math.lua b/birb/utils/math.lua index 3120360..84aeeaa 100644 --- a/birb/utils/math.lua +++ b/birb/utils/math.lua @@ -1,4 +1,4 @@ --- loveutils.math : easy to use functions for mathematics and geometry. +--- loveutils.math : easy to use functions for mathematics and geometry. --[[ Copyright © 2019 Kazhnuz @@ -56,13 +56,24 @@ function Math.between(num, value1, value2) return math.min(math.max(num, min), max) end -function Math.wrapAndLimit(num, min, max) - if (num < min) then - num = max - elseif (num > max) then - num = min +function Math.either(bool, val1, val2) + if (bool) then + return val1 + else + return val2 end - return num +end + +function Math.wrap(val, min, max) + while (val < min) do + local diff = ((min-1) - val) + val = max - diff + end + while (val > max) do + local diff = ((max+1) - val) + val = min + diff + end + return val end -- VECTOR/DIRECTION functions @@ -96,19 +107,28 @@ function Math.pointDistance(x1, y1, x2, y2) vecy = math.max(y1, y2) - math.min(y1, y2) return math.sqrt(vecx^2 + vecy^2) + end function Math.pointDirection(x1,y1,x2,y2) local vecx, vecy, angle vecy = y2 - y1 vecx = x2 - x1 - angle = math.atan2(vecy, vecx) + -- We disable diagnostic to this line as we use LuaJIT 2.0 + ---@diagnostic disable-next-line: deprecated + angle = math.atan2(-vecy, vecx) return angle end +function Math.lengthdir(lenght, dir) + local x = math.cos(dir) * lenght + local y = -math.sin(dir) * lenght + return x, y +end + -- 3D MATH FUNCTIONS --- Basic math calculations +-- Basic math calculations for 3D function Math.getMiddlePoint3D(x1, y1, z1, x2, y2, z2) local newx, newy, newz, vecx, vecy, vecz @@ -142,12 +162,11 @@ function Math.numberToString(x, length) local length = length or 1 local string = "" local x = x - if (x >= math.pow(10, length)) then - x = length*10 - 1 + if (x >= (10 ^ length)) then string = string .. x else for i=1, (length-1) do - if (x < math.pow(10, length-i)) then + if (x < (10 ^ (length-i))) then string = string .. "0" end end diff --git a/birb/utils/string.lua b/birb/utils/string.lua new file mode 100644 index 0000000..68eca05 --- /dev/null +++ b/birb/utils/string.lua @@ -0,0 +1,26 @@ +local String = {} + +function String.isEmpty(pString) + return (pString == "" or pString == nil) +end + +function String.split(pString, pPattern) + local Table = {} -- NOTE: use {n = 0} in Lua-5.0 + local fpat = "(.-)" .. pPattern + local last_end = 1 + local s, e, cap = pString:find(fpat, 1) + while s do + if s ~= 1 or cap ~= "" then + table.insert(Table,cap) + end + last_end = e+1 + s, e, cap = pString:find(fpat, last_end) + end + if last_end <= #pString then + cap = pString:sub(last_end) + table.insert(Table, cap) + end + return Table +end + +return String \ No newline at end of file diff --git a/birb/utils/table.lua b/birb/utils/table.lua index 46cd624..ce08309 100644 --- a/birb/utils/table.lua +++ b/birb/utils/table.lua @@ -1,8 +1,7 @@ -- loveutils.table : simple functions for table manipulation and computation. --- TODO: could be a part of loveutils.math ? --[[ - Copyright © 2019 Kazhnuz + Copyright © 2021 Kazhnuz 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 @@ -23,7 +22,82 @@ ]] local Table = {} +local Bools = require "birb.utils.bools" +--- Get the sum of a liste of number +---@param table table the table which you want to find if it contain the content +---@param content any the content that you want to find in the table +---@return boolean contain if the table contain the content +function Table.contain(table, content) + for k, v in ipairs(table) do + if (v == content) then + return true + end + end + return false +end + +--- Get the table in form of a string +---@param table table the table which you want to transform into a string +---@return string string the string created from the table +function Table.toString(table, depth) + depth = depth or 2 + local string = "{" + for key, value in pairs(table) do + if (type(value) ~= "userdata" and depth > 0) then + if (type(value) == "table") then + if (value.is ~= nil) then + string = string .. "Object" + end + string = string .. Table.toString(value, depth - 1) + elseif (type(value) == "boolean") then + string = string .. Bools.toString(value) + else + string = string .. value + end + string = string .. "," + end + end + return string .. "}" +end + +--- Clone a table +---@param table1 table the table to clone +---@return table returnTable the cloned table +function Table.clone(table1) + local returnTable = {} + for key, value in pairs(table1) do + returnTable[key] = value + end + return returnTable +end + +--- Merge two list +---@param table1 table the first list to merge +---@param table2 table the list that you want to merge to the first +---@return table table1 the first list, merged with the second +function Table.mergeList(table1, table2) + for i, value in ipairs(table2) do + table.insert(table1, value) + end + return table1 +end + +--- Merge two table +---@param table1 table the first table to merge +---@param table2 table the table that you want to merge to the first +---@return table table1 the first table, merged with the second +function Table.merge(table1, table2) + for key, value in pairs(table2) do + table1[key] = value + end + return table1 +end + +--- Reduce a list with a function +---@param list table the list you want to reduce +---@param fn function a function to apply to the whole list. Args: the first reduced list & the current value +---@return any acc the result of the reducing function Table.reduce(list, fn) local acc for k, v in ipairs(list) do @@ -36,6 +110,9 @@ function Table.reduce(list, fn) return acc end +--- Get the sum of a liste of number +---@param table table the list to parse into an sum +---@return number sum the sum of the table function Table.sum(table) local sum = 0 for _, v in pairs(table) do @@ -45,8 +122,57 @@ function Table.sum(table) return sum end +--- Get the average of a liste of number +---@param table table the list to parse into an average +---@return number average the average of the table function Table.average(table) return Table.sum(table) / #table end +--- Parse a basic list into a structured table. Return an error if the number of arguments is not the same +---@param table table the list to parse into a table +---@param structure table the structure to create the table : each name correspond to an attribute of the parsed table +---@param nullableNbr integer the number of nullable argument (at the end of the functions) (can be null) +---@return table parsedTable the parsed table +function Table.parse(table, structure, nullableNbr) + local parsedTable = {} + assert(table ~= nil, "The table to parse can't be null") + assert(structure ~= nil, "The table structure can't be null") + nullableNbr = nullableNbr or 0 + + if ((#table) > (#structure)) or ((#table) < (#structure - nullableNbr)) then + error("The table to parse " .. Table.toString(table) .. + " doesn't have the right number of arguments: " .. #table .. + " instead of " .. #structure .. + " and " .. nullableNbr .. " nullables") + else + for i, key in ipairs(structure) do + parsedTable[key] = table[i] + end + end + + return parsedTable +end + +function Table.remove(table, funcDelete) + -- Code from https://stackoverflow.com/questions/12394841/safely-remove-items-from-an-array-table-while-iterating + local j, n = 1, #table; + + for i=1,n do + if (not funcDelete(table[i], i, j)) then + -- Move i's kept value to j's position, if it's not already there. + if (i ~= j) then + table[j] = table[i]; + table[i] = nil; + end + -- Increment position of where we'll place the next kept value. + j = j + 1; + else + table[i] = nil; + end + end + + return table; +end + return Table diff --git a/birb/utils/time.lua b/birb/utils/time.lua new file mode 100644 index 0000000..1134176 --- /dev/null +++ b/birb/utils/time.lua @@ -0,0 +1,28 @@ +local Math = require "birb.utils.math" + +Time = {} + +Time.HOURS = 3600 +Time.MINUTES = 60 +Time.SEPARATOR = ":" + +function Time.timestamp(hour, minute, seconds) + return (hour * Time.HOURS) + (minute * Time.MINUTES) + seconds +end + +function Time.getFields(timestamp) + local hours = math.floor(timestamp / Time.HOURS) + local minutes = math.floor((timestamp % Time.HOURS) / Time.MINUTES) + local seconds = math.floor((timestamp % Time.MINUTES)) + return hours, minutes, seconds +end + +function Time.toString(timestamp) + local hours, minutes, seconds = Time.getFields(timestamp) + local str = Math.numberToString(hours, 2) + str = str .. Time.SEPARATOR .. Math.numberToString(minutes, 2) + str = str .. Time.SEPARATOR .. Math.numberToString(seconds, 2) + return str +end + +return Time \ No newline at end of file diff --git a/debug.sh b/debug.sh new file mode 100755 index 0000000..8231d84 --- /dev/null +++ b/debug.sh @@ -0,0 +1 @@ +love ./examples DEBUGLEVEL=4 \ No newline at end of file diff --git a/examples/conf.lua b/examples/conf.lua index 10f282c..d7b88cb 100644 --- a/examples/conf.lua +++ b/examples/conf.lua @@ -1,47 +1,47 @@ function love.conf(t) - t.identity = "city.kobold.Birb" -- The name of the save directory (string) - t.version = "11.1" -- The LÖVE version this game was made for (string) - t.console = false -- Attach a console (boolean, Windows only) - t.accelerometerjoystick = false -- Enable the accelerometer on iOS and Android by exposing it as a Joystick (boolean) - t.gammacorrect = false -- Enable gamma-correct rendering, when supported by the system (boolean) - t.debugLevel = 4 -- Debug level mode : 0=Error only, 3=Everything. + t.identity = "city.kobold.Birb" -- The name of the save directory (string) + t.version = "11.1" -- The LÖVE version this game was made for (string) + t.console = false -- Attach a console (boolean, Windows only) + t.accelerometerjoystick = false -- Enable the accelerometer on iOS and Android by exposing it as a Joystick (boolean) + t.gammacorrect = false -- Enable gamma-correct rendering, when supported by the system (boolean) + t.gameversion = "0.7.0" -- The game version (different than love2D version) - t.window.title = "Birb Engine Examples" -- The window title (string) - t.window.icon = nil -- Filepath to an image to use as the window's icon (string) - t.window.width = 424 -- The window internal width (number) - t.window.height = 240 -- The window internal height (number) - t.window.borderless = false -- Remove all border visuals from the window (boolean) - t.window.resizable = false -- Let the window be user-resizable (boolean) - t.window.minwidth = 1 -- Minimum window width if the window is resizable (number) - t.window.minheight = 1 -- Minimum window height if the window is resizable (number) - t.window.fullscreen = false -- Enable fullscreen (boolean) + t.window.title = "Birb Examples" -- The window title (string) + t.window.icon = nil -- Filepath to an image to use as the window's icon (string) + t.window.width = 424 -- The window internal width (number) + t.window.height = 240 -- The window internal height (number) + t.window.borderless = false -- Remove all border visuals from the window (boolean) + t.window.resizable = false -- Let the window be user-resizable (boolean) + t.window.minwidth = 1 -- Minimum window width if the window is resizable (number) + t.window.minheight = 1 -- Minimum window height if the window is resizable (number) + t.window.fullscreen = false -- Enable fullscreen (boolean) t.window.fullscreentype = "exclusive" -- Choose between "desktop" fullscreen or "exclusive" fullscreen mode (string) - t.window.vsync = true -- Enable vertical sync (boolean) - t.window.msaa = 0 -- The number of samples to use with multi-sampled antialiasing (number) - t.window.display = 1 -- Index of the monitor to show the window in (number) - t.window.highdpi = false -- Enable high-dpi mode for the window on a Retina display (boolean) - t.window.x = nil -- The x-coordinate of the window's position in the specified display (number) - t.window.y = nil -- The y-coordinate of the window's position in the specified display (number) - t.window.resolution = 2 -- The default resolution + t.window.vsync = true -- Enable vertical sync (boolean) + t.window.msaa = 0 -- The number of samples to use with multi-sampled antialiasing (number) + t.window.display = 1 -- Index of the monitor to show the window in (number) + t.window.highdpi = false -- Enable high-dpi mode for the window on a Retina display (boolean) + t.window.x = nil -- The x-coordinate of the window's position in the specified display (number) + t.window.y = nil -- The y-coordinate of the window's position in the specified display (number) + t.window.resolution = 2 -- The default resolution t.volume = {} t.volume.music = 100 -- music audio volume t.volume.sfx = 100 -- sfx audio volume - t.modules.audio = true -- Enable the audio module (boolean) - t.modules.event = true -- Enable the event module (boolean) - t.modules.graphics = true -- Enable the graphics module (boolean) - t.modules.image = true -- Enable the image module (boolean) - t.modules.joystick = true -- Enable the joystick module (boolean) - t.modules.keyboard = true -- Enable the keyboard module (boolean) - t.modules.math = true -- Enable the math module (boolean) - t.modules.mouse = true -- Enable the mouse module (boolean) - t.modules.physics = true -- Enable the physics module (boolean) - t.modules.sound = true -- Enable the sound module (boolean) - t.modules.system = true -- Enable the system module (boolean) - t.modules.timer = true -- Enable the timer module (boolean), Disabling it will result 0 delta time in love.update - t.modules.touch = true -- Enable the touch module (boolean) - t.modules.video = true -- Enable the video module (boolean) - t.modules.window = true -- Enable the window module (boolean) - t.modules.thread = true -- Enable the thread module (boolean) + t.modules.audio = true -- Enable the audio module (boolean) + t.modules.event = true -- Enable the event module (boolean) + t.modules.graphics = true -- Enable the graphics module (boolean) + t.modules.image = true -- Enable the image module (boolean) + t.modules.joystick = true -- Enable the joystick module (boolean) + t.modules.keyboard = true -- Enable the keyboard module (boolean) + t.modules.math = true -- Enable the math module (boolean) + t.modules.mouse = true -- Enable the mouse module (boolean) + t.modules.physics = true -- Enable the physics module (boolean) + t.modules.sound = true -- Enable the sound module (boolean) + t.modules.system = true -- Enable the system module (boolean) + t.modules.timer = true -- Enable the timer module (boolean), Disabling it will result 0 delta time in love.update + t.modules.touch = true -- Enable the touch module (boolean) + t.modules.video = true -- Enable the video module (boolean) + t.modules.window = true -- Enable the window module (boolean) + t.modules.thread = true -- Enable the thread module (boolean) end diff --git a/examples/datas/gamedata/index.lua b/examples/datas/gamedata/index.lua new file mode 100644 index 0000000..3941af5 --- /dev/null +++ b/examples/datas/gamedata/index.lua @@ -0,0 +1 @@ +return {} \ No newline at end of file diff --git a/examples/game/init.lua b/examples/game/init.lua index 27835df..aba2b14 100644 --- a/examples/game/init.lua +++ b/examples/game/init.lua @@ -1,4 +1,4 @@ -local GameSystem = require "birb.modules.gamesystem" +local GameSystem = require "birb.gamesystem" local Game = GameSystem:extend() function Game:new() diff --git a/examples/main.lua b/examples/main.lua index 622cf65..1efcb52 100644 --- a/examples/main.lua +++ b/examples/main.lua @@ -22,13 +22,11 @@ ]] require "birb" -Game = require "game" + scenes = require "scenes" -function love.load() - birb.startCore(3) - game = Game() - game:read(1) - +function love.load(args) + print(utils.table.toString(args)) + birb.start("game", args) scenes.MainMenu() end diff --git a/examples/scenes/basic/test_menus/init.lua b/examples/scenes/basic/test_menus/init.lua index 7a22f76..d317ef1 100644 --- a/examples/scenes/basic/test_menus/init.lua +++ b/examples/scenes/basic/test_menus/init.lua @@ -24,10 +24,10 @@ local Scene = require "birb.modules.scenes" local TestScene = Scene:extend() -local MenuType = require "birb.modules.menusystem.menus.listbox" -local MenuType2 = require "birb.modules.menusystem.menus.flowbox" -local MenuType3 = require "birb.modules.menusystem.menus.grid" -local Widget = require "birb.modules.menusystem.menus.widgets" +local MenuType = require "birb.modules.gui.menus.listbox" +local MenuType2 = require "birb.modules.gui.menus.flowbox" +local MenuType3 = require "birb.modules.gui.menus.grid" +local Widget = require "birb.modules.gui.menus.widgets" local MenuWidget = Widget.Text:extend() diff --git a/examples/scenes/gameplay/plateform/actors/player.lua b/examples/scenes/gameplay/plateform/actors/player.lua index 09ad23f..44a5422 100644 --- a/examples/scenes/gameplay/plateform/actors/player.lua +++ b/examples/scenes/gameplay/plateform/actors/player.lua @@ -40,7 +40,7 @@ function Player:updateStart(dt) end if (self.isPunching) then - self:checkHitboxesCollisions() + self:applyHitboxesCollisions() end if self.keys["start"].isPressed then @@ -87,7 +87,7 @@ function Player:setDirection(direction) if direction ~= 0 then direction = utils.math.sign(direction) self.direction = direction - self.sprite:setScalling(direction, nil) + self.sprite:setScallingX(direction) end end diff --git a/examples/scenes/gameplay/plateform/init.lua b/examples/scenes/gameplay/plateform/init.lua index c149a1a..e62d01a 100644 --- a/examples/scenes/gameplay/plateform/init.lua +++ b/examples/scenes/gameplay/plateform/init.lua @@ -36,24 +36,24 @@ function Plateformer:new() World(self, folder .. ".actors", "datas/maps/plateformer/platformer.lua") - Pause(self) - self.menusystem:deactivate() - self.menusystem:lockWorldWhenActive(true) - self.menusystem:lockAssetsWhenActive(true) + --Pause(self) + --self.menusystem:deactivate() + --self.menusystem:lockWorldWhenActive(true) + --self.menusystem:lockAssetsWhenActive(true) self.world:loadMap() end function Plateformer:restart() - self.menusystem:deactivate() + --self.menusystem:deactivate() collectgarbage() self.world:reset() end function Plateformer:update(dt) - if (self.menusystem.isActive == true) and self.sources[1].keys["start"].isPressed then - self.menusystem:deactivate() - end + --if (self.menusystem.isActive == true) and self.sources[1].keys["start"].isPressed then + --self.menusystem:deactivate() + --end end function Plateformer:draw() diff --git a/examples/scenes/gameplay/plateform/pause.lua b/examples/scenes/gameplay/plateform/pause.lua index ba5ea49..4b93cbd 100644 --- a/examples/scenes/gameplay/plateform/pause.lua +++ b/examples/scenes/gameplay/plateform/pause.lua @@ -1,5 +1,5 @@ -local ListMenu = require "birb.modules.menusystem.menus.listbox" -local Widget = require "birb.modules.menusystem.menus.widgets" +local ListMenu = require "birb.modules.gui.menus.listbox" +local Widget = require "birb.modules.gui.menus.widgets" local PauseMenu = ListMenu:extend() @@ -25,7 +25,7 @@ end -- All widgets used by the pause menu function ResumeWidget:new() - self.scene = core.scenemanager.currentScene + self.scene = core.scenemanager:getScene() local label = "resume" ResumeWidget.super.new(self, MENU_NAME, "medium", label) end @@ -36,7 +36,7 @@ function ResumeWidget:action() end function RestartWidget:new() - self.scene = core.scenemanager.currentScene + self.scene = core.scenemanager:getScene() local label = "restart" RestartWidget.super.new(self, MENU_NAME, "medium", label) end @@ -47,7 +47,7 @@ function RestartWidget:action() end function ExitWidget:new() - self.scene = core.scenemanager.currentScene + self.scene = core.scenemanager:getScene() local label = "exit" ExitWidget.super.new(self, MENU_NAME, "medium", label) end diff --git a/examples/scenes/mainmenu/init.lua b/examples/scenes/mainmenu/init.lua index 19ef439..3930438 100644 --- a/examples/scenes/mainmenu/init.lua +++ b/examples/scenes/mainmenu/init.lua @@ -1,4 +1,4 @@ --- scenes/mainmenu :: the main menu of the different birb scenes +-- scenes/mainmenu :: the main menu of the different birb examples --[[ Copyright © 2019 Kazhnuz @@ -24,104 +24,12 @@ local Scene = require "birb.modules.scenes" local MainMenu = Scene:extend() -local ListBox = require "birb.modules.menusystem.menus.listbox" -local Widget = require "birb.modules.menusystem.menus.widgets" +local Menu = require "scenes.mainmenu.menu" -local TextMenu = require "birb.modules.menusystem.textmenu" - -local SceneWidget = TextMenu.baseWidgets.Base:extend() -local ExitWidget = TextMenu.baseWidgets.Base:extend() - -local MENU_NAME = "mainMenu" - -function MainMenu:start() +function MainMenu:new() + MainMenu.super.new(self, true, true) self.assets:batchImport("scenes.mainmenu.assets") - print(self.assets:getFont("medium")) - local menu = self:addMenu() - for i=1, 4 do - local name = i .. "player" - menu:addSubmenu(name, core.lang:translate("commons", name)) - if i == 1 then - self:addScene(scenes.Plateformer, "plateform", i) - end - self:addScene(scenes.MovePlayer, "topdown", i) - self:addScene(scenes.MovePlayer3D, "topdown3D", i) - self:addScene(scenes.Action3D, "bigmap3D", i) - if i > 1 then - self:addScene(scenes.MovePlayer, "topdown (zoom)", i, "zoom") - self:addScene(scenes.MovePlayer3D, "topdown3D (zoom)", i, "zoom") - end - end - self:addSubMenu("menus", "menu") - self:addScene(scenes.Inventory, "inventory") - self:addScene(scenes.Options, "options") - self:addScene(scenes.TestMenu, "tests") - - - self.menusystem:setSoundFromSceneAssets("navigate") - local menu = self.menusystem.menus[MENU_NAME] - menu:switch("main") - - ExitWidget(self, "main") - self.menusystem:switchMenu(MENU_NAME) -end - --- MENU FUNCTION --- Functions that serve the handling of menus - -function MainMenu:addMenu() - local w = 424/2 - local x, y = w / 2, 24 - return TextMenu(MENU_NAME, "medium", x, y, w, 8, 0) -end - -function MainMenu:addSubMenu(name, fullname) - local menu = self.menusystem.menus[MENU_NAME] - menu:addSubmenu(name, core.lang:translate("mainmenu", fullname)) -end - -function MainMenu:addScene(scene, fullname, arg1, arg2, arg3, arg4, arg5) - local args = {arg1, arg2, arg3, arg4, arg5} - SceneWidget(self, MENU_NAME, scene, fullname, args) -end - -function MainMenu:draw() - love.graphics.setColor(.3, .1, .4, 1) - love.graphics.rectangle("fill", 0, 0, 424, 240) - utils.graphics.resetColor() - love.graphics.print(math.floor(game.playtime), 8, 8) -end - --- WIDGETS --- Widgets used by menus - --- Scene widget :: switch scene - -function SceneWidget:new(scene, menu, newscene, fullname, args) - self.scene = scene - self.args = args - self.newscene = newscene - local label = core.lang:translate("mainmenu", fullname) - SceneWidget.super.new(self, MENU_NAME, label) -end - -function SceneWidget:action() - core.scenemanager:storeCurrentScene("mainmenu") - core.scenemanager:prepareTransition() - self.newscene(self.args[1], self.args[2], self.args[3], self.args[4], self.args[5]) -end - --- Exit Widget : exit the scenes - -function ExitWidget:new(scene, menu) - self.scene = scene - local label = core.lang:translate("commons", "exit") - SceneWidget.super.new(self, MENU_NAME, label) -end - -function ExitWidget:action() - game:write() - love.event.quit() + Menu(self) end return MainMenu diff --git a/examples/scenes/mainmenu/menu.lua b/examples/scenes/mainmenu/menu.lua new file mode 100644 index 0000000..5ecd2ba --- /dev/null +++ b/examples/scenes/mainmenu/menu.lua @@ -0,0 +1,47 @@ +local Parent = require "birb.modules.gui.textmenu" +local MainMenu = Parent:extend() + +local defTransitions = require "birb.modules.transitions" + +local MENU_X, MENU_Y = 24, 48 +local MENU_W = 424/3 +local MENU_ITEM_NUMBER = 8 + +function MainMenu:new() + MainMenu.super.new(self, "mainmenu", "medium", MENU_X, MENU_Y, MENU_W, MENU_ITEM_NUMBER, false) + + for i=1, 4 do + local name = i .. "player" + self:switch("main") + self:addSubmenu(name, i .. " Players") + if i == 1 then + self:addItem("Plateformer", "left", function() self:launchScene(scenes.Plateformer, i) end) + end + self:addItem("Overworld", "left", function() self:launchScene(scenes.MovePlayer, i) end) + self:addItem("Basic 3D", "left", function() self:launchScene(scenes.MovePlayer3D, i) end) + self:addItem("Complexe 3D", "left", function() self:launchScene(scenes.Action3D, i) end) + if i > 1 then + self:addItem("Basic 3D (zoom)", "left", function() self:launchScene(scenes.MovePlayer3D, i, "zoom") end) + self:addItem("Complexe 3D (zoom)", "left", function() self:launchScene(scenes.Action3D, i, "zoom") end) + end + end + self:switch("main") + self:addSubmenu("menus", "Menus") + self:addItem("Inventory", "left", function() self:launchScene(scenes.Inventory) end) + self:addItem("Options", "left", function() self:launchScene(scenes.Options) end) + self:addItem("Tests", "left", function() self:launchScene(scenes.TestMenu) end) + self:switch("main") + self:addItem("Exit game", "left", function() self:exitGame() end) + self:getFocus() +end + +function MainMenu:launchScene(scene, arg1, arg2, arg3, arg4, arg5) + local args = {arg1, arg2, arg3, arg4, arg5} + core.screen:startTransition(defTransitions.circle, defTransitions.default, function() scene(args) end, 424/2, 240/2) +end + +function MainMenu:exitGame() + love.event.quit("000") +end + +return MainMenu diff --git a/examples/scenes/menus/inventory/init.lua b/examples/scenes/menus/inventory/init.lua index e2566c4..6bdf0b6 100644 --- a/examples/scenes/menus/inventory/init.lua +++ b/examples/scenes/menus/inventory/init.lua @@ -24,9 +24,9 @@ local Scene = require "birb.modules.scenes" local Inventory = Scene:extend() -local HListBox = require "birb.modules.menusystem.menus.hlistbox" -local FloxBox = require "birb.modules.menusystem.menus.flowbox" -local Widget = require "birb.modules.menusystem.menus.widgets" +local HListBox = require "birb.modules.gui.menus.hlistbox" +local FloxBox = require "birb.modules.gui.menus.flowbox" +local Widget = require "birb.modules.gui.menus.widgets" local InventoryWidget = Widget.Text:extend() local ItemWidget = Widget.Text:extend() diff --git a/examples/scenes/menus/options/consts.lua b/examples/scenes/menus/options/consts.lua new file mode 100644 index 0000000..aec753b --- /dev/null +++ b/examples/scenes/menus/options/consts.lua @@ -0,0 +1,8 @@ +local consts = {} + +consts.OPTION_MENU = "optionMenu" +consts.BORDERS_W = 96 +consts.BORDERS_H = 24 +consts.NBR_ELEMS = 8 + +return consts \ No newline at end of file diff --git a/examples/scenes/menus/options/init.lua b/examples/scenes/menus/options/init.lua index 86be3f0..a1cef42 100644 --- a/examples/scenes/menus/options/init.lua +++ b/examples/scenes/menus/options/init.lua @@ -24,10 +24,12 @@ local Scene = require "birb.modules.scenes" local OptionsMenu = Scene:extend() -local ListBox = require "birb.modules.menusystem.menus.listbox" local Widgets = require "scenes.menus.options.widgets" +local Menu = require "scenes.menus.options.menu" -function OptionsMenu:new() +local consts = require "scenes.menus.options.consts" + +function OptionsMenu:start() OptionsMenu.super.new(self) self.assets:addImageFont("medium", "assets/fonts/medium") self.assets:setMusic("assets/music/options.ogg") @@ -38,26 +40,31 @@ function OptionsMenu:new() self.assets:playMusic() - self:addMenu("main", true) + self.menu = Menu("medium"); + self:addSubMenu("video", "video") - self:addSubMenu("audio", "audio") - self:addSubMenu("langs", "langs") - self:addSubMenu("inputs", "inputs") - Widgets.Resolution(self, "video") - Widgets.Switch(self, "video", "fullscreen") - Widgets.Switch(self, "video", "borders") - Widgets.Switch(self, "video", "vsync") + Widgets.Switch("fullscreen") + Widgets.Switch("borders") + Widgets.Switch("vsync") - self:addPlayerMenus() + self:addSubMenu("audio", "audio") + Widgets.Audio("sfx") + Widgets.Audio("music") + + self:addSubMenu("langs", "langs") self:setLanguageMenu() - Widgets.Audio(self, "audio", "sfx") - Widgets.Audio(self, "audio", "music") + self:addSubMenu("inputs", "inputs") + + self:addPlayerMenus() + + local menu = self.menusystem.menus[consts.OPTION_MENU] + menu:switch("main") Widgets.Exit(self, "main") - self.menusystem:switchMenu("main") + self.menusystem:switchMenu(consts.OPTION_MENU) self.menusystem:setSoundFromSceneAssets("navigate") @@ -69,29 +76,19 @@ end -- Functions that serve the handling of menus function OptionsMenu:addMenu(name, nobackbutton) - local screenHeight, screenWidth = core.screen:getDimensions() - local w, h = 424/2, 240 - 48 - local x, y = w / 2, 24 - ListBox(self.menusystem, name, x, y, w, h, 8) + Menu("medium") end function OptionsMenu:addSubMenu(name, fullname) - self:addMenu(name) - Widgets.SubMenu(self, "main", name, fullname) - Widgets.SubMenu(self, name, "main", "back", 1, "<") + local menu = self.menusystem.menus[consts.OPTION_MENU] + menu:addSubmenu(name, core.lang:translate("options", fullname), "main") end function OptionsMenu:addPlayerMenus() - for i,v in ipairs(core.input.data) do - local menu = "player" .. i - self:addMenu(menu) - Widgets.PlayerSubMenu(self, "inputs", i) - for k,w in pairs(v.keys) do - -- FIXME: make sure that you can use the order you want for the keys list - -- instead of a random one - Widgets.Key(self, i, k) - end - Widgets.SubMenu(self, menu, "inputs", "back", 1, "<") + for key, _ in pairs(core.input.data[1].keys) do + -- FIXME: make sure that you can use the order you want for the keys list + -- instead of a random one + Widgets.Key(key) end end @@ -100,8 +97,8 @@ function OptionsMenu:addScene(submenu, scene, fullname) end function OptionsMenu:setLanguageMenu() - for i,v in ipairs(core.lang.data.available) do - Widgets.Lang(self, "langs", v) + for i,lang in ipairs(core.lang.data.available) do + Widgets.Lang(lang) end end @@ -121,6 +118,7 @@ end function OptionsMenu:draw() love.graphics.setColor(.3, .1, .4, 1) love.graphics.rectangle("fill", 0, 0, 424, 240) + utils.graphics.resetColor() end return OptionsMenu diff --git a/examples/scenes/menus/options/menu.lua b/examples/scenes/menus/options/menu.lua new file mode 100644 index 0000000..0a56960 --- /dev/null +++ b/examples/scenes/menus/options/menu.lua @@ -0,0 +1,14 @@ +local TextMenu = require "birb.modules.gui.textmenu" +local OptionMenu = TextMenu:extend() + +local consts = require "scenes.menus.options.consts" + +function OptionMenu:new(font) + local screenWidth, _ = core.screen:getDimensions() + local w = screenWidth - (consts.BORDERS_W*2) + local x = consts.BORDERS_W + local y = consts.BORDERS_H + OptionMenu.super.new(self, consts.OPTION_MENU, font, x, y, w, consts.NBR_ELEMS, 8) +end + +return OptionMenu \ No newline at end of file diff --git a/examples/scenes/menus/options/widgets.lua b/examples/scenes/menus/options/widgets.lua index dcb19f0..1711237 100644 --- a/examples/scenes/menus/options/widgets.lua +++ b/examples/scenes/menus/options/widgets.lua @@ -23,15 +23,15 @@ local widgets = {} -local Widget = require "birb.modules.menusystem.menus.widgets" -local DoubleTextWidget = Widget.Text:extend() +local Widget = require "birb.modules.gui.textmenu.widgets.basic" +local DoubleTextWidget = Widget:extend() widgets.SubMenu = DoubleTextWidget:extend() -widgets.Dummy = Widget.Text:extend() -widgets.Exit = Widget.Text:extend() +widgets.Dummy = Widget:extend() +widgets.Exit = Widget:extend() widgets.Switch = DoubleTextWidget:extend() widgets.Resolution = DoubleTextWidget:extend() -widgets.Lang = Widget.Text:extend() +widgets.Lang = Widget:extend() widgets.PlayerSubMenu = DoubleTextWidget:extend() widgets.Key = DoubleTextWidget:extend() widgets.Audio = DoubleTextWidget:extend() @@ -41,44 +41,33 @@ widgets.Audio = DoubleTextWidget:extend() -- DoubleText widget : a two-side text widget -function DoubleTextWidget:new(menu, font, label1, label2) - DoubleTextWidget.super.new(self, menu, font, label1) - self.label2 = label2 or "" -end - -function DoubleTextWidget:drawCanvas() - local w, h - w = math.floor(self.width) - h = math.floor(self.height / 2) - (self.font:getHeight() / 2) - self.font:draw(self.label, 4, h, -1, "left") - self.font:draw(self.label2, w-4, h, -1, "right") +function DoubleTextWidget:new(label1, label2) + DoubleTextWidget.super.new(self, "optionMenu", label1, "left") + local label2 = label2 or "" + self:addLabel(label2, "right") end -- Submenu widget :: go to a submenu -function widgets.SubMenu:new(scene, menu, newmenu, fullname, order, label2) +function widgets.SubMenu:new(scene, newmenu, fullname, order, label2) self.scene = scene - local widgetmenu = self.scene.menusystem.menus[menu] - local font = self.scene.assets.fonts["medium"] local label = core.lang:translate("options", fullname) local label2 = label2 or ">" self.newmenu = newmenu - widgets.SubMenu.super.new(self, widgetmenu, font, label, label2) + widgets.SubMenu.super.new(self, label, label2) self.order = order or 0 end function widgets.SubMenu:action() self.scene.assets:playSFX("confirm") - self.scene.menusystem:switchMenu(self.newmenu) + self.menu:switch(self.newmenu) end -- Dummy widget :: An empty widget to serve as a base for others function widgets.Dummy:new(scene, menu, fullname) self.scene = scene - local widgetmenu = self.scene.menusystem.menus[menu] - local font = self.scene.assets.fonts["medium"] - widgets.Dummy.super.new(self, widgetmenu, font, fullname) + widgets.Dummy.super.new(self, menu, fullname) end function widgets.Dummy:action() @@ -89,14 +78,12 @@ end function widgets.Exit:new(scene, menu) self.scene = scene - local widgetmenu = self.scene.menusystem.menus[menu] - local font = self.scene.assets.fonts["medium"] local label = core.lang:translate("commons", "exit") - widgets.Exit.super.new(self, widgetmenu, font, "Exit") + widgets.Exit.super.new(self, "optionMenu", label, "left") end function widgets.Exit:action() - self.scene.assets:playSFX("confirm") + self.assets:playSFX("confirm") core.scenemanager:setStoredScene("mainmenu") end @@ -105,14 +92,11 @@ end -- Switch widget (One widget to handle graphical switch) -function widgets.Switch:new(scene, menu, keyname) - self.scene = scene - local widgetmenu = self.scene.menusystem.menus[menu] - local font = self.scene.assets.fonts["medium"] +function widgets.Switch:new(keyname) self.keyname = keyname local label = core.lang:translate("options", keyname) local label2 = self:getLabel() - widgets.Switch.super.new(self, widgetmenu, font, label, label2) + widgets.Switch.super.new(self, label, label2) self.order = 0 end @@ -152,21 +136,19 @@ end function widgets.Switch:action() self:modifyKey() - self.scene.assets:playSFX("confirm") - self.label2 = self:getLabel() + local scene = core.scenemanager:getScene() + scene.assets:playSFX("confirm") + self:replaceLabel(2, self:getLabel()) core.options:write() self:invalidateCanvas() end -- Resolution Widget -function widgets.Resolution:new(scene, menu) - self.scene = scene - local widgetmenu = self.scene.menusystem.menus[menu] - local font = self.scene.assets.fonts["medium"] +function widgets.Resolution:new() local label = core.lang:translate("options", "resolution") local label2 = self:getLabel() - widgets.Resolution.super.new(self, widgetmenu, font, label, label2) + widgets.Resolution.super.new(self, label, label2) end function widgets.Resolution:getLabel() @@ -179,9 +161,10 @@ function widgets.Resolution:action() else core.options.data.video.resolution = core.options.data.video.resolution + 1 end - self.label2 = self:getLabel() + self:replaceLabel(2, self:getLabel()) core.screen:applySettings() - self.scene.assets:playSFX("confirm") + local scene = core.scenemanager:getScene() + scene.assets:playSFX("confirm") self:invalidateCanvas() core.options:write() end @@ -189,17 +172,15 @@ end -- LANGS WIDGET -- Allow you to change the lang of the game -function widgets.Lang:new(scene, menu, lang) - self.scene = scene - local widgetmenu = self.scene.menusystem.menus[menu] - local font = self.scene.assets.fonts["medium"] +function widgets.Lang:new(lang) local label = core.lang:getLangName(lang) self.lang = lang - widgets.Lang.super.new(self, widgetmenu, font, label) + widgets.Lang.super.new(self, "optionMenu", label, "left") end function widgets.Lang:action() - self.scene.assets:playSFX("confirm") + local scene = core.scenemanager:getScene() + scene.assets:playSFX("confirm") core.options:setLanguage(self.lang) --self.scene.menusystem:invalidateAllWidgets() end @@ -209,35 +190,31 @@ end function widgets.PlayerSubMenu:new(scene, menu, sourceid) self.scene = scene - local widgetmenu = self.scene.menusystem.menus[menu] - local font = self.scene.assets.fonts["medium"] local label = core.lang:translate("options", "player") .. " " .. sourceid local label2 = ">" self.newmenu = "player" .. sourceid - widgets.PlayerSubMenu.super.new(self, widgetmenu, font, label, label2) + widgets.PlayerSubMenu.super.new(self, label, label2) self.order = 0 end function widgets.PlayerSubMenu:action() - self.scene.assets:playSFX("confirm") - self.scene.menusystem:switchMenu(self.newmenu) + local scene = core.scenemanager:getScene() + scene.assets:playSFX("confirm") + scene.menusystem:switchMenu(self.newmenu) end -- Key widgets -function widgets.Key:new(scene, sourceid, key) - self.scene = scene - self.source = sourceid +function widgets.Key:new(key) + self.source = 1 self.key = key local menu = "player" .. self.source - local widgetmenu = self.scene.menusystem.menus[menu] - local font = self.scene.assets.fonts["medium"] local label = self.key local label2 = self:getLabel() - widgets.Key.super.new(self, widgetmenu, font, label, label2) + widgets.Key.super.new(self, label, label2) self.order = 0 end @@ -246,28 +223,27 @@ function widgets.Key:getLabel() end function widgets.Key:action() - self.scene.assets:playSFX("navigate") - self.scene:changeKey(self) - self.scene.menusystem:deactivate() + local scene = core.scenemanager:getScene() + scene.assets:playSFX("navigate") + scene:changeKey(self) + scene.menusystem:deactivate() end function widgets.Key:receiveKey( key ) - self.scene.assets:playSFX("confirm") + local scene = core.scenemanager:getScene() + scene.assets:playSFX("confirm") core.options:setInputKey(self.source, self.key, key) - self.label2 = self:getLabel() + self:replaceLabel(2, self:getLabel()) self:invalidateCanvas() end -- AUDIO FUNCTIONS -- Sounds/Music functions -function widgets.Audio:new(scene, menu, audiotype) - self.scene = scene +function widgets.Audio:new(audiotype) self.audiotype = audiotype - local widgetmenu = self.scene.menusystem.menus[menu] - local font = self.scene.assets.fonts["medium"] self.audiotype = audiotype local label = "" if (self.audiotype == "sfx") then @@ -277,7 +253,7 @@ function widgets.Audio:new(scene, menu, audiotype) end local label2 = self:getLabel() - widgets.Audio.super.new(self, widgetmenu, font, label, label2) + widgets.Audio.super.new(self, label, label2) self.order = 0 end @@ -306,15 +282,16 @@ function widgets.Audio:setVolume(vol) core.options.data.audio.music = vol end - self.label2 = self:getLabel() + self:replaceLabel(2, self:getLabel()) self:invalidateCanvas() end function widgets.Audio:action() local value = self:getVolume() self:setVolume(value - 20) - self.scene.assets:playSFX("confirm") - self.scene.assets.music:setVolume(core.options.data.audio.music / 100) + local scene = core.scenemanager:getScene() + scene.assets:playSFX("confirm") + core.music:applyVolume() core.options:write() end diff --git a/launch.sh b/launch.sh new file mode 100755 index 0000000..d6c35f4 --- /dev/null +++ b/launch.sh @@ -0,0 +1 @@ +love ./examples \ No newline at end of file