diff --git a/sonic-radiance.love/core/input.lua b/sonic-radiance.love/core/input.lua index 716dd46..7513d25 100644 --- a/sonic-radiance.love/core/input.lua +++ b/sonic-radiance.love/core/input.lua @@ -28,23 +28,8 @@ function InputManager:new(controller) self.controller = controller self.data = self.controller.options.data.input[1] - self.keys = {} - for k,v in pairs(self.data.keys) do - self.keys[k] = {} - self.keys[k].isDown = false - self.keys[k].isPressed = false - self.keys[k].isReleased = false - self.keys[k].test = "ok" - end - - self.fakekeys = {} - for k,v in pairs(self.data.keys) do - self.fakekeys[k] = {} - self.fakekeys[k].isDown = false - self.fakekeys[k].isPressed = false - self.fakekeys[k].isReleased = false - self.fakekeys[k].test = "ok" - end + self.keys = self:getKeyList() + self.fakekeys = self:getKeyList() end function InputManager:isDown(padkey) @@ -61,6 +46,19 @@ function InputManager:isDown(padkey) return isdown end +function InputManager:getKeyList() + local keys = {} + for k,v in pairs(self.data.keys) do + keys[k] = {} + keys[k].isDown = false + keys[k].isPressed = false + keys[k].isReleased = false + keys[k].test = "ok" + end + + return keys +end + function InputManager:translateAction(key) --TODO:depreciated function local padkey = "" @@ -78,6 +76,17 @@ function InputManager:getKey(padkey) return key end +function InputManager:flushKeys() + self.keys = {} + for k,v in pairs(self.data.keys) do + self.keys[k] = {} + self.keys[k].isDown = false + self.keys[k].isPressed = false + self.keys[k].isReleased = false + self.keys[k].test = "ok" + end +end + function InputManager:update(dt) for k,v in pairs(self.keys) do local isDown = self:isDown(k) diff --git a/sonic-radiance.love/core/modules/assets/animator.lua b/sonic-radiance.love/core/modules/assets/animator.lua index f1eb2c6..7bce90c 100644 --- a/sonic-radiance.love/core/modules/assets/animator.lua +++ b/sonic-radiance.love/core/modules/assets/animator.lua @@ -61,20 +61,34 @@ function Animator:update(dt) end end +function Animator:getAnimationDuration(animation) + return (self.animationData.endAt - self.animationData.startAt) / self.animationData.speed +end + function Animator:getFrame() return self.frame end +function Animator:animationExist(name) + return (self.sprite.data.animations[self.currentAnimation] ~= nil) +end + function Animator:draw(x, y, r, sx, sy, ox, oy, kx, ky) self.sprite:drawFrame(self.frame, x, y, r, sx, sy, ox, oy, kx, ky) end function Animator:changeAnimation(name, restart) + -- Force restart if animation name is different + if (self.currentAnimation ~= name) then + restart = true + else + restart = restart or false + end + self.currentAnimation = name self.animationData = self.sprite.data.animations[self.currentAnimation] - local restart = restart or true - if (restart) then + if (restart == true) then self.frame = self.animationData.startAt self.frameTimer = 0 end diff --git a/sonic-radiance.love/core/modules/assets/background.lua b/sonic-radiance.love/core/modules/assets/background.lua index 7b1f7e0..862050b 100644 --- a/sonic-radiance.love/core/modules/assets/background.lua +++ b/sonic-radiance.love/core/modules/assets/background.lua @@ -28,10 +28,11 @@ function Background:new(filepath) self.image = love.graphics.newImage(filepath) self.batch = love.graphics.newSpriteBatch(self.image , 1000 ) - self.width, self.height = self.image:getDimensions() + self.width, self.height = self.image:getDimensions() + screenwidth, screenheight = core.screen:getDimensions() - local w = math.floor(424 / self.width) * self.width + 1 - local h = math.floor(240 / self.height) * self.height + 1 + local w = math.floor(screenwidth / self.width) * self.width + 1 + local h = math.floor(screenheight / self.height) * self.height + 1 for i=-1, w do for j=-1, h do diff --git a/sonic-radiance.love/core/modules/assets/fonts.lua b/sonic-radiance.love/core/modules/assets/fonts.lua index c4d0879..f2bc7c9 100644 --- a/sonic-radiance.love/core/modules/assets/fonts.lua +++ b/sonic-radiance.love/core/modules/assets/fonts.lua @@ -107,9 +107,9 @@ function Font:print(text, x, y, align, r, sx, sy, ox, oy, kx, ky) self:set() if (self.spacing.active) then - utils.draw.printWithSpacing(text, self.spacing.size, align, x, y, r, sx, sy, ox, oy, kx, ky) + utils.graphics.printWithSpacing(text, x, y, self.spacing.size, align, r, sx, sy, ox, oy, kx, ky) else - utils.draw.print(text, align, x, y, r, sx, sy, ox, oy, kx, ky) + utils.graphics.print(text, x, y, align, r, sx, sy, ox, oy, kx, ky) end end @@ -138,7 +138,7 @@ 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) - utils.draw.resetColor() + utils.graphics.resetColor() end function Font:applyFilterBorder(text, x, y, limit, align, r, sx, sy, ox, oy, kx, ky) @@ -155,7 +155,7 @@ function Font:applyFilterBorder(text, x, y, limit, align, r, sx, sy, ox, oy, kx, self:printf(text, x , y+1, limit, align, r, sx, sy, ox, oy, kx, ky) self:printf(text, x+1, y+1, limit, align, r, sx, sy, ox, oy, kx, ky) - utils.draw.resetColor() + utils.graphics.resetColor() end function Font:applyFilterDoubleBorder(text, x, y, limit, align, r, sx, sy, ox, oy, kx, ky) @@ -172,7 +172,7 @@ function Font:applyFilterDoubleBorder(text, x, y, limit, align, r, sx, sy, ox, o self:printf(text, x , y+2, limit, align, r, sx, sy, ox, oy, kx, ky) self:printf(text, x+2, y+2, limit, align, r, sx, sy, ox, oy, kx, ky) - utils.draw.resetColor() + utils.graphics.resetColor() end return Font diff --git a/sonic-radiance.love/core/modules/assets/imagefonts.lua b/sonic-radiance.love/core/modules/assets/imagefonts.lua new file mode 100644 index 0000000..16e0b7a --- /dev/null +++ b/sonic-radiance.love/core/modules/assets/imagefonts.lua @@ -0,0 +1,14 @@ +local Font = require "core.modules.assets.fonts" +local ImageFont = Font:extend() + +function ImageFont:new(filename, extraspacing) + local data = require(filename) + local extraspacing = extraspacing or data.extraspacing or 1 + self.font = love.graphics.newImageFont(filename .. ".png", data.glyphs, extraspacing) + self.filter = "" + self:setColor(1, 1, 1, 1) + self:setSpacing(false, 0) + self.align = "left" +end + +return ImageFont diff --git a/sonic-radiance.love/core/modules/assets/init.lua b/sonic-radiance.love/core/modules/assets/init.lua index d1dac82..b6e11dc 100644 --- a/sonic-radiance.love/core/modules/assets/init.lua +++ b/sonic-radiance.love/core/modules/assets/init.lua @@ -26,6 +26,8 @@ local Assets = Object:extend() local Sprite = require "core.modules.assets.sprites" local Font = require "core.modules.assets.fonts" +local ImageFont = require "core.modules.assets.imagefonts" + local Tileset = require "core.modules.assets.tileset" local Autotile = require "core.modules.assets.autotile" local Background = require "core.modules.assets.background" @@ -42,6 +44,8 @@ function Assets:new() self:clearTileset() self.images = {} + + self.isActive = true end function Assets:init() @@ -68,7 +72,9 @@ function Assets:clear() end function Assets:update(dt) - self:animationsUpdate(dt) + if (self.isActive) then + self:animationsUpdate(dt) + end end -- SFX et Musique @@ -90,14 +96,14 @@ function Assets:setMusic(filename) if filename ~= nil then love.audio.stop( ) self.music = love.audio.newSource(filename, "stream" ) - self.music:setVolume(game.options.data.audio.music / 100) + self.music:setVolume(core.options.data.audio.music / 100) end end function Assets:playSFX(filename) if not (self.sfx[filename] == nil) then self.sfx[filename]:stop() - self.sfx[filename]:setVolume(game.options.data.audio.sfx / 100) + self.sfx[filename]:setVolume(core.options.data.audio.sfx / 100) love.audio.play( self.sfx[filename] ) end end @@ -160,6 +166,11 @@ function Assets:addFont(key, 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 diff --git a/sonic-radiance.love/core/modules/assets/sprites.lua b/sonic-radiance.love/core/modules/assets/sprites.lua index b52580c..326db34 100644 --- a/sonic-radiance.love/core/modules/assets/sprites.lua +++ b/sonic-radiance.love/core/modules/assets/sprites.lua @@ -42,6 +42,10 @@ function Sprite:update(dt) self.animator:update(dt) end +function Sprite:clone() + return Animator(self) +end + function Sprite:setCustomSpeed(customSpeed) self.animator:setCustomSpeed(customSpeed) end @@ -54,6 +58,10 @@ function Sprite:changeAnimation(name, restart) self.animator:changeAnimation(name, restart) end +function Sprite:animationExist(name) + return self.animator:animationExist(name) +end + function Sprite:drawAnimation(x, y, r, sx, sy, ox, oy, kx, ky) self.animator:draw(x, y, r, sx, sy, ox, oy, kx, ky) end diff --git a/sonic-radiance.love/core/modules/menusystem/flowbox.lua b/sonic-radiance.love/core/modules/menusystem/flowbox.lua new file mode 100644 index 0000000..a120f80 --- /dev/null +++ b/sonic-radiance.love/core/modules/menusystem/flowbox.lua @@ -0,0 +1,186 @@ +local cwd = (...):gsub('%.flowbox$', '') .. "." +local Menu = require(cwd .. "parent") + +local FlowBox = Menu:extend() + +local menuutils = require(cwd .. "widgets.utils") + +function FlowBox:new(menusystem, name, x, y, w, h, slots_hor, slots_vert) + self.view = {} + self.view.slotNumber = slots_hor * slots_vert + self.view.lineNumber = slots_vert + self.view.colNumber = slots_hor + self.view.firstSlot = 1 + FlowBox.super.new(self, menusystem, name, x, y, w, h) + self.widget.h = math.floor( self.h / slots_vert ) + self.widget.w = math.floor( self.w / slots_hor ) + self.h = slots_vert * self.widget.h -- On fait en sorte que la hauteur + self.w = slots_hor * self.widget.w -- et la largeur + -- soit un multiple du nombre de slot et de leur dimensions +end + +function FlowBox:updateWidgetSize() + self.widget.h = math.floor( self.h / self.view.lineNumber ) + self.widget.w = math.floor( self.w / self.view.colNumber ) +end + +function FlowBox:update(dt) + self:updateView() +end + +function FlowBox:updateView() + local col, line = self:getCoord(self.widget.selected) + local begincol, beginline = self:getCoord(self.view.firstSlot) + + if line < beginline then + beginline = line + end + + if line > beginline + self.view.lineNumber - 1 then + beginline = line - self.view.lineNumber + 1 + end + + if beginline < 0 then + beginline = 0 + end + + self.view.firstSlot = beginline * self.view.colNumber + 1 +end + +function FlowBox:getCoord(id_selected) + id_selected = id_selected - 1 -- On simplifie les calcul en prenant 0 comme départ + local line, col + line = math.floor(id_selected / self.view.colNumber) + col = id_selected - (line * self.view.colNumber) + return col, line +end + +function FlowBox:moveCursor(new_col, new_line) + local col, line = self:getCoord(self.widget.selected) + local lastcol, lastline = self:getCoord(#self.widget.list) + + + if new_line < 0 then + new_line = lastline + end + + if new_line > lastline then + new_line = 0 + end + + if (new_line == lastline) then + if new_col < 0 then + new_col = lastcol + end + + if new_col > lastcol then + if (line == lastline) then + new_col = 0 + else + new_col = lastcol + end + end + else + if new_col < 0 then + new_col = self.view.colNumber - 1 + end + + if new_col == self.view.colNumber then + new_col = 0 + end + end + + self.widget.selected = (new_line * self.view.colNumber) + new_col + 1 +end + +function FlowBox:keyreleased(key, code) + local col, line = self:getCoord(self.widget.selected) + if key == 'left' then + self:moveCursor(col - 1, line) + end + + if key == 'right' then + self:moveCursor(col + 1, line) + end + + if key == 'up' then + self:moveCursor(col, line - 1) + end + + if key == 'down' then + self:moveCursor(col, line + 1) + end + + if key == "A" then + if (self.widget.selected >= 1 and self.widget.selected <= #self.widget.list) then + self.widget.list[self.widget.selected]:action() + end + end +end + +function FlowBox:mousemoved(x, y) + local col, line = self:getCoord(self.widget.selected) + local begincol, beginline = self:getCoord(self.view.firstSlot) + local newcol, newline, widget_selected + + newline = beginline + math.floor(y / self.widget.h) + newcol = math.floor(x / self.widget.w) + widget_selected = (newline * self.view.colNumber) + newcol + 1 + + if widget_selected >= 1 and widget_selected <= #self.widget.list then + self.widget.selected = widget_selected + self:getFocus() + end +end + +function FlowBox:mousepressed(x, y, button, isTouch) + local col, line = self:getCoord(self.widget.selected) + local begincol, beginline = self:getCoord(self.view.firstSlot) + local newline, newcol, widget_selected + + newline = beginline + math.floor(y / self.widget.h) + newcol = math.floor(x / self.widget.w) + widget_selected = (newline * self.view.colNumber) + newcol + 1 + + if widget_selected >= 1 and widget_selected <= #self.widget.list then + self.widget.selected = widget_selected + self:getFocus() + self.widget.list[self.widget.selected]:action() + end + +end + +function FlowBox:draw() + self:updateView() + local widgety = self.y + local widgetx = self.x + for i,v in ipairs(self.widget.list) do + if (i >= self.view.firstSlot) and (i < self.view.firstSlot + self.view.slotNumber) then + v:draw(widgetx, widgety, self.widget.w, self.widget.h) + if self.widget.selected == i and self:haveFocus() == true then + v:drawSelected(widgetx, widgety, self.widget.w, self.widget.h) + else + v:draw(widgetx, widgety, self.widget.w, self.widget.h) + end + widgetx = widgetx + self.widget.w + if widgetx == (self.x + self.w) then + widgetx = self.x + widgety = widgety + self.widget.h + end + end + end +end + +function FlowBox:drawCursor() + self:updateView() + local begincol, beginline = self:getCoord(self.view.firstSlot) + if (self.widget.selected >= 1 and self.widget.selected <= #self.widget.list) then + local w, h = self:getWidgetSize() + local col, line = self:getCoord(self.widget.selected) + local x = (col) * h + local y = (line - beginline) * h + menuutils.drawCursor(self.x + x, self.y + y, w, h) + end +end + +return FlowBox diff --git a/sonic-radiance.love/core/modules/menusystem/grid.lua b/sonic-radiance.love/core/modules/menusystem/grid.lua new file mode 100644 index 0000000..7dec4b3 --- /dev/null +++ b/sonic-radiance.love/core/modules/menusystem/grid.lua @@ -0,0 +1,235 @@ +local cwd = (...):gsub('%.grid$', '') .. "." +local Menu = require(cwd .. "parent") + +local GridBox = Menu:extend() + +local menuutils = require(cwd .. "widgets.utils") + +function GridBox:new(menusystem, name, x, y, w, h, colNumber, lineNumber) + self.view = {} + self.view.slotNumber = colNumber * lineNumber + self.view.colNumber = colNumber + self.view.lineNumber = lineNumber + self.view.firstSlot = 1 + GridBox.super.new(self, menusystem, name, x, y, w, h) + self.h = lineNumber * self.widget.h -- On fait en sorte que la hauteur + self.w = colNumber * self.widget.w -- et la largeur + -- soit un multiple du nombre de slot et de leur dimensions + self.cursor = {} + self.cursor.x = 0 + self.cursor.y = 0 + + -- La gridbox possède la particularité de pouvoir fusioner des slots, on fait + -- donc une liste de slots disponibles, qui serviront par la suite. + self.slots = {} +end + +function GridBox:addSlot(widgetID, x, y, w, h) + local slot = {} + slot.x = x + slot.y = y + slot.w = w + slot.h = h + slot.widgetID = widgetID + + table.insert(self.slots, slot) +end + +function GridBox:updateWidgetSize() + self.widget.h = math.floor( self.h / self.view.lineNumber ) + self.widget.w = math.floor( self.w / self.view.colNumber ) +end + +function GridBox:getWidgetSize(id) + local slot = self:getWidgetSlot(id) + if slot == 0 then + return 1, 1 + else + return self.widget.w * self.slots[slot].w, self.widget.h * self.slots[slot].h + end +end + +function GridBox:getSlotHitbox(slot) + local x, y, w, h + x = self.slots[slot].x * self.widget.w + y = self.slots[slot].y * self.widget.h + w = self.slots[slot].w * self.widget.w + h = self.slots[slot].h * self.widget.h + + return x, y, w, h +end + +function GridBox:getSlotCenter(slot) + local x, y, w, h = self:getSlotHitbox(slot) + + return x + (w/2), y + (h/2) +end + +function GridBox:getWidgetID(slot) + local widgetID + if self.slots[slot] ~= nil then + widgetID = self.slots[slot].widgetID + else + widgetID = 0 + end + return widgetID +end + +function GridBox:haveWidget(slot) + local id = self:getWidgetID(slot) + return self.widget.list[id] ~= nil +end + +function GridBox:getWidgetSlot(widgetID) + local slot = 0 + for i,v in ipairs(self.slots) do + if (self.slots[i].widgetID == widgetID) then + slot = i + end + end + + return slot +end + +function GridBox:getWidgetAtPoint(x, y) + local x = x or 0 + local y = y or 0 + local widgetID = nil + + for i,v in ipairs(self.slots) do + local xx, yy, ww, hh = self:getSlotHitbox(i) + if (x >= xx) and (y >= yy) and (x < xx + ww) and (y < yy + hh) then + widgetID = v.widgetID + end + end + + return widgetID +end + +function GridBox:update(dt) + self.view.firstSlot = 1 +end + +function GridBox:keyreleased(key, code) + slotID = self:getWidgetSlot(self.widget.selected) + local col, line = self.cursor.x, self.cursor.y + if key == 'left' then + self:moveCol(-1) + end + + if key == 'right' then + self:moveCol(1) + end + + if key == 'up' then + self:moveLine(-1) + end + + if key == 'down' then + self:moveLine(1) + end + + if key == "A" and self.widget.selected <= #self.widget.list then + self.widget.list[self.widget.selected]:action() + end +end + +function GridBox:moveCol(direction) + local orig_x, orig_y = self:getSlotCenter(self.widget.selected) + local distance = self.w -- on met directement à la distance max possible le système + local nearastWidget = 0 + for i,v in ipairs(self.slots) do + local xx, yy = self:getSlotCenter(i) + -- On commence par vérifier si le slot est bien positionné par rapport au + -- widget de base + if utils.math.sign(xx - orig_x) == direction then + if utils.math.pointDistance(orig_x, orig_y, xx, yy) < distance then + distance = utils.math.pointDistance(orig_x, orig_y, xx, yy) + nearestWidget = v.widgetID + end + end + end + + if nearestWidget ~= 0 then + self.widget.selected = nearestWidget + end +end + +function GridBox:moveLine(direction) + local orig_x, orig_y = self:getSlotCenter(self.widget.selected) + local distance = self.h -- on met directement à la distance max possible le système + local nearastWidget = 0 + for i,v in ipairs(self.slots) do + local xx, yy = self:getSlotCenter(i) + -- On commence par vérifier si le slot est bien positionné par rapport au + -- widget de base + if utils.math.sign(yy - orig_y) == direction then + if utils.math.pointDistance(orig_x, orig_y, xx, yy) < distance then + distance = utils.math.pointDistance(orig_x, orig_y, xx, yy) + nearestWidget = v.widgetID + end + end + end + + if nearestWidget ~= 0 then + self.widget.selected = nearestWidget + end +end + +function GridBox:mousemoved(x, y) + local widgetID = self:getWidgetAtPoint(x, y) + + if widgetID ~= nil then + self.widget.selected = widgetID + self:getFocus() + end + + if self.widget.selected < 1 then + self.widget.selected = 1 + end + if self.widget.selected > #self.widget.list then + self.widget.selected = #self.widget.list + end + +end + +function GridBox:mousepressed(x, y, button, isTouch) + local widgetID = self:getWidgetAtPoint(x, y) + + if widgetID ~= nil then + self.widget.selected = widgetID + self:getFocus() + + if #self.widget.list > 0 and self.widget.selected > 1 and self.widget.selected <= #self.widget.list then + self.widget.list[self.widget.selected]:action() + end + end +end + +function GridBox:draw() + + for i,v in ipairs(self.slots) do + if self:haveWidget(i) then + local widgetx = self.x + (v.x * self.widget.w) + local widgety = self.y + (v.y * self.widget.h) + if self.widget.selected == v.widgetID and self:haveFocus() == true then + self.widget.list[v.widgetID]:drawSelected(widgetx, widgety) + else + self.widget.list[v.widgetID]:draw(widgetx, widgety) + end + end + end +end + +function GridBox:drawCursor() + self:updateView() + if (self.widget.selected >= 1 and self.widget.selected <= #self.widget.list) then + local slot = self:getWidgetSlot(self.widget.selected) + local w, h = self:getWidgetSize(slot) + local x = self.slots[slot].x * self.widget.w + local y = self.slots[slot].y * self.widget.h + menuutils.drawCursor(self.x + x, self.y + y, w, h) + end +end + +return GridBox diff --git a/sonic-radiance.love/core/modules/menusystem/init.lua b/sonic-radiance.love/core/modules/menusystem/init.lua new file mode 100644 index 0000000..db5ee4d --- /dev/null +++ b/sonic-radiance.love/core/modules/menusystem/init.lua @@ -0,0 +1,111 @@ +local MenuSystem = Object:extend() + +local cwd = (...):gsub('%.init$', '') .. "." + +MenuSystem.Parent = require(cwd .. "parent") +MenuSystem.ListBox = require(cwd .. "listbox") +MenuSystem.FlowBox = require(cwd .. "flowbox") +MenuSystem.Grid = require(cwd .. "grid") +MenuSystem.TextMenu = require(cwd .. "textmenu") + +MenuSystem.Widget = require(cwd .. "widgets") + + +--local VirtualPad = require "modules.virtualpad" + +function MenuSystem:new() + self.menus = {} + self.focusedMenu = "" +end + +function MenuSystem:reset() + self.menus = {} +end + +function MenuSystem:addMenu(name, menu) + self.menus[name] = menu +end + +function MenuSystem:update(dt) + self:removeDestroyedMenus() + for k,v in pairs(self.menus) do + v:update(dt) + v:updateWidgets(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 k,v in pairs(self.keys) do + if self.keys[k].isPressed then + self.menus[self.focusedMenu]:keyreleased(k) + end + end + end + end + +end + +function MenuSystem:setAllMenuVisibility(visibility) + for k,v in pairs(self.menus) do + v.isVisible = visibility + end +end + +function MenuSystem:setAllMenuActivity(activity) + for k,v in pairs(self.menus) do + v.isActive = activity + end +end + +function MenuSystem:removeDestroyedMenus() + -- On retire les entitées marquées comme supprimées + for k,v in pairs(self.menus) do + if (v.isDestroyed == true) then + self.menus[k] = nil + end + end +end + +function MenuSystem:keyreleased(key, code) + -- TODO:depreciated function +end + +function MenuSystem:mousemoved(x, y, dx, dy) + for k,v in pairs(self.menus) do + if v.isActive then + if (x > v.x) and (x < v.x + v.w) and (y > v.y) and (y < v.y + v.h) then + v:mousemoved(x - v.x, y - v.y) + break; + end + end + end +end + +function MenuSystem:mousepressed( x, y, button, istouch ) + for k,v in pairs(self.menus) do + if v.isActive then + if (x > v.x) and (x < v.x + v.w) and (y > v.y) and (y < v.y + v.h) then + v:mousepressed(x - v.x, y - v.y, button, istouch ) + break; + end + end + end +end + +function MenuSystem:draw(dt) -- On dessine les entitées + for k,v in pairs(self.menus) do + if (v.isVisible) then + v:draw(dt) + end + end + + if self.menus[self.focusedMenu] ~= nil then + if (self.menus[self.focusedMenu].isVisible) then + self.menus[self.focusedMenu]:drawCursor() + end + end + +end + +return MenuSystem diff --git a/sonic-radiance.love/core/modules/menusystem/listbox.lua b/sonic-radiance.love/core/modules/menusystem/listbox.lua new file mode 100644 index 0000000..944c465 --- /dev/null +++ b/sonic-radiance.love/core/modules/menusystem/listbox.lua @@ -0,0 +1,110 @@ +local cwd = (...):gsub('%.listbox$', '') .. "." +local Menu = require(cwd .. "parent") + +local menuutils = require(cwd .. "widgets.utils") + +local ListBox = Menu:extend() + +function ListBox:new(menusystem, name, x, y, w, h, slotNumber) + self.view = {} + self.view.slotNumber = slotNumber + self.view.firstSlot = 1 + ListBox.super.new(self, menusystem, name, x, y, w, h) + self.h = slotNumber * self.widget.h -- On fait en sorte que la hauteur + -- soit un multiple du nombre de slot et de leur hauteur +end + +function ListBox:updateWidgetSize() + self.widget.h = math.floor( self.h / self.view.slotNumber ) + self.widget.w = self.w +end + +function ListBox:update(dt) + self:updateView() +end + +function ListBox:updateView() + if self.widget.selected < self.view.firstSlot then + self.view.firstSlot = self.widget.selected + end + if self.widget.selected > self.view.firstSlot + self.view.slotNumber - 1 then + self.view.firstSlot = self.widget.selected - self.view.slotNumber + 1 + end + + if self.view.firstSlot < 1 then + self.view.firstSlot = 1 + end +end + +function ListBox:keyreleased(key, code) + + if key == 'up' then + self:moveCursor(self.widget.selected - 1) + end + + if key == 'down' then + self:moveCursor(self.widget.selected + 1) + end + + if key == "A" then + if (self.widget.selected >= 1 and self.widget.selected <= #self.widget.list) then + self.widget.list[self.widget.selected]:action() + end + end + + if key == "B" then + if (self.widget.cancel >= 1 and self.widget.cancel <= #self.widget.list) then + self.widget.list[self.widget.cancel]:action() + end + end + +end + +function ListBox:mousemoved(x, y) + local widget_selected = self.view.firstSlot + math.floor(y / self.widget.h) + + if widget_selected >= 1 and widget_selected <= #self.widget.list then + self.widget.selected = widget_selected + self:getFocus() + end +end + +function ListBox:mousepressed(x, y, button, isTouch) + local widget_selected = self.view.firstSlot + math.floor(y / self.widget.h) + + if widget_selected >= 1 and widget_selected <= #self.widget.list then + self.widget.selected = widget_selected + self:getFocus() + if #self.widget.list > 0 then + self.widget.list[self.widget.selected]:action() + end + end + +end + +function ListBox:draw() + self:updateView() + local widgety = self.y + for i,v in ipairs(self.widget.list) do + if (i >= self.view.firstSlot) and (i < self.view.firstSlot + self.view.slotNumber) then + v:draw(self.x, widgety, self.w, self.widget.h) + if self.widget.selected == i and self:haveFocus() == true then + v:drawSelected(self.x, widgety, self.w, self.widget.h) + else + v:draw(self.x, widgety, self.w, self.widget.h) + end + widgety = widgety + self.widget.h + end + end +end + +function ListBox:drawCursor() + self:updateView() + if (self.widget.selected >= 1 and self.widget.selected <= #self.widget.list) then + local w, h = self:getWidgetSize() + local y = (self.widget.selected - self.view.firstSlot) * h + menuutils.drawCursor(self.x,self.y + y, w, h) + end +end + +return ListBox diff --git a/sonic-radiance.love/core/modules/menusystem/parent.lua b/sonic-radiance.love/core/modules/menusystem/parent.lua new file mode 100644 index 0000000..a6bb2a5 --- /dev/null +++ b/sonic-radiance.love/core/modules/menusystem/parent.lua @@ -0,0 +1,179 @@ +local Menu = Object:extend() + +function Menu:new(menusystem, name, x, y, w, h) + self.menusystem = menusystem + self.name = name + + self.x = x + self.y = y + self.w = w + self.h = h + + self.widget = {} + self.widget.list = {} + self.widget.selected = 0 + self.widget.selectedPrevious = 0 + self.widget.cancel = 0 + self:updateWidgetSize() + + self.isDestroyed = false + self.isVisible = true + self.isActive = true + + self.sound = {} + self.sound.asset = nil + self.sound.active = false + + self:register() +end + +function Menu:getFocus() + self.menusystem.focusedMenu = self.name +end + +function Menu:haveFocus() + return (self.menusystem.focusedMenu == self.name) +end + +function Menu:register() + self.menusystem:addMenu(self.name, self) +end + +function Menu:setCancelWidget(id) + self.widget.cancel = #self.widget.list +end + +function Menu:updateWidgetSize() + self.widget.h = 0 + self.widget.w = 0 +end + +function Menu:getWidgetSize(id) + return self.widget.w, self.widget.h +end + +function Menu:cancelAction() + if (self.widget.cancel ~= 0) then + self.widget.list[self.widget.cancel]:action() + end +end + +function Menu:update(dt) + -- Cette fonction ne contient rien par défaut +end + +function Menu:clear() + self.widget.list = {} + self.widget.cancel = 0 +end + +function Menu:resize(x,y,w,h) + self.x = x + self.y = y + self.w = w + self.h = h + + self:updateWidgetSize() +end + +function Menu:destroy() + self.destroyed = true +end + +function Menu:draw() + -- nothing here +end + +function Menu:drawCursor() + -- nothing here +end + +function Menu:drawCanvas() + +end + +function Menu:keyreleased(key) + -- Cette fonction ne contient rien par défaut +end + +function Menu:mousemoved(x, y) + -- Cette fonction ne contient rien par défaut +end + +function Menu:mousepressed( x, y, button, istouch ) + -- Cette fonction ne contient rien par défaut +end + +function Menu:addWidget(newwidget) + if #self.widget.list == 0 then + self.widget.selected = 1 + end + table.insert(self.widget.list, newwidget) + self:updateWidgetsID() +end + +function Menu:updateWidgets(dt) + self:removeDestroyedWidgets() + for i,v in ipairs(self.widget.list) do + v.id = i + v:update(dt) + end +end + +function Menu:updateWidgetsID() + for i,v in ipairs(self.widget.list) do + v.id = i + end +end + +function Menu:removeDestroyedWidgets() -- On retire les widgets marquées comme supprimées + for i,v in ipairs(self.widget.list) do + if (v.destroyed == true) then + table.remove(self.widget.list, i) + end + end +end + +function Menu:setCursor(cursorid) + self.widget.selected = cursorid --math.max(1, math.min(cursorid, #self.widget.list)) +end + +function Menu:moveCursor(new_selected) + self:playSelectSound() + if new_selected < 1 then + self.widget.selected = #self.widget.list + new_selected + else + if new_selected > #self.widget.list then + self.widget.selected = new_selected - #self.widget.list + else + self.widget.selected = new_selected + end + end +end + +function Menu:setSound(soundasset) + self.sound.active = true + self.sound.asset = soundasset +end + +function Menu:playSelectSound() + if self.sound.active == true then + love.audio.stop( self.sound.asset ) + self.sound.asset:setVolume(core.options.data.audio.sfx / 100) + love.audio.play( self.sound.asset ) + end +end + +function Menu:resetView() + -- ne sert à rien ici, c'est juste pour éviter des crash +end + +function Menu:updateView() + -- ne sert à rien ici, c'est juste pour éviter des crash +end + +function Menu:moveView() + -- ne sert à rien ici, c'est juste pour éviter des crash +end + +return Menu diff --git a/sonic-radiance.love/core/modules/menusystem/textmenu.lua b/sonic-radiance.love/core/modules/menusystem/textmenu.lua new file mode 100644 index 0000000..6703039 --- /dev/null +++ b/sonic-radiance.love/core/modules/menusystem/textmenu.lua @@ -0,0 +1,221 @@ +local cwd = (...):gsub('%.textmenu$', '') .. "." +local Menu = require(cwd .. "parent") + +local TextMenu = Menu:extend() + +function TextMenu:new(menusystem, name, x, y, font, slots) + self.slots = slots + TextMenu.super.new(self, menusystem, name, x, y, 0, 0) + self.ox = x + self.oy = y + self.font = font + self.align = "left" + + self.begin = 1 + + self:getBoundingBox() +end + +function TextMenu:getBoundingBox() + self:setWidthAuto() + self.widget.h = self.font:getHeight() + self.h = self.widget.h * self.slots + + if self.align == "right" then + self.x = self.ox - self.w + elseif self.align == "center" then + self.x = self.ox - self.w / 2 + else + self.x = self.ox + end + + self.y = self.oy +end + +function TextMenu:centerText() + self:setAlign("center") +end + +function TextMenu:setAlign(align) + self.align = align + self.font:setAlign("center") +end + +function TextMenu:update(dt) + self:getBoundingBox() + if self.widget.selected ~= 0 then + if self.widget.selected < self.begin then + self.begin = self.widget.selected + end + if self.widget.selected > self.begin + self.slots - 1 then + self.begin = self.widget.selected - self.slots + 1 + end + end + + if self.begin < 1 then + self.begin = 1 + end +end + +function TextMenu:setWidthAuto() + local width = self.w + + for i,v in ipairs(self.widget.list) do + local stringWidth = self.font:getWidth(v.beginlabel .. v.label .. v.endlabel) + width = math.max(stringWidth, width) + end + if width ~= self.w then + self.canvas.needRedraw = true + end + self.w = width +end + +function TextMenu:getWidth() + self:setWidthAuto() + return self.w +end + +function TextMenu:getHeight() + return self.h +end + +function TextMenu:keyreleased(key, code) + + if key == 'up' then + self:moveCursor(self.widget.selected - 1) + end + + if key == 'down' then + self:moveCursor(self.widget.selected + 1) + end + + if key == "A" then + if (self.widget.selected > 0) and (self.widget.selected <= #self.widget.list) then + self.widget.list[self.widget.selected]:action() + end + end + + if key == "B" then + self:cancelAction() + end + +end + +function TextMenu:mousemoved(x, y) + local selectedPrevous = self.widget.selected + self.widget.selected = self.begin + math.floor(y / self.widget.h) + if self.widget.selected < 1 then + self.widget.selected = 1 + end + if self.widget.selected > #self.widget.list then + self.widget.selected = #self.widget.list + end + + if self.widget.selected ~= selectedPrevious then + self.canvas.needRedraw = true + end +end + +function TextMenu:mousepressed(x, y, button, isTouch) + self.widget.selected = self.begin + math.floor(y / self.widget.h) + if self.widget.selected < 1 then + self.widget.selected = 1 + end + if self.widget.selected > #self.widget.list then + self.widget.selected = #self.widget.list + end + if #self.widget.list > 0 then + self.widget.list[self.widget.selected]:action() + end + + if self.widget.selected ~= selectedPrevious then + self.canvas.needRedraw = true + end +end + +function TextMenu:drawCanvas() + print("redraw menu") + + self.canvas.texture = love.graphics.newCanvas(self.w, self.h) + love.graphics.setCanvas( self.canvas.texture ) + + local ox, x + + local widgety = 0 + local ox = self.w / 2 + local x = 0 + + self.font:set() + for i, v in ipairs(self.widget.list) do + if (i >= self.begin) and (i < self.begin + self.slots) then + self:drawWidget(i, widgety) + + widgety = widgety + self.widget.h + end + end + utils.draw.resetColor() + + love.graphics.setCanvas( ) +end + +function TextMenu:drawWidget(widgetID, y) + local widget = self.widget.list[widgetID] + print(widget) + if widget.canvas.needRedraw == true then + self:drawWidgetCanvas(widget) + widget.canvas.needRedraw = false + end + + if self.widget.selected == widgetID and self.focus == true then + love.graphics.setColor(1, 1, 0, 1) + else + love.graphics.setColor(1, 1, 1, 1) + end + + love.graphics.draw(widget.canvas.texture, 0, y) +end + +function TextMenu:drawWidgetCanvas(widget) + widget.canvas.texture = love.graphics.newCanvas(self.w, self.widget.h) + + love.graphics.setCanvas( widget.canvas.texture ) + + self.font:draw(widget.label, math.floor(self.w / 2), 0, -1, self.align) + self.font:draw(widget.beginlabel, math.floor(0), 0, -1, "left") + self.font:draw(widget.endlabel, math.floor(self.w), 0, -1, "right") + + love.graphics.setCanvas( self.canvas.texture ) +end + +function TextMenu:resetView() + self.begin = 1 + self.canvas.needRedraw = true +end + +function Menu:moveView(begin, absolute) + --local absolute = absolute or true + self.widget.selected = 0 + + if (absolute) then + self.begin = begin + else + self.begin = self.begin + begin + end + -- ne sert à rien ici, c'est juste pour éviter des crash + + self.canvas.needRedraw = true +end + +function Menu:getView() + return self.begin +end + +function Menu:isViewAtBeggining() + return (self.begin <= 1) +end + +function Menu:isViewAtEnd() + return ((self.begin + self.slots) > (#self.widget.list)) +end + +return TextMenu diff --git a/sonic-radiance.love/core/modules/menusystem/widgets/init.lua b/sonic-radiance.love/core/modules/menusystem/widgets/init.lua new file mode 100644 index 0000000..03006df --- /dev/null +++ b/sonic-radiance.love/core/modules/menusystem/widgets/init.lua @@ -0,0 +1,98 @@ +local Widget = {} + +BaseWidget = Object:extend() +TextWidget = BaseWidget:extend() + +function BaseWidget:new(menu) + self.menu = menu + + self.destroyed = false + self.selectable = false + self.selection_margin = 0 + self.margin = 2 + + self:register() + + self.canvas = {} + self.canvas.texture = nil + self.canvas.needRedraw = true +end + +function BaseWidget:register() + self.menu:addWidget(self) +end + +function BaseWidget:redrawCanvas() + self.width, self.height = self.menu:getWidgetSize(self.id) + + self.canvas.texture = love.graphics.newCanvas(self.width, self.height) + love.graphics.setCanvas( self.canvas.texture ) + + self:drawCanvas() + self.canvas.needRedraw = false + + love.graphics.setCanvas( ) +end + +function BaseWidget:drawCanvas() + self.r = love.math.random(128)/256 + self.g = love.math.random(128)/256 + self.b = love.math.random(128)/256 + + love.graphics.setColor(self.r, self.g, self.b, 70) + love.graphics.rectangle("fill", 0, 0, self.width, self.height) + love.graphics.setColor(self.r, self.g, self.b) + love.graphics.rectangle("line", 0, 0, self.width, self.height) + utils.graphics.resetColor() +end + +function BaseWidget:selectAction() + -- Do nothing +end + +function BaseWidget:draw(x, y) + if self.canvas.texture ~= nil then + utils.graphics.resetColor() + love.graphics.draw(self.canvas.texture, x, y) + end +end + +function BaseWidget:drawSelected(x,y,w,h) + self:draw(x, y, w, h) +end + +function BaseWidget:update(dt) + if (self.canvas.needRedraw) then + self:redrawCanvas() + end + -- N/A +end + +function BaseWidget:action() + --self:destroy() +end + +function BaseWidget:destroy() + self.destroyed = true +end + +-- Simple text widget + +function TextWidget:new(menu, font, label) + TextWidget.super.new(self, menu) + self.font = font + self.label = label +end + +function TextWidget:drawCanvas() + local w, h + w = math.floor(self.width / 2) + h = math.floor(self.height / 2) - (self.font:getHeight() / 2) + self.font:draw(self.label, w, h, -1, "center") +end + + +Widget.Base = BaseWidget +Widget.Text = TextWidget + +return Widget diff --git a/sonic-radiance.love/core/modules/menusystem/widgets/utils.lua b/sonic-radiance.love/core/modules/menusystem/widgets/utils.lua new file mode 100644 index 0000000..ab4a48c --- /dev/null +++ b/sonic-radiance.love/core/modules/menusystem/widgets/utils.lua @@ -0,0 +1,34 @@ +local menuUtils = {} + +function menuUtils.drawCursor(x, y, w, h) + love.graphics.setColor(0,0,0) + + love.graphics.rectangle("fill", x, y, 4, 8) + love.graphics.rectangle("fill", x, y, 8, 4) + + love.graphics.rectangle("fill", x + w, y, -4, 8) + love.graphics.rectangle("fill", x + w, y, -8, 4) + + love.graphics.rectangle("fill", x, y + h, 4, -8) + love.graphics.rectangle("fill", x, y + h, 8, -4) + + love.graphics.rectangle("fill", x + w, y + h, -4, -8) + love.graphics.rectangle("fill", x + w, y + h, -8, -4) + + love.graphics.setColor(255,255,255) + + love.graphics.rectangle("fill", x + 1, y + 1, 2, 6) + love.graphics.rectangle("fill", x + 1, y + 1, 6, 2) + + love.graphics.rectangle("fill", x + w - 1, y + 1, -2, 6) + love.graphics.rectangle("fill", x + w - 1, y + 1, -6, 2) + + love.graphics.rectangle("fill", x + 1, y + h - 1, 2, -6) + love.graphics.rectangle("fill", x + 1, y + h - 1, 6, -2) + + love.graphics.rectangle("fill", x + w - 1, y + h - 1, -2, -6) + love.graphics.rectangle("fill", x + w - 1, y + h - 1, -6, -2) + +end + +return menuUtils diff --git a/sonic-radiance.love/core/modules/scenes.lua b/sonic-radiance.love/core/modules/scenes.lua index a46faff..c87f29e 100644 --- a/sonic-radiance.love/core/modules/scenes.lua +++ b/sonic-radiance.love/core/modules/scenes.lua @@ -24,12 +24,15 @@ local Scene = Object:extend() local Assets = require "core.modules.assets" +local MenuSystem = require "core.modules.menusystem" function Scene:new() self.mouse = {} self.mouse.x, self.mouse.y = core.screen:getMousePosition() - self.assets = Assets() + self.assets = Assets() + self.menusystem = MenuSystem() + self.keys = core.input:getKeyList() end function Scene:register() @@ -56,4 +59,9 @@ function Scene:clear() end +function Scene:flushKeys() + core.input:flushKeys() + self.keys = core.input.keys +end + return Scene diff --git a/sonic-radiance.love/core/scenemanager.lua b/sonic-radiance.love/core/scenemanager.lua index a3b5362..5d403ca 100644 --- a/sonic-radiance.love/core/scenemanager.lua +++ b/sonic-radiance.love/core/scenemanager.lua @@ -34,7 +34,9 @@ function SceneManager:update(dt) if (self.currentScene ~= nil) then local keys = self.controller.input.keys self.currentScene.keys = keys + self.currentScene.menusystem.keys = keys self.currentScene.assets:update(dt) + self.currentScene.menusystem:update(dt) self.currentScene:update(dt) end end @@ -43,10 +45,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 function SceneManager:mousepressed( x, y, button, istouch ) self.currentScene:mousepressed( x, y, button, istouch ) + self.currentScene.menusystem:mousepressed( x, y, button, istouch ) end function SceneManager:clearScene() @@ -57,6 +61,7 @@ function SceneManager:draw() self.controller.screen:apply() if (self.currentScene ~= nil) then self.currentScene:draw(dt) + self.currentScene.menusystem:draw() end self.controller.screen:cease() end diff --git a/sonic-radiance.love/core/screen.lua b/sonic-radiance.love/core/screen.lua index 1d8d3dc..4e962a8 100644 --- a/sonic-radiance.love/core/screen.lua +++ b/sonic-radiance.love/core/screen.lua @@ -26,14 +26,12 @@ local ScreenManager = Object:extend() local CScreen = require "libs.cscreen" -local SCREEN_HEIGHT = 240 -local SCREEN_WIDTH = 424 - function ScreenManager:new(controller) self.controller = controller self.data = self.controller.options.data.video + self.width, self.height = love.graphics.getDimensions() self:applySettings() - CScreen.init(SCREEN_WIDTH, SCREEN_HEIGHT, true) + CScreen.init(self.width, self.height, true) CScreen.setColor(0, 0, 0, 1) love.graphics.setDefaultFilter( "nearest", "nearest", 1 ) @@ -46,7 +44,7 @@ function ScreenManager:applySettings() flags.vsync = self.data.vsync flags.borderless = (self.data.border == false) - love.window.setMode(SCREEN_WIDTH * self.data.resolution, SCREEN_HEIGHT * self.data.resolution, flags) + love.window.setMode(self.width * self.data.resolution, self.height * self.data.resolution, flags) love.window.setFullscreen( self.data.fullscreen ) local width, height = love.window.getMode() @@ -61,6 +59,10 @@ function ScreenManager:getMousePosition() return CScreen.project(love.mouse.getX(), love.mouse.getY()) end +function ScreenManager:getDimensions() + return self.width, self.height +end + function ScreenManager:apply() CScreen.apply() end