commit c6547c112153f5573ce2a9db08b7f19b15b87998 Author: 2ndbeam <2ndbeam@disroot.org> Date: Wed Oct 29 18:12:43 2025 +0300 Almost working from 1st try diff --git a/config.lua b/config.lua new file mode 100644 index 0000000..93d9be9 --- /dev/null +++ b/config.lua @@ -0,0 +1,5 @@ +Config = { + cellSize = 64, + gridOffset = 0, + portWidth = 16 +} diff --git a/gridpoint.lua b/gridpoint.lua new file mode 100644 index 0000000..e8d57e0 --- /dev/null +++ b/gridpoint.lua @@ -0,0 +1,31 @@ +require 'point' +require 'config' + +-- Point table with grid-based coordinates +---@class GridPoint: Point +GridPoint = Point + +-- Convert grid x, y to global x, y +---@return Point +function GridPoint:absolute() + return Point:new( + self.x * Config.cellSize + Config.gridOffset, + self.y * Config.cellSize + ) +end + +-- Same as coords, but converted to global coords +---@return number, number +function GridPoint:globalCoords() + return self.x * Config.cellSize - Config.cellSize / 2 + Config.gridOffset, + self.y * Config.cellSize - Config.cellSize / 2 +end + +-- Returns local coords from global +---@param point Point +---@return GridPoint +function GridPoint.snapCoords( point ) + local x = math.ceil( (point.x - Config.gridOffset) / Config.cellSize ) + local y = math.ceil( point.y / Config.cellSize ) + return GridPoint:new( x, y ) +end diff --git a/main.lua b/main.lua new file mode 100644 index 0000000..1893794 --- /dev/null +++ b/main.lua @@ -0,0 +1,33 @@ +require 'point' +require 'gridpoint' +require 'mouse' +require 'mechanism' +require 'port' + +function love.load() + Screenw, Screenh = love.window.getMode() + Gridw, Gridh = Screenw / Config.cellSize, Screenh / Config.cellSize + local port = Port:new( GridPoint:new(-1, 0), PortRotation.left, { 0.8, 0.8, 0, 1 } ) + Mecha1 = Mechanism:new( GridPoint:new(5, 5), GridPoint:new(3, 3), { port }, {0.5, 0.5, 0.5, 1} ) +end + +function love.update( dt ) + dt = dt + Mouse:update() +end + +function love.draw() + for i = 1, Gridw do + love.graphics.line( i * Config.cellSize, 0, i * Config.cellSize, Screenh ) + end + for j = 1, Gridh do + love.graphics.line( 0, j * Config.cellSize, Screenw, j * Config.cellSize ) + end + local mx, my = Mouse.point:globalCoords() + mx = mx - Config.cellSize / 2 + my = my - Config.cellSize / 2 + local mh, mw = Config.cellSize, Config.cellSize + love.graphics.rectangle("fill", mx, my, mh, mw) + + Mecha1:draw() +end diff --git a/mechanism.lua b/mechanism.lua new file mode 100644 index 0000000..9401d58 --- /dev/null +++ b/mechanism.lua @@ -0,0 +1,69 @@ +require 'tablefuncs' +require 'gridpoint' +require 'port' + +---@param xcorner GridPoint +---@param size GridPoint +---@return GridPoint +local function nextxcorner( xcorner, size ) + local cornerLookup = { + GridPoint:new( 0, 0 ), + GridPoint:new( size.x - 1, 0 ), + GridPoint:new( size.x - 1, size.y - 1 ), + GridPoint:new( size.x - 1, size.y - 1 ) + } + local index = TableFind(cornerLookup, xcorner, function(value) value:equals(xcorner) end) + if index < #cornerLookup then + index = index + 1 + else + index = 0 + end + return cornerLookup[index] +end + +---@class Mechanism +---@field position GridPoint +---@field size GridPoint +---@field xcorner GridPoint +---@field ports Port[] +---@field color table +Mechanism = { + position = GridPoint:new( 0, 0 ), + size = GridPoint:new( 1, 1 ), + xcorner = GridPoint:new( 0, 0 ), + ports = {}, + color = { 0.5, 0.5, 0.5, 1 } +} + +function Mechanism:new( position, size, ports, color ) + local mechanism = { + position = position or self.position, + size = size or self.size, + ports = ports or {}, + color = color or self.color + } + + setmetatable( mechanism, { __index = self } ) + + return mechanism +end + +function Mechanism:rotateClockwise() + self.xcorner = nextxcorner(self.xcorner, self.size) + for _, port in ipairs(self.ports) do + port:rotateClockwise() + end +end + +function Mechanism:draw() + love.graphics.setColor(self.color) + local x, y = self.position:globalCoords() + x = x - Config.cellSize / 2 + y = y - Config.cellSize / 2 + local w, h = self.size:globalCoords() + love.graphics.rectangle("fill", x, y, w, h) + for _, port in ipairs(self.ports) do + local offset = GridPoint:new( self.position.x + self.xcorner.x, self.position.y + self.xcorner.y ) + port:draw( offset ) + end +end diff --git a/mouse.lua b/mouse.lua new file mode 100644 index 0000000..c880cd4 --- /dev/null +++ b/mouse.lua @@ -0,0 +1,19 @@ +-- TODO: rewrite +---@class Mouse +---@field x integer +---@field y integer +---@field point GridPoint +Mouse = { + x = 0, + y = 0, + point = GridPoint:new( 0, 0 ) +} + +-- TODO: fix collision with other line's endpoint +function Mouse:update() + Mouse.x, Mouse.y = love.mouse.getPosition() + Mouse.x = Mouse.x + 1 + Mouse.y = Mouse.y + 1 + + Mouse.point = GridPoint.snapCoords( Point:new( Mouse.x, Mouse.y ) ) +end diff --git a/point.lua b/point.lua new file mode 100644 index 0000000..4795ee0 --- /dev/null +++ b/point.lua @@ -0,0 +1,42 @@ +-- Represents 2D point +---@class Point +Point = { x = 1, y = 1 } + +-- Point factory +---@param x number | nil +---@param y number | nil +---@return any +function Point:new( x, y ) + local point = { + x = x or x, + y = y or y + } + + setmetatable( point, { __index = self } ) + + return point +end + +-- Comparing function +---@param point self +---@return boolean +function Point:equals( point ) + return self.x == point.x and self.y == point.y +end + +-- Get self coordinates +---@return number, number +function Point:coords() + return self.x, self.y +end + +-- Return vector length between points +---@param point Point +---@return number +function Point:distanceTo( point ) + return math.sqrt( + ( self.x - point.x ) ^ 2 + + ( self.y - point.y ) ^ 2 + ) +end + diff --git a/port.lua b/port.lua new file mode 100644 index 0000000..bed4976 --- /dev/null +++ b/port.lua @@ -0,0 +1,71 @@ +require 'gridpoint' + +---@enum Alignment +Alignment = { + Vertical = true, + Horizontal = false +} + +---@enum PortRotation +PortRotation = { + right = {false, false}, + down = {false, true}, + left = {true, false}, + up = {true, true} +} + +---@class Port +---@field position GridPoint +---@field alignment Alignment +---@field scanOffset number +---@field color table +Port = { + position = GridPoint:new(0, 0), + alignment = Alignment.Vertical, + scanOffset = 0, + color = { 0.8, 0.8, 0, 1 } +} + +---@param position GridPoint +---@param rotation PortRotation +---@param color table +---@return Port +function Port:new(position, rotation, color) + local port = { + position = position or self.position, + alignment = self.alignment, + scanOffset = self.scanOffset, + color = color or self.color + } + if rotation ~= nil then + port.scanOffset = rotation[1] and 1 or 0 + port.alignment = rotation[2] + end + + setmetatable(port, { __index = self }) + + return port +end + +function Port:rotateClockwise() + local swap = self.position.x + self.position.x = -self.position.y + self.position.y = swap + self.scanOffset = (self.scanOffset == 1) == self.alignment and 1 or 0 + self.alignment = not self.alignment +end + +---@param offset GridPoint +function Port:draw( offset ) + love.graphics.setColor(self.color) + local drawPoint = GridPoint:new( + offset.x + self.position.x + self.scanOffset, + offset.y + self.position.y + self.scanOffset + ) + local x, y = drawPoint:globalCoords() + x = self.alignment and x - Config.cellSize / 2 or x - Config.portWidth / 2 - Config.cellSize / 2 + y = self.alignment and y - Config.portWidth / 2 - Config.cellSize / 2 or y - Config.cellSize / 2 + local w = self.alignment and Config.cellSize or Config.portWidth + local h = self.alignment and Config.portWidth or Config.cellSize + love.graphics.rectangle("fill", x, y, w, h) +end diff --git a/tablefuncs.lua b/tablefuncs.lua new file mode 100644 index 0000000..e478747 --- /dev/null +++ b/tablefuncs.lua @@ -0,0 +1,27 @@ +-- Find key by value in table by predicate +---@param table table +---@param value any +---@param pred function +---@return any +function TableFind( table, value, pred ) + for key, innervalue in pairs( table ) do + if pred( value, innervalue ) then + return key + end + end + return nil +end + +-- Find if value exists in table by predicate +---@param table table +---@param value any +---@param pred function +---@return boolean +function TableHas( table, value, pred ) + for _, innervalue in pairs( table ) do + if pred( value, innervalue ) then + return true + end + end + return false +end