Compare commits

..

7 commits

Author SHA1 Message Date
71f98fd831 Centered grid 2025-10-24 12:52:33 +03:00
e04b8e523e Added levels menu 2025-10-23 16:32:58 +03:00
fd1e314ec9 Added indexed function 2025-10-23 16:32:27 +03:00
a47e14ffca print version in the main menu 2025-10-23 15:19:10 +03:00
27a0003579 Tell lua lsp about nil-ed point 2025-10-23 15:18:50 +03:00
57a69a6e0c Take build version from config.lua 2025-10-23 15:12:31 +03:00
7df0478890 more modular menu 2025-10-23 14:47:00 +03:00
13 changed files with 260 additions and 131 deletions

View file

@ -1,4 +1,4 @@
VERSION=0.1 VERSION=$(shell grep VERSION config.lua | sed -n -e "s/VERSION = 'v//" -e "s/'//p")
IGNORE_FLAGS=--ignore Makefile --ignore build IGNORE_FLAGS=--ignore Makefile --ignore build
LOVE_PATH := $(shell command -v love) LOVE_PATH := $(shell command -v love)

View file

@ -1,10 +1,13 @@
require 'tablefuncs' require 'tablefuncs'
VERSION = 'v0.2'
-- Global config table -- Global config table
---@class Config ---@class Config
---@field pointRadius number Radius of each grid point, relative to cellSize ---@field pointRadius number Radius of each grid point, relative to cellSize
---@field linePointRadius number Radius of line start/end points, relative to cellSize ---@field linePointRadius number Radius of line start/end points, relative to cellSize
---@field cellSize number Size of each grid cell ---@field cellSize number Size of each grid cell
---@field gridOffset number X offset of grid processing
---@field lineStyle string love2d line style setting ---@field lineStyle string love2d line style setting
---@field lineWidth number love2d line width setting ---@field lineWidth number love2d line width setting
---@field menuLineWidth number love2d line width for buttons ---@field menuLineWidth number love2d line width for buttons
@ -15,6 +18,7 @@ Config = {
linePointRadius = 0.4, linePointRadius = 0.4,
cellSize = 30, cellSize = 30,
gridOffset = 160,
lineStyle = "smooth", lineStyle = "smooth",
lineWidth = 0.1, lineWidth = 0.1,

View file

@ -39,8 +39,9 @@ function Grid:draw()
end end
for y = 1, self.size.y do for y = 1, self.size.y do
local px, py = x * Config.cellSize, y * Config.cellSize local gp = GridPoint:new(x, y)
love.graphics.circle( "fill", px - Config.cellSize / 2, py - Config.cellSize / 2, Config.cellSize * Config.pointRadius) local px, py = gp:globalCoords()
love.graphics.circle( "fill", px, py, Config.cellSize * Config.pointRadius)
end end
end end
-- Draw lines -- Draw lines

View file

@ -9,7 +9,7 @@ GridPoint = Point
---@return Point ---@return Point
function GridPoint:absolute() function GridPoint:absolute()
return Point:new( return Point:new(
self.x * Config.cellSize, self.x * Config.cellSize + Config.gridOffset,
self.y * Config.cellSize self.y * Config.cellSize
) )
end end
@ -17,7 +17,7 @@ end
-- Same as coords, but converted to global coords -- Same as coords, but converted to global coords
---@return number, number ---@return number, number
function GridPoint:globalCoords() function GridPoint:globalCoords()
return self.x * Config.cellSize - Config.cellSize / 2, return self.x * Config.cellSize - Config.cellSize / 2 + Config.gridOffset,
self.y * Config.cellSize - Config.cellSize / 2 self.y * Config.cellSize - Config.cellSize / 2
end end
@ -25,7 +25,7 @@ end
---@param point Point ---@param point Point
---@return GridPoint ---@return GridPoint
function GridPoint.snapCoords( point ) function GridPoint.snapCoords( point )
local x = math.ceil( point.x / Config.cellSize ) local x = math.ceil( (point.x - Config.gridOffset) / Config.cellSize )
local y = math.ceil( point.y / Config.cellSize ) local y = math.ceil( point.y / Config.cellSize )
return GridPoint:new( x, y ) return GridPoint:new( x, y )
end end

View file

@ -6,7 +6,7 @@ require 'makegrid'
---@field current integer ---@field current integer
LevelHandler = { LevelHandler = {
levels = { levels = {
'test3', 'test2', 'test' 'test2', 'test', 'test3'
}, },
current = 1, current = 1,
} }
@ -18,13 +18,22 @@ function LevelHandler:next()
if self.current > #self.levels then if self.current > #self.levels then
self.current = 1 self.current = 1
end end
local levelPath = string.format('levels/%s', self.levels[self.current]) local levelPath = 'levels/' .. self.levels[self.current]
return MakeGrid( require( levelPath ) ) return MakeGrid( require( levelPath ) )
end end
-- Returns first level -- Returns first level
---@return Grid ---@return Grid
function LevelHandler:first() function LevelHandler:first()
local levelPath = string.format('levels/%s', self.levels[1]) local levelPath = 'levels/' .. self.levels[1]
return MakeGrid( require( levelPath ) )
end
-- Returns level by its index in table
---@param i number
---@return Grid
function LevelHandler:indexed(i)
self.current = i
local levelPath = 'levels/' .. self.levels[self.current]
return MakeGrid( require( levelPath ) ) return MakeGrid( require( levelPath ) )
end end

125
menu.lua
View file

@ -1,114 +1,6 @@
require 'config' require 'config'
require 'button' require 'button'
require 'menu.state'
-- Menu state class
---@class MenuState
---@field buttons Button[]
MenuState = {
buttons = {}
}
-- Factory function
---@param buttons Button[] | nil
---@return MenuState
function MenuState:new( buttons )
local state = {
buttons = buttons or MenuState.buttons
}
setmetatable( state, { __index = self } )
return state
end
-- Draw buttons
function MenuState:draw()
for _, button in ipairs(self.buttons) do
button:draw()
end
end
-- Update buttons
---@param dt number
---@param point Point
---@param pressed boolean
function MenuState:update( dt, point, pressed )
for _, button in pairs(self.buttons) do
button:update( dt, point, pressed )
end
end
---@enum MenuStateIndex
MenuStateIndex = {
start = 'start',
pause = 'pause',
levels = 'levels',
hidden = 'hidden',
completed = 'completed'
}
local buttonTopPos = Point:new( 240, 120 )
local buttonBotPos = Point:new( 240, 240 )
local buttonSize = Point:new( 320, 80 )
local startButton = Button:new(
buttonTopPos,
buttonSize,
'Start',
nil,
nil,
function()
Menu.current_state = MenuStateIndex.hidden
GameGrid = LevelHandler:first()
Menu.updateCellSize()
end
)
local exitToMenuButton = Button:new(
buttonBotPos,
buttonSize,
'Return to menu',
nil,
nil,
function()
Menu.current_state = MenuStateIndex.start
end
)
local exitGameButton = Button:new(
buttonBotPos,
buttonSize,
'Exit',
nil,
nil,
function()
love.event.quit()
end
)
local nextLevelButton = Button:new(
buttonTopPos,
buttonSize,
'Next level',
nil,
nil,
function()
GameGrid = LevelHandler:next()
Menu.updateCellSize()
Menu.current_state = MenuStateIndex.hidden
end
)
local backToGameButton = Button:new(
buttonTopPos,
buttonSize,
'Continue',
nil,
nil,
function()
Menu.current_state = MenuStateIndex.hidden
end
)
-- Menu handler -- Menu handler
---@class Menu ---@class Menu
@ -117,20 +9,13 @@ local backToGameButton = Button:new(
Menu = { Menu = {
states = { states = {
-- Main menu -- Main menu
[MenuStateIndex.start] = MenuState:new({ [MenuStateIndex.start] = require 'menu.start',
startButton, exitGameButton
}),
-- Pause menu -- Pause menu
[MenuStateIndex.pause] = MenuState:new({ [MenuStateIndex.pause] = require 'menu.pause',
backToGameButton, exitToMenuButton
}),
-- Level selector -- Level selector
[MenuStateIndex.levels] = MenuState:new({ [MenuStateIndex.levels] = require 'menu.levels',
}),
-- Level completed menu -- Level completed menu
[MenuStateIndex.completed] = MenuState:new({ [MenuStateIndex.completed] = require 'menu.completed',
nextLevelButton, exitToMenuButton
}),
-- Empty state -- Empty state
[MenuStateIndex.hidden] = MenuState:new() [MenuStateIndex.hidden] = MenuState:new()
}, },

24
menu/common.lua Normal file
View file

@ -0,0 +1,24 @@
require 'point'
require 'button'
local buttonTopPos = Point:new( 240, 160 )
local buttonBotPos = Point:new( 240, 280 )
local buttonSize = Point:new( 320, 80 )
local titlePos = Point:new( 240, 80 )
return {
buttonTopPos = buttonTopPos,
buttonBotPos = buttonBotPos,
buttonSize = buttonSize,
titlePos = titlePos,
exitToMenuButton = Button:new(
buttonBotPos,
buttonSize,
'Return to menu',
nil,
nil,
function()
Menu.current_state = MenuStateIndex.start
end
)
}

29
menu/completed.lua Normal file
View file

@ -0,0 +1,29 @@
require 'menu.state'
require 'button'
require 'text'
local common = require 'menu.common'
local nextLevelButton = Button:new(
common.buttonTopPos,
common.buttonSize,
'Next level',
nil,
nil,
function()
GameGrid = LevelHandler:next()
Menu.updateCellSize()
Menu.current_state = MenuStateIndex.hidden
end
)
local title = Text:new(
common.titlePos,
common.buttonSize,
'Level completed!'
)
return MenuState:new(
{ nextLevelButton, common.exitToMenuButton },
{ title }
)

47
menu/levels.lua Normal file
View file

@ -0,0 +1,47 @@
require 'menu.state'
require 'button'
require 'text'
local common = require 'menu.common'
local size, margin = 60, 30
local levelSize = Point:new( size, size )
local yOffset = 160
local levelsPerLine = 8
local levelCount = #LevelHandler.levels
local buttons = {}
for i=1,levelCount do
local x = (size + margin) * (i % levelsPerLine)
local y = (size + margin) * math.floor(i / levelsPerLine) + yOffset
local button = Button:new(
Point:new(x, y),
levelSize,
tostring(i),
nil,
nil,
function()
GameGrid = LevelHandler:indexed(i)
Menu.updateCellSize()
Menu.current_state = MenuStateIndex.hidden
end
)
table.insert(buttons, button)
end
local exitToMenuButton = Button:new(
Point:new( 240, 40 ),
common.buttonSize,
'Return to menu',
nil,
nil,
function()
Menu.current_state = MenuStateIndex.start
end
)
table.insert(buttons, exitToMenuButton)
return MenuState:new(buttons)

27
menu/pause.lua Normal file
View file

@ -0,0 +1,27 @@
require 'menu.state'
require 'button'
require 'text'
local common = require 'menu.common'
local backToGameButton = Button:new(
common.buttonTopPos,
common.buttonSize,
'Continue',
nil,
nil,
function()
Menu.current_state = MenuStateIndex.hidden
end
)
local title = Text:new(
common.titlePos,
common.buttonSize,
'Paused'
)
return MenuState:new(
{ backToGameButton, common.exitToMenuButton },
{ title }
)

50
menu/start.lua Normal file
View file

@ -0,0 +1,50 @@
require 'menu.state'
require 'button'
require 'text'
require 'point'
require 'config'
local common = require 'menu.common'
local versionPos = Point:new( 0, 468 )
local versionSize = Point:new( 800 )
local startButton = Button:new(
common.buttonTopPos,
common.buttonSize,
'Start',
nil,
nil,
function()
Menu.current_state = MenuStateIndex.levels
end
)
local exitGameButton = Button:new(
common.buttonBotPos,
common.buttonSize,
'Exit',
nil,
nil,
function()
love.event.quit()
end
)
local title = Text:new(
common.titlePos,
common.buttonSize,
'Lines'
)
local versionText = Text:new(
versionPos,
versionSize,
string.format("Version %s", VERSION),
'left'
)
return MenuState:new(
{ startButton, exitGameButton },
{ title, versionText }
)

53
menu/state.lua Normal file
View file

@ -0,0 +1,53 @@
-- Menu state class
---@class MenuState
---@field buttons Button[]
---@field text Text[]
MenuState = {
buttons = {},
text = {}
}
-- Factory function
---@param buttons Button[] | nil
---@param text Text[] | nil
---@return MenuState
function MenuState:new( buttons, text )
local state = {
buttons = buttons or MenuState.buttons,
text = text or MenuState.text
}
setmetatable( state, { __index = self } )
return state
end
-- Draw buttons
function MenuState:draw()
for _, button in ipairs(self.buttons) do
button:draw()
end
for _, txt in ipairs(self.text) do
txt:draw()
end
end
-- Update buttons
---@param dt number
---@param point Point
---@param pressed boolean
function MenuState:update( dt, point, pressed )
for _, button in pairs(self.buttons) do
button:update( dt, point, pressed )
end
end
---@enum MenuStateIndex
MenuStateIndex = {
start = 'start',
pause = 'pause',
levels = 'levels',
hidden = 'hidden',
completed = 'completed'
}

View file

@ -3,8 +3,8 @@
Point = { x = 1, y = 1 } Point = { x = 1, y = 1 }
-- Point factory -- Point factory
---@param x number ---@param x number | nil
---@param y number ---@param y number | nil
---@return any ---@return any
function Point:new( x, y ) function Point:new( x, y )
local point = { local point = {