diff --git a/config.lua b/config.lua index b1f8bd4..5458694 100644 --- a/config.lua +++ b/config.lua @@ -9,7 +9,10 @@ Config = { -- love2d line drawing settings lineStyle = "smooth", - lineWidth = 5 + lineWidth = 5, + + -- drag sensivity, px + dragSensivity = 5 } -- Colors table @@ -19,3 +22,23 @@ Color = { green = { 0, 1, 0 }, blue = { 0, 0, 1 } } + +-- Find key by value in table by predicate +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 +function tableHas( table, value, pred ) + for key, innervalue in pairs( table ) do + if pred( value, innervalue ) then + return true + end + end + return false +end diff --git a/grid.lua b/grid.lua index 2946120..3981712 100644 --- a/grid.lua +++ b/grid.lua @@ -34,3 +34,43 @@ function Grid:draw() end end end + +-- Check all lines and return one, which contains point (if any) +function Grid:matchesLine( point, ignoreEnd ) + local line = self.lines[tableFind( self.lines, point, + function( value, innervalue ) + return innervalue:has( value ) + end + )] + + if line ~= nil and not ignoreEnd then + if line.startpoint:equals( point ) then + line:clear() + line:push( line.startpoint ) + end + if line.endpoint:equals( point ) then + line:clear() + line:reverse() + return line + end + end + + -- Try to check endpoint + if line == nil and not ignoreEnd then + line = self.lines[tableFind( self.lines, point, + function( value, innervalue ) + if innervalue.endpoint:equals( value ) then + innervalue:clear() + innervalue:reverse() + return true + end + return false + end + )] + end + return line +end + +function Grid:inBounds( point ) + return point.x <= self.size.x and point.y <= self.size.y +end diff --git a/line.lua b/line.lua index 00447c4..d89e24b 100644 --- a/line.lua +++ b/line.lua @@ -38,7 +38,7 @@ function Line:draw() love.graphics.circle( "fill", sx, sy, Config.linePointRadius ) local ex, ey = self.endpoint:globalCoords() love.graphics.circle( "fill", ex, ey, Config.linePointRadius ) - if #self.points == 1 then + if #self.points <= 1 then love.graphics.setColor( Color.white ) return end @@ -52,3 +52,27 @@ function Line:draw() love.graphics.line( points ) love.graphics.setColor( Color.white ) end + +-- Clear points +function Line:clear() + for k, _ in pairs( self.points ) do + self.points[k] = nil + end +end + +-- Swap startpoint and endpoint +function Line:reverse() + local swap = self.startpoint + self.startpoint = self.endpoint + self.endpoint = swap + self:push( self.startpoint ) +end + +-- Check if line has the exact point +function Line:has( point ) + return tableHas( self.points, point, + function( value, innervalue ) + return innervalue:equals( value ) + end + ) +end diff --git a/main.lua b/main.lua index 894b240..2eda39e 100644 --- a/main.lua +++ b/main.lua @@ -13,29 +13,90 @@ function love.load() Color.red ) gameGrid:push( line ) + local line1 = Line:new( + GridPoint:new( 1, 5 ), + GridPoint:new( 5, 2 ), + Color.green + ) + gameGrid:push( line1 ) + local line2 = Line:new( + GridPoint:new( 2, 5 ), + GridPoint:new( 5, 3 ), + Color.blue + ) + gameGrid:push( line2 ) + mouse = { x = 0, y = 0, pressed = false, - lastPressed = false + lastPressed = false, + startX = -1, + startY = -1, + dragged = false, + lastLine = nil, + lastPoint = nil, + point = Point:new( 0, 0 ) } end -- TODO: move input interactions into module +-- TODO: fix collision with other line's endpoint function love.update( dt ) mouse.x, mouse.y = love.mouse.getPosition() + mouse.x = mouse.x + 1 + mouse.y = mouse.y + 1 + mouse.lastPoint = mouse.point mouse.lastPressed = pressed mouse.pressed = love.mouse.isDown( 1 ) + mouse.point = snapCoords( Point:new( mouse.x, mouse.y ) ) + if mouse.lastLine ~= nil then + local pointsLen = #mouse.lastLine.points + local lastLinePoint = mouse.lastLine.points[pointsLen] + if vectorLength( mouse.point, lastLinePoint ) == 1 + and gameGrid:inBounds( mouse.point ) + and gameGrid:matchesLine( mouse.point, true ) == nil + and not lastLinePoint:equals( mouse.lastLine.endpoint ) then + mouse.lastLine:push( mouse.point ) + end + end + + + mouse.dragged = mouse.pressed + and mouse.startX > 0 + and vectorLength( + Point:new( mouse.x, mouse.y ), + Point:new( mouse.startX, mouse.startY ) + ) > Config.dragSensivity + + if not mouse.pressed and mouse.startX > 0 then + mouse.startX = -1 + mouse.startY = -1 + mouse.lastLine = nil + end + + if not mouse.lastPressed + and mouse.pressed + and mouse.startX < 0 then + mouse.startX = mouse.x + mouse.startY = mouse.y + mouse.lastLine = gameGrid:matchesLine( mouse.point, false ) + end end function love.draw() gameGrid:draw() - if mouse.pressed then - local x, y = snapCoords( Point:new( mouse.x, mouse.y ) ):coords() - local text = string.format( "%d:%d global\n%d:%d local", mouse.x, mouse.y, x, y ) - love.graphics.print( text, 64, 256 ) + local text = string.format( "%d:%d global\n%d:%d local\n%d:%d from start", mouse.x, mouse.y, mouse.point.x, mouse.point.y, mouse.startX - mouse.x, mouse.startY - mouse.y ) + love.graphics.print( text, 64, 256 ) + + if mouse.dragged then + love.graphics.print( "drag", 64, 300 ) end + if mouse.lastLine ~= nil then + love.graphics.print( tostring( mouse.lastLine ), 128, 300 ) + end + end -- Returns local coords from global @@ -44,3 +105,7 @@ function snapCoords( point ) local y = math.ceil( point.y / Config.cellSize ) return GridPoint:new( x, y ) end + +function vectorLength( startpoint, endpoint ) + return math.sqrt( ( startpoint.x - endpoint.x ) ^ 2 + ( startpoint.y - endpoint.y ) ^ 2 ) +end