diff --git a/README.md b/README.md index 253606d..f5f5e57 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ A dungeon crawler game made with LoveDOS for the DOSember Game Jam https://itch. ### Music -- [Dogs of Cyberspace by congusbongus](https://modarchive.org/index.php?request=view_by_moduleid&query=207032) +- [Eskisky Zhi by Immorpher](https://immorpher.bandcamp.com/track/eskisky-zhi) ### Fonts diff --git a/bgm/dogs.wav b/bgm/dogs.wav deleted file mode 100644 index add4a69..0000000 Binary files a/bgm/dogs.wav and /dev/null differ diff --git a/bgm/eskisky.wav b/bgm/eskisky.wav new file mode 100644 index 0000000..20c2116 Binary files /dev/null and b/bgm/eskisky.wav differ diff --git a/src/gstates/gstate.lua b/src/gstates/gstate.lua index be47ab2..516841f 100644 --- a/src/gstates/gstate.lua +++ b/src/gstates/gstate.lua @@ -3,13 +3,13 @@ ------------------------------------------------------------------------------ local make_class = require 'src.utils.classes' - +local Drawable = require 'src.ui.drawable' ------------------------------------------------------------------------------ -- Class definitions ------------------------------------------------------------------------------ -local GameState = make_class() +local GameState = make_class(Drawable) ------------------------------------------------------------------------------ @@ -17,13 +17,9 @@ local GameState = make_class() ------------------------------------------------------------------------------ function GameState:_init(name, index) + Drawable._init(self) self.name = name self.index = index - self.valid = false -end - - -function GameState:load() end @@ -32,37 +28,6 @@ function GameState:update(_) end -function GameState:draw() -end - - -function GameState:unload() -end - - -function GameState:keypressed(_, _ , _) -end - - -function GameState:textinput(_) -end - - -function GameState:keyreleased(_, _) -end - - -function GameState:mousemoved(_, _, _, _) -end - - -function GameState:mousepressed(_, _, _) -end - - -function GameState:mousereleased(_, _, _) -end - ------------------------------------------------------------------------------ -- Module return ------------------------------------------------------------------------------ diff --git a/src/gstates/intro.lua b/src/gstates/intro.lua index 7d0c13c..4048eb4 100644 --- a/src/gstates/intro.lua +++ b/src/gstates/intro.lua @@ -2,11 +2,11 @@ -- Imports ------------------------------------------------------------------------------ -local love = require 'love' -local make_class = require 'src.utils.classes' -local GameState = require 'src.gstates.gstate' -local Fader = require 'src.utils.fader' - +local make_class = require 'src.utils.classes' +local GameState = require 'src.gstates.gstate' +local Sprite = require 'src.ui.sprite' +local Fader = require 'src.utils.fader' +local SoundEffect = require 'src.utils.sfx' ------------------------------------------------------------------------------ -- Class definitions @@ -25,18 +25,27 @@ function Intro:_init(name, index) self.fade = Fader() self.stage = 0 self.timer = 0 + + self.splash = Sprite('imgs/splash.png') + self.author = Sprite('imgs/wally.png') + self.title = Sprite('imgs/title.png') + + self.splash_snd = SoundEffect('snd/jachiev.wav') + self.author_snd = SoundEffect('snd/alang.wav') + self.title_snd = SoundEffect('snd/ablhole.wav') end function Intro:load() - self.splash = love.graphics.newImage('imgs/splash.png') - self.author = love.graphics.newImage('imgs/wally.png') - self.title = love.graphics.newImage('imgs/title.png') - self.splash_snd = love.audio.newSource('snd/jachiev.wav') - self.author_snd = love.audio.newSource('snd/alang.wav') - self.title_snd = love.audio.newSource('snd/ablhole.wav') - self.valid = true + -- Load all assets. + self.splash:load() + self.author:load() + self.title:load() + self.splash_snd:load() + self.author_snd:load() + self.title_snd:load() + -- Play the initial sound effect. self.splash_snd:play() end @@ -89,12 +98,10 @@ end function Intro:draw() - if self.valid then - -- If there is data to draw, then draw the current stage's backdrop. - if self.stage == 0 then love.graphics.draw(self.splash, 0, 0) - elseif self.stage == 1 then love.graphics.draw(self.author, 0, 0) - elseif self.stage == 2 then love.graphics.draw(self.title, 0, 0) end - end + -- If there is data to draw, then draw the current stage's backdrop. + if self.stage == 0 then self.splash:draw() + elseif self.stage == 1 then self.author:draw() + elseif self.stage == 2 then self.title:draw() end -- Draw the fader if needed. self.fade:draw() @@ -102,13 +109,13 @@ end function Intro:unload() - self.splash = nil - self.author = nil - self.title = nil - self.splash_snd = nil - self.author_snd = nil - self.title_snd = nil - self.valid = false + -- Null all assets so they can be claimed by the GC. + self.splash:unload() + self.author:unload() + self.title:unload() + self.splash_snd:unload() + self.author_snd:unload() + self.title_snd:unload() end diff --git a/src/gstates/menu.lua b/src/gstates/menu.lua new file mode 100644 index 0000000..a43f9d2 --- /dev/null +++ b/src/gstates/menu.lua @@ -0,0 +1,86 @@ +------------------------------------------------------------------------------ +-- Imports +------------------------------------------------------------------------------ + +local love = require 'love' +local make_class = require 'src.utils.classes' +local GameState = require 'src.gstates.gstate' +local Fader = require 'src.utils.fader' +local Cursor = require 'src.ui.cursor' +local SoundEffect = require 'src.utils.sfx' + + +------------------------------------------------------------------------------ +-- Class definitions +------------------------------------------------------------------------------ + +local MainMenu = make_class(GameState) + + +------------------------------------------------------------------------------ +-- Class methods +------------------------------------------------------------------------------ + +function MainMenu:_init(name, index) + GameState._init(self, name, index) + self.skip = false + self.fade = Fader() + + -- Create a mouse cursor object at the current mouse position. + local mx, my = love.mouse.getPosition() + self.cursor = Cursor(mx, my) + + -- Create sound effects. + self.bgm = SoundEffect('bgm/eskisky.wav') +end + + +function MainMenu:load() + -- Load sprites. + self.cursor:load() + + -- Load sound effects and start playing the background music + self.bgm:load() + self.bgm:play() +end + + +function MainMenu:update(dt) + -- Update the fader. + self.fade:update(dt) + + -- Move on to the next game state if the user skipped the intro or all stages are complete. + if not self.skip then return self.index else return -1 end +end + + +function MainMenu:draw() + self.cursor:draw() + self.fade:draw() +end + + +function MainMenu:unload() + self.cursor:unload() + self.bgm:unload() +end + + +function MainMenu:keypressed(key) + -- Skip the intro on any key press. + if key == "escape" then + self.skip = true + end +end + + +function MainMenu:mousemoved(x, y, dx, dy) + self.cursor:mousemoved(x, y, dx, dy) +end + + +------------------------------------------------------------------------------ +-- Module return +------------------------------------------------------------------------------ + +return MainMenu diff --git a/src/states.lua b/src/states.lua index a8d7b82..d7d4a6b 100644 --- a/src/states.lua +++ b/src/states.lua @@ -2,7 +2,8 @@ -- Imports ------------------------------------------------------------------------------ -local Intro = require 'src.gstates.intro' +local Intro = require 'src.gstates.intro' +local MainMenu = require 'src.gstates.menu' ------------------------------------------------------------------------------ @@ -12,6 +13,7 @@ local Intro = require 'src.gstates.intro' -- Table of all valid game states. local states = { Intro('intro', 1), + MainMenu('menu', 2), } diff --git a/src/ui/cursor.lua b/src/ui/cursor.lua new file mode 100644 index 0000000..15c89cd --- /dev/null +++ b/src/ui/cursor.lua @@ -0,0 +1,35 @@ +------------------------------------------------------------------------------ +-- Imports +------------------------------------------------------------------------------ + +local make_class = require 'src.utils.classes' +local Sprite = require 'src.ui.sprite' + + +------------------------------------------------------------------------------ +-- Class definitions +------------------------------------------------------------------------------ + +local Cursor = make_class(Sprite) + + +------------------------------------------------------------------------------ +-- Class methods +------------------------------------------------------------------------------ + +function Cursor:_init(x, y) + Sprite._init(self, 'imgs/pointer.png', x, y) +end + + +function Cursor:mousemoved(x, y) + self.x = x + self.y = y +end + + +------------------------------------------------------------------------------ +-- Module return +------------------------------------------------------------------------------ + +return Cursor diff --git a/src/ui/drawable.lua b/src/ui/drawable.lua new file mode 100644 index 0000000..ec0cf6a --- /dev/null +++ b/src/ui/drawable.lua @@ -0,0 +1,66 @@ +------------------------------------------------------------------------------ +-- Imports +------------------------------------------------------------------------------ + +local make_class = require 'src.utils.classes' + + +------------------------------------------------------------------------------ +-- Class definitions +------------------------------------------------------------------------------ + +local Drawable = make_class() + + +------------------------------------------------------------------------------ +-- Class methods +------------------------------------------------------------------------------ + +function Drawable:_init() +end + + +function Drawable:load() +end + + +function Drawable:update(_) +end + + +function Drawable:draw() +end + + +function Drawable:unload() +end + + +function Drawable:keypressed(_, _ , _) +end + + +function Drawable:textinput(_) +end + + +function Drawable:keyreleased(_, _) +end + + +function Drawable:mousemoved(_, _, _, _) +end + + +function Drawable:mousepressed(_, _, _) +end + + +function Drawable:mousereleased(_, _, _) +end + +------------------------------------------------------------------------------ +-- Module return +------------------------------------------------------------------------------ + +return Drawable diff --git a/src/ui/sprite.lua b/src/ui/sprite.lua new file mode 100644 index 0000000..a964118 --- /dev/null +++ b/src/ui/sprite.lua @@ -0,0 +1,48 @@ +------------------------------------------------------------------------------ +-- Imports +------------------------------------------------------------------------------ + +local love = require 'love' +local make_class = require 'src.utils.classes' +local Drawable = require 'src.ui.drawable' + +------------------------------------------------------------------------------ +-- Class definitions +------------------------------------------------------------------------------ + +local Sprite = make_class(Drawable) + + +------------------------------------------------------------------------------ +-- Class methods +------------------------------------------------------------------------------ + +function Sprite:_init(sprite_name, x, y) + self.sprite_name = sprite_name + self.x = (x ~= nil and x) or 0 + self.y = (y ~= nil and y) or 0 +end + + +function Sprite:load() + self.sprite = love.graphics.newImage(self.sprite_name) +end + + +function Sprite:draw() + if self.sprite ~= nil then + love.graphics.draw(self.sprite, self.x, self.y) + end +end + + +function Sprite:unload() + self.sprite = nil +end + + +------------------------------------------------------------------------------ +-- Module return +------------------------------------------------------------------------------ + +return Sprite diff --git a/src/utils/fader.lua b/src/utils/fader.lua index 0bf4cc8..ea2cee4 100644 --- a/src/utils/fader.lua +++ b/src/utils/fader.lua @@ -48,17 +48,22 @@ end function Fader:update(dt) + -- While the fader is active. if not self.done then + -- Update the internal timer. self.t = self.t + dt + -- Advance the fade if enough time has passed. if self.t >= 0.009 then self.step = self.step + 1 self.t = 0.0 end + -- Mark as done when all fade tiles have been shown/hidden. if self.step > 175 then self.done = true + -- Execute the callback if any. if self.callback ~= nil then self.callback() self.callback = nil @@ -70,23 +75,32 @@ end function Fader:draw() local c = 1 + + -- Set the render color to black. love.graphics.setColor(0, 0, 0) + -- For every fader tile. for i = 0, 16 do for j = 0, 10 do + -- Check if this is a fade in or fade out. if not self.reverse then + -- If it's a fade out then draw black tiles until c. if c <= self.step then love.graphics.rectangle('fill', 20 * i, 20 * j, 20, 20) end else - if c <= self.step then else + -- If it's a fade in then draw black tiles with indices higher than c. + if c > self.step then love.graphics.rectangle('fill', 20 * i, 20 * j, 20, 20) end end + + -- Advance to the next tile to show/hide. c = c + 1 end end + -- Reset the render color to white. love.graphics.setColor() end diff --git a/src/utils/sfx.lua b/src/utils/sfx.lua new file mode 100644 index 0000000..bcb3773 --- /dev/null +++ b/src/utils/sfx.lua @@ -0,0 +1,106 @@ +------------------------------------------------------------------------------ +-- Imports +------------------------------------------------------------------------------ + +local love = require 'love' +local make_class = require 'src.utils.classes' + + +------------------------------------------------------------------------------ +-- Class definitions +------------------------------------------------------------------------------ + +-- SoundEffect is a simple wrapper around Löve's Source class to allow for +-- easy loading/unloading and automatically hecking if a sound effect is valid +-- before using it. +local SoundEffect = make_class() + + +------------------------------------------------------------------------------ +-- Class methods +------------------------------------------------------------------------------ + +function SoundEffect:_init(file_name) + self.file_name = file_name +end + + +function SoundEffect:load() + self.sfx = love.audio.newSource(self.file_name) +end + + +function SoundEffect:unload() + if self:isPlaying() then self:stop() end + self.sfx = nil +end + + +function SoundEffect:setVolume(volume) + if self.sfx ~= nil then self.sfx:setVolume(volume) end +end + + +function SoundEffect:setPitch(pitch) + if self.sfx ~= nil then self.sfx:setPitch(pitch) end +end + + +function SoundEffect:setLooping(enable) + if self.sfx ~= nil then self.sfx:setLooping(enable) end +end + + +function SoundEffect:getDuration() + if self.sfx ~= nil then + return self.sfx:getDuration() + else + return nil + end +end + + +function SoundEffect:isPlaying() + return self.sfx ~= nil and self.sfx:isPlaying() +end + + +function SoundEffect:isPaused() + return self.sfx ~= nil and self.sfx:isPaused() +end + + +function SoundEffect:isStopped() + return self.sfx ~= nil and self.sfx:isStopped() +end + + +function SoundEffect:tell() + if self.sfx ~= nil then + return self.sfx:tell() + else + return nil + end +end + + +function SoundEffect:play() + if self.sfx ~= nil then self.sfx:play() end +end + + +function SoundEffect:pause() + if self.sfx ~= nil then self.sfx:pause() end +end + + +function SoundEffect:stop() + if self.sfx ~= nil then self.sfx:stop() end +end + + +------------------------------------------------------------------------------ +-- Module return +------------------------------------------------------------------------------ + +return SoundEffect