Add directional sticky and skewer box variants
This commit is contained in:
parent
c3f5aafd77
commit
f549eaf523
13 changed files with 723 additions and 101 deletions
83
movement.lua
Normal file
83
movement.lua
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
-- Finds the complete set of blocks that must move together for one grid step.
|
||||
-- A block joins the set when it is in another block's destination (ordinary
|
||||
-- pushing), is behind a directional sticky puller, or touches a skewer block.
|
||||
local Movement = {}
|
||||
|
||||
local adjacentDirections = {
|
||||
{x = 1, y = 0},
|
||||
{x = -1, y = 0},
|
||||
{x = 0, y = 1},
|
||||
{x = 0, y = -1},
|
||||
}
|
||||
|
||||
local function isSticky(entity)
|
||||
return entity.isSticky and entity:isSticky()
|
||||
end
|
||||
|
||||
local function isPassable(entity)
|
||||
return entity.canPassOver and entity:canPassOver()
|
||||
end
|
||||
|
||||
local function isSkewer(entity)
|
||||
return entity.isSkewer and entity:isSkewer()
|
||||
end
|
||||
|
||||
function Movement.findMovableGroup(startCells, direction, entityAt, isInBounds)
|
||||
local entities = {}
|
||||
local pendingCells = {}
|
||||
for _, cell in ipairs(startCells) do
|
||||
table.insert(pendingCells, cell)
|
||||
end
|
||||
|
||||
local nextCell = 1
|
||||
while nextCell <= #pendingCells do
|
||||
local cell = pendingCells[nextCell]
|
||||
nextCell = nextCell + 1
|
||||
|
||||
if not isInBounds(cell) then
|
||||
return false, entities
|
||||
end
|
||||
|
||||
local entity = entityAt(cell)
|
||||
if entity and not isPassable(entity) and not entities[entity] then
|
||||
if not entity:canMove() then
|
||||
return false, entities
|
||||
end
|
||||
|
||||
entities[entity] = entity
|
||||
|
||||
-- Anything occupying this block's destination must be pushed too.
|
||||
for _, projectedCell in ipairs(entity:getOccupiedCells(direction)) do
|
||||
table.insert(pendingCells, projectedCell)
|
||||
end
|
||||
|
||||
-- Sticky blocks pull only from the trailing face, like the player. A
|
||||
-- lateral move therefore shears the contact. Skewers retain the older
|
||||
-- all-edge behaviour and make everything they touch one rigid group.
|
||||
for _, occupiedCell in ipairs(entity:getOccupiedCells()) do
|
||||
for _, adjacentDirection in ipairs(adjacentDirections) do
|
||||
local adjacentCell = {
|
||||
x = occupiedCell.x + adjacentDirection.x,
|
||||
y = occupiedCell.y + adjacentDirection.y,
|
||||
}
|
||||
if isInBounds(adjacentCell) then
|
||||
local adjacentEntity = entityAt(adjacentCell)
|
||||
local trailing = adjacentDirection.x == -direction.x and
|
||||
adjacentDirection.y == -direction.y
|
||||
local attached = adjacentEntity and (
|
||||
isSkewer(entity) or isSkewer(adjacentEntity) or
|
||||
(trailing and (isSticky(entity) or isSticky(adjacentEntity)))
|
||||
)
|
||||
if attached and adjacentEntity ~= entity and adjacentEntity:canMove() then
|
||||
table.insert(pendingCells, adjacentCell)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return true, entities
|
||||
end
|
||||
|
||||
return Movement
|
||||
Loading…
Add table
Add a link
Reference in a new issue