diff --git a/src/gstates/gstate.lua b/src/gstates/gstate.lua index ca2abf3..a8f4c33 100644 --- a/src/gstates/gstate.lua +++ b/src/gstates/gstate.lua @@ -20,13 +20,14 @@ local GameState = make_class(Drawable) function GameState:_init(name, index) Drawable._init(self) - self.name = name - self.index = index + self.name = name + self.index = index + self.next_state = self.index end function GameState:update(_) - return self.index + return self.next_state end diff --git a/src/gstates/menu.lua b/src/gstates/menu.lua index 60f25f8..fdf3e94 100644 --- a/src/gstates/menu.lua +++ b/src/gstates/menu.lua @@ -5,82 +5,101 @@ local love = require 'love' local assets = require 'src.utils.asstmngr' local make_class = require 'src.utils.classes' +local constants = require 'src.gstates.menus.const' local GameState = require 'src.gstates.gstate' +local MainMenu = require 'src.gstates.menus.mainmenu' +local OptionsMenu = require 'src.gstates.menus.options' local Fader = require 'src.graphics.fader' -local Sprite = require 'src.graphics.sprite' local Cursor = require 'src.ui.cursor' local Font = require 'src.ui.font' local SoundEffect = require 'src.sound.sfx' -local VBox = require 'src.ui.vbox' -local Color = require 'src.utils.color' ------------------------------------------------------------------------------ -- Class definitions ------------------------------------------------------------------------------ -local MainMenu = make_class(GameState) +local Menu = make_class(GameState) ------------------------------------------------------------------------------ --- Class methods +-- Class methods ------------------------------------------------------------------------------ -function MainMenu:_init(name, index) +function Menu:_init(name, index) GameState._init(self, name, index) - self.next_state = self.index - self.fade = Fader() + self.fade = Fader() + self.current_menu = constants.MAIN_MENU + self.next_menu = constants.MAIN_MENU + self.all_loaded = false -- Create sprites and buttons. - self.background = Sprite('imgs/concb03.png') self.btn_font = Font('fonts/Concrete.ttf') self.title_font = Font('fonts/BBrick.ttf', 35) - -- Create UI elements. - self.btns = VBox(15, 5, love.graphics.getWidth()) - self.btns:add_label('LoveDOS', self.title_font, Color(215, 0, 0), true) - self.btns:add_text_button('New Game', self.btn_font) - self.btns:add_text_button('Load Game', self.btn_font) - self.btns:add_text_button('Options', self.btn_font) - self.btns:add_text_button('Help & Story', self.btn_font) - self.btns:add_text_button('Quit', self.btn_font, function() self.next_state = -1 end) - -- Create a mouse cursor object at the current mouse position. local mx, my = love.mouse.getPosition() - self.cursor = Cursor(mx, my) + self.cursor = Cursor(mx, my) -- Create sound effects. self.bgm = SoundEffect('bgm/eskisky.wav') + -- Create the sub-menus. + self.menus = { } + self.menus[constants.MAIN_MENU] = MainMenu(self, self.title_font, self.btn_font) + self.menus[constants.OPTIONS_MENU] = OptionsMenu(self, self.title_font, self.btn_font) + -- Register all assets. assets:register(self.name, self.btn_font) assets:register(self.name, self.title_font) - assets:register(self.name, self.background) assets:register(self.name, self.cursor) assets:register(self.name, self.bgm) - assets:register(self.name, self.btns) end -function MainMenu:update(dt) - if assets:done(self.name) then - if not self.bgm:isPlaying() then self.bgm:play() end +function Menu:update(dt) + if not self.bgm:isPlaying() then self.bgm:play() end + + if self.all_loaded then + self.menus[self.current_menu]:update(dt) + + -- If the game state changed then trigger a fade out. + if self.next_menu ~= self.current_menu and self.fade.done then + self.fade:fade_out() + end - -- Update the fader. self.fade:update(dt) + + -- Update the game state. + if self.menus[self.next_menu] == nil then + error(string.format('%s: switched to unknown menu', self.next_menu)) + else + -- If the new state exists then unload it's data and set the new state. + if self.next_menu ~= self.current_menu and self.fade.done then + self.current_menu = self.next_menu + self.fade:fade_in() + end + end else + local done = true + assets:update(self.name) + + for _, v in pairs(self.menus) do + assets:update(v.name) + done = done and assets:done(v.name) + end + + self.all_loaded = assets:done(self.name) and done end return self.next_state end -function MainMenu:draw() - if assets:done(self.name) then - self.background:draw() - - self.btns:draw() +function Menu:draw() + if self.all_loaded then + self.menus[self.current_menu]:draw() self.cursor:draw() self.fade:draw() else @@ -89,23 +108,23 @@ function MainMenu:draw() end -function MainMenu:keypressed(_) -end - - -function MainMenu:mousemoved(x, y, dx, dy) - self.btns:mousemoved(x, y, dx, dy) +function Menu:mousemoved(x, y, dx, dy) + self.menus[self.current_menu]:mousemoved(x, y, dx, dy) self.cursor:mousemoved(x, y, dx, dy) end -function MainMenu:mousepressed(x, y, btn) - self.btns:mousepressed(x, y, btn) +function Menu:mousepressed(x, y, btn) + if self.fade.done then + self.menus[self.current_menu]:mousepressed(x, y, btn) + end end -function MainMenu:mousereleased(x, y, btn) - self.btns:mousereleased(x, y, btn) +function Menu:mousereleased(x, y, btn) + if self.fade.done then + self.menus[self.current_menu]:mousereleased(x, y, btn) + end end @@ -113,4 +132,4 @@ end -- Module return ------------------------------------------------------------------------------ -return MainMenu +return Menu diff --git a/src/gstates/menus/base.lua b/src/gstates/menus/base.lua new file mode 100644 index 0000000..a82e576 --- /dev/null +++ b/src/gstates/menus/base.lua @@ -0,0 +1,75 @@ +------------------------------------------------------------------------------ +-- Imports +------------------------------------------------------------------------------ + +local love = require 'love' +local assets = require 'src.utils.asstmngr' +local make_class = require 'src.utils.classes' +local GameState = require 'src.gstates.gstate' +local Sprite = require 'src.graphics.sprite' +local VBox = require 'src.ui.vbox' + + +------------------------------------------------------------------------------ +-- Class definitions +------------------------------------------------------------------------------ + +local BaseMenu = make_class(GameState) + + +------------------------------------------------------------------------------ +-- Class methods +------------------------------------------------------------------------------ + +function BaseMenu:_init(parent, name, index, bckg) + GameState._init(self, name, index) + + self.parent = parent + + -- Create background sprite and container. + self.background = Sprite(bckg) + self.container = VBox(15, 5, love.graphics.getWidth()) + + -- Register the background and container into the asset manager. + assets:register(self.name, self.background) + assets:register(self.name, self.container) +end + + +function BaseMenu:mousemoved(x, y, dx, dy) + self.container:mousemoved(x, y, dx, dy) +end + + +function BaseMenu:mousepressed(x, y, btn) + self.container:mousepressed(x, y, btn) +end + + +function BaseMenu:mousereleased(x, y, btn) + self.container:mousereleased(x, y, btn) +end + + +function BaseMenu:update() + if not assets:done(self.name) then + assets:update(self.name) + end +end + + +function BaseMenu:draw() + if assets:done(self.name) then + self.background:draw() + self.container:draw() + else + assets:draw() + end +end + + +------------------------------------------------------------------------------ +-- Module return +------------------------------------------------------------------------------ + +return BaseMenu diff --git a/src/gstates/menus/const.lua b/src/gstates/menus/const.lua new file mode 100644 index 0000000..9f08773 --- /dev/null +++ b/src/gstates/menus/const.lua @@ -0,0 +1,17 @@ +------------------------------------------------------------------------------ +-- Constants +------------------------------------------------------------------------------ + +local constants = { + MAIN_MENU = 1, + OPTIONS_MENU = 2, + STORY = 3, + LOAD_MENU = 4, +} + + +------------------------------------------------------------------------------ +-- Module return +------------------------------------------------------------------------------ + +return constants diff --git a/src/gstates/menus/mainmenu.lua b/src/gstates/menus/mainmenu.lua new file mode 100644 index 0000000..07667c7 --- /dev/null +++ b/src/gstates/menus/mainmenu.lua @@ -0,0 +1,39 @@ +------------------------------------------------------------------------------ +-- Imports +------------------------------------------------------------------------------ + +local make_class = require 'src.utils.classes' +local constants = require 'src.gstates.menus.const' +local BaseMenu = require 'src.gstates.menus.base' +local Color = require 'src.utils.color' + + +------------------------------------------------------------------------------ +-- Class definitions +------------------------------------------------------------------------------ + +local MainMenu = make_class(BaseMenu) + + +------------------------------------------------------------------------------ +-- Main Menu Class methods +------------------------------------------------------------------------------ + +function MainMenu:_init(parent, title_font, button_font) + BaseMenu._init(self, parent, "Main Menu", constants.MAIN_MENU, 'imgs/concb03.png') + + -- Create UI elements of the main menu. + self.container:add_label('LoveDOS', title_font, Color(215, 0, 0), true) + self.container:add_text_button('New Game', button_font) + self.container:add_text_button('Load Game', button_font) + self.container:add_text_button('Options', button_font, function() parent.next_menu = constants.OPTIONS_MENU end) + self.container:add_text_button('Help & Story', button_font) + self.container:add_text_button('Quit', button_font, function() parent.next_state = -1 end) +end + + +------------------------------------------------------------------------------ +-- Module return +------------------------------------------------------------------------------ + +return MainMenu diff --git a/src/gstates/menus/options.lua b/src/gstates/menus/options.lua new file mode 100644 index 0000000..ce8a12c --- /dev/null +++ b/src/gstates/menus/options.lua @@ -0,0 +1,39 @@ +------------------------------------------------------------------------------ +-- Imports +------------------------------------------------------------------------------ + +local make_class = require 'src.utils.classes' +local constants = require 'src.gstates.menus.const' +local BaseMenu = require 'src.gstates.menus.base' +local Color = require 'src.utils.color' + + +------------------------------------------------------------------------------ +-- Class definitions +------------------------------------------------------------------------------ + +local OptionsMenu = make_class(BaseMenu) + + +------------------------------------------------------------------------------ +-- Class methods +------------------------------------------------------------------------------ + +function OptionsMenu:_init(parent, title_font, button_font) + BaseMenu._init(self, parent, "Options Menu", constants.OPTIONS_MENU, 'imgs/cpu.png') + + -- Create UI elements of the main menu. + self.container:add_label('Options', title_font, Color(215, 0, 0), true) + self.container:add_label('Enable Permadeath', button_font) + self.container:add_label('Controls', button_font) + self.container:add_label('Sound Volume', button_font) + self.container:add_label('Music Volume', button_font) + self.container:add_text_button('Go Back', button_font, function() parent.next_menu = constants.MAIN_MENU end) +end + + +------------------------------------------------------------------------------ +-- Module return +------------------------------------------------------------------------------ + +return OptionsMenu diff --git a/src/sound/sfx.lua b/src/sound/sfx.lua index b1a7421..ca81cbd 100644 --- a/src/sound/sfx.lua +++ b/src/sound/sfx.lua @@ -26,7 +26,9 @@ end function SoundEffect:load() - self.sfx = love.audio.newSource(self.file_name) + if not self:is_loaded() then + self.sfx = love.audio.newSource(self.file_name) + end end @@ -36,6 +38,11 @@ function SoundEffect:unload() end +function SoundEffect:is_loaded() + return self.sfx ~= nil +end + + function SoundEffect:setVolume(volume) if self.sfx ~= nil then self.sfx:setVolume(volume) end end diff --git a/src/states.lua b/src/states.lua index d7d4a6b..e93a73a 100644 --- a/src/states.lua +++ b/src/states.lua @@ -2,8 +2,8 @@ -- Imports ------------------------------------------------------------------------------ -local Intro = require 'src.gstates.intro' -local MainMenu = require 'src.gstates.menu' +local Intro = require 'src.gstates.intro' +local Menu = require 'src.gstates.menu' ------------------------------------------------------------------------------ @@ -13,7 +13,7 @@ local MainMenu = require 'src.gstates.menu' -- Table of all valid game states. local states = { Intro('intro', 1), - MainMenu('menu', 2), + Menu('menu', 2), } diff --git a/src/utils/asstmngr.lua b/src/utils/asstmngr.lua index 4e7ec3e..28ed1d3 100644 --- a/src/utils/asstmngr.lua +++ b/src/utils/asstmngr.lua @@ -65,14 +65,18 @@ end function AssetManager:update(owner) if self.assets[owner] ~= nil then - if self.co == nil then - self.co = coroutine.create(_load) + if self.assets[owner].co == nil then + self.assets[owner].co = coroutine.create(_load) end - local errorfree, retval = coroutine.resume(self.co, self, owner) + local errorfree, retval = coroutine.resume(self.assets[owner].co, self, owner) if errorfree then self.assets[owner].done = retval + + if retval then + self.assets[owner].co = nil + end else error(retval) end @@ -96,6 +100,7 @@ function AssetManager:register(owner, asset) if self.assets[owner] == nil then self.assets[owner] = { done = false, + co = nil, } end