diff --git a/src/core/PlayArea.ttslua b/src/core/PlayArea.ttslua index 21f07b8b..200b1fa0 100644 --- a/src/core/PlayArea.ttslua +++ b/src/core/PlayArea.ttslua @@ -3,14 +3,17 @@ --------------------------------------------------------- -- set true to enable debug logging -local DEBUG = false +local DEBUG = true -- Location connection directional options local BIDIRECTIONAL = 0 local ONE_WAY = 1 +local INCOMING_ONE_WAY = 2 -- Connector draw parameters local CONNECTION_THICKNESS = 0.015 +local DRAGGING_CONNECTION_THICKNESS = 0.15 +local DRAGGING_CONNECTION_COLOR = { 0.8, 0.8, 0.8, 1 } local CONNECTION_COLOR = { 0.4, 0.4, 0.4, 1 } local DIRECTIONAL_ARROW_DISTANCE = 3.5 local ARROW_ARM_LENGTH = 0.9 @@ -91,7 +94,7 @@ end function onCollisionEnter(collisionInfo) local obj = collisionInfo.collision_object local objType = obj.name - + -- only continue for cards if not collisionEnabled or (objType ~= "Card" and objType ~= "CardCustom") then return end @@ -151,6 +154,11 @@ function onUpdate() if obj == nil or not isInPlayArea(obj) then draggingGuids[guid] = nil needsConnectionRebuild = true + -- If object still exists then it's been dragged outside the area and needs to clear the + -- lines attached to it + if obj ~= nil then + obj.setVectorLines(nil) + end end -- Even if the last location left the play area, need one last draw to clear the lines needsConnectionDraw = true @@ -159,7 +167,7 @@ function onUpdate() rebuildConnectionList() end if needsConnectionDraw then - drawConnections() + drawDraggingConnections() end end @@ -174,7 +182,7 @@ function maybeTrackLocation(card) if metadata.type == "Location" then locations[card.getGUID()] = metadata rebuildConnectionList() - drawConnections() + drawBaseConnections() end end end @@ -190,14 +198,14 @@ function maybeUntrackLocation(card) if locations[card.getGUID()] ~= nil and not card.locked then locations[card.getGUID()] = nil rebuildConnectionList() - drawConnections() + drawBaseConnections() end end -- Builds a list of GUID to GUID connection information based on the currently tracked locations. -- This will update the connection information and store it in the locationConnections data member, -- but does not draw those connections. This should often be followed by a call to --- drawConnections() +-- drawBaseConnections() function rebuildConnectionList() if not showLocationLinks() then locationConnections = { } @@ -256,10 +264,15 @@ function buildConnection(cardId, iconCardList) for _, connectedGuid in ipairs(iconCardList[icon]) do -- If the reciprocal exists, convert it to BiDi, otherwise add as a one-way if locationConnections[connectedGuid] ~= nil - and locationConnections[connectedGuid][card.getGUID()] ~= nil then + and locationConnections[connectedGuid][card.getGUID()] == ONE_WAY then locationConnections[connectedGuid][card.getGUID()] = BIDIRECTIONAL + locationConnections[card.getGUID()][connectedGuid] = nil else + if locationConnections[connectedGuid] == nil then + locationConnections[connectedGuid] = { } + end locationConnections[card.getGUID()][connectedGuid] = ONE_WAY + locationConnections[connectedGuid][card.getGUID()] = INCOMING_ONE_WAY end end end @@ -283,8 +296,9 @@ function getLocationData(card) end end --- Draws the lines for connections currently in locationConnections. -function drawConnections() +-- Draws the lines for connections currently in locationConnections but not in draggingGuids. +-- Constructed vectors will be set to the playmat +function drawBaseConnections() if not showLocationLinks() then locationConnections = { } return @@ -295,14 +309,16 @@ function drawConnections() -- Objects should reliably exist at this point, but since this can be called during onUpdate the -- object checks are conservative just to make sure. local origin = getObjectFromGUID(originGuid) - if origin != nil then + if draggingGuids[originGuid] == nil and origin != nil then for targetGuid, direction in pairs(targetGuids) do local target = getObjectFromGUID(targetGuid) - if target != nil then + if draggingGuids[targetGuid] == nil and target != nil then + -- Since we process the full list, we're guaranteed to hit any ONE_WAY connections later + -- so we can ignore INCOMING_ONE_WAY if direction == BIDIRECTIONAL then - addBidirectionalVector(origin, target, cardConnectionLines) + addBidirectionalVector(origin, target, self, cardConnectionLines) elseif direction == ONE_WAY then - addOneWayVector(origin, target, cardConnectionLines) + addOneWayVector(origin, target, self, cardConnectionLines) end end end @@ -311,22 +327,61 @@ function drawConnections() self.setVectorLines(cardConnectionLines) end +-- Draws the lines for cards which are currently being dragged. +function drawDraggingConnections() + if not showLocationLinks() then + return + end + local cardConnectionLines = { } + local ownedVectors = { } + + for originGuid, _ in pairs(draggingGuids) do + targetGuids = locationConnections[originGuid] + -- Objects should reliably exist at this point, but since this can be called during onUpdate the + -- object checks are conservative just to make sure. + local origin = getObjectFromGUID(originGuid) + if draggingGuids[originGuid] and origin != nil then + ownedVectors[originGuid] = { } + for targetGuid, direction in pairs(targetGuids) do + local target = getObjectFromGUID(targetGuid) + if target != nil then + if direction == BIDIRECTIONAL then + addBidirectionalVector(origin, target, origin, ownedVectors[originGuid]) + elseif direction == ONE_WAY then + addOneWayVector(origin, target, origin, ownedVectors[originGuid]) + elseif direction == INCOMING_ONE_WAY and not draggingGuids[targetGuid] then + addOneWayVector(target, origin, origin, ownedVectors[originGuid]) + end + end + end + end + end + for ownerGuid, vectors in pairs(ownedVectors) do + local card = getObjectFromGUID(ownerGuid) + card.setVectorLines(vectors) + end +end + -- Draws a bidirectional location connection between the two cards, adding the lines to do so to the -- given lines list. ---@param card1 Object One of the card objects to connect ---@param card2 Object The other card object to connect +---@param vectorOwner Object The object which these lines will be set to. Used for relative +--- positioning and scaling, as well as highlighting connections during a drag operation ---@param lines Table List of vector line elements. Mutable, will be updated to add this connector -function addBidirectionalVector(card1, card2, lines) +function addBidirectionalVector(card1, card2, vectorOwner, lines) local cardPos1 = card1.getPosition() local cardPos2 = card2.getPosition() cardPos1.y = CONNECTION_LINE_Y cardPos2.y = CONNECTION_LINE_Y - local pos1 = self.positionToLocal(cardPos1) - local pos2 = self.positionToLocal(cardPos2) + + local pos1 = vectorOwner.positionToLocal(cardPos1) + local pos2 = vectorOwner.positionToLocal(cardPos2) + table.insert(lines, { points = { pos1, pos2 }, - color = CONNECTION_COLOR, - thickness = CONNECTION_THICKNESS, + color = vectorOwner == self and CONNECTION_COLOR or DRAGGING_CONNECTION_COLOR, + thickness = vectorOwner == self and CONNECTION_THICKNESS or DRAGGING_CONNECTION_THICKNESS, }) end @@ -334,10 +389,12 @@ end -- given lines list. Arrows will point towards the target card. ---@param origin Object Origin card in the connection ---@param target Object Target card object to connect +---@param vectorOwner Object The object which these lines will be set to. Used for relative +--- positioning and scaling, as well as highlighting connections during a drag operation ---@param lines Table List of vector line elements. Mutable, will be updated to add this connector -function addOneWayVector(origin, target, lines) +function addOneWayVector(origin, target, vectorOwner, lines) -- Start with the BiDi then add the arrow lines to it - addBidirectionalVector(origin, target, lines) + addBidirectionalVector(origin, target, vectorOwner, lines) local originPos = origin.getPosition() local targetPos = target.getPosition() originPos.y = CONNECTION_LINE_Y @@ -355,28 +412,30 @@ function addOneWayVector(origin, target, lines) local closeToTarget = Vector(targetPos):moveTowards(originPos, distanceFromCard - ARROW_ARM_LENGTH / 2) if (originPos:distance(closeToOrigin) > originPos:distance(closeToTarget)) then - addArrowLines(midpoint, originPos, lines) + addArrowLines(midpoint, originPos, vectorOwner, lines) else - addArrowLines(closeToOrigin, originPos, lines) - addArrowLines(closeToTarget, originPos, lines) + addArrowLines(closeToOrigin, originPos, vectorOwner, lines) + addArrowLines(closeToTarget, originPos, vectorOwner, lines) end end -- Draws an arrowhead at the given position. ---@param arrowheadPosition Table Centerpoint of the arrowhead to draw (NOT the tip of the arrow) ---@param originPos Table Origin point of the connection, used to position the arrow arms +---@param vectorOwner Object The object which these lines will be set to. Used for relative +--- positioning and scaling, as well as highlighting connections during a drag operation ---@param lines Table List of vector line elements. Mutable, will be updated to add this arrow -function addArrowLines(arrowheadPos, originPos, lines) +function addArrowLines(arrowheadPos, originPos, vectorOwner, lines) local arrowArm1 = Vector(arrowheadPos):moveTowards(originPos, ARROW_ARM_LENGTH):sub(arrowheadPos):rotateOver("y", -1 * ARROW_ANGLE):add(arrowheadPos) local arrowArm2 = Vector(arrowheadPos):moveTowards(originPos, ARROW_ARM_LENGTH):sub(arrowheadPos):rotateOver("y", ARROW_ANGLE):add(arrowheadPos) - local head = self.positionToLocal(arrowheadPos) - local arm1 = self.positionToLocal(arrowArm1) - local arm2 = self.positionToLocal(arrowArm2) + local head = vectorOwner.positionToLocal(arrowheadPos) + local arm1 = vectorOwner.positionToLocal(arrowArm1) + local arm2 = vectorOwner.positionToLocal(arrowArm2) table.insert(lines, { points = { arm1, head, arm2}, - color = CONNECTION_COLOR, - thickness = CONNECTION_THICKNESS + color = vectorOwner == self and CONNECTION_COLOR or DRAGGING_CONNECTION_COLOR, + thickness = vectorOwner == self and CONNECTION_THICKNESS or DRAGGING_CONNECTION_THICKNESS, }) end