Add directional sticky and skewer box variants

This commit is contained in:
Your Name 2026-08-11 15:07:11 -04:00
parent c3f5aafd77
commit f549eaf523
13 changed files with 723 additions and 101 deletions

124
room.lua
View file

@ -10,8 +10,12 @@ require "switch"
require "door"
require "dialogue_manager"
require "generic_moveable"
require "generic_sticky"
require "generic_skewer"
require "generic_unmoveable"
local Movement = require "movement"
function Room:initialize(t)
self.player = {}
self.switches = { red = {}, green = {}, blue = {} }
@ -202,7 +206,7 @@ function Room:movePlayer(key)
end
local move = true
-- PUSHHHHHHHHHHHHHHHHHHHHHH---------------------
-- PUSH ---------------------------------------------------------------
local initialTargetCell = {
x = pos.x + dir.x, y = pos.y + dir.y
@ -219,104 +223,24 @@ function Room:movePlayer(key)
if not self:isInBounds(initialTargetCell) then
-- let's us move out of bounds to Change Rooms without pulling a bloc_
move = true
elseif initialTargetEntity and initialTargetEntity:canPassOver() then
--we should put this in the else statement actually
move = true
else
local targetCells
targetCells = {initialTargetCell} -- ...we start with our attempted movement...
local doneSearching
while not doneSearching do
nextTargetCells = {} -- ...then we create this array to save our next group of cells
local emptyCells = {}
for _, cell in pairs(targetCells) do
if self:isInBounds(cell) then
local entity = self:getCellInMatrix(self.collidableMatrices[color], cell)
if entity then
--something is here!!
if not entitiesToPush[entity] then --if the entity hasnt been found already
if entity:canMove() then
local projectedCells = entity:getOccupiedCells(dir) -- we project the movement here
entitiesToPush[entity] = entity
for _, projectedCell in ipairs(projectedCells) do
table.insert(nextTargetCells, projectedCell)
end
else
move = false
doneSearching = true
end
end
else
--there's nothin there!!
table.insert(emptyCells, cell)
end
else
--we are out of bounds now
move = false
doneSearching = true
end
end
--if every projected cell is empty then we can do the move
if #emptyCells == #targetCells then
move = true
doneSearching = true
end
targetCells = nextTargetCells
end
--let's get out of this loop b/c if we can't move one color we can't move at all
move, entitiesToPush = Movement.findMovableGroup(
{initialTargetCell}, dir,
function(cell) return self:getCellInMatrix(self.collidableMatrices[color], cell) end,
function(cell) return self:isInBounds(cell) end
)
end
---PULL CHEC
-- PULL ---------------------------------------------------------------
local initialTargetCell = {x = pos.x - dir.x, y = pos.y - dir.y}
local targetCells
local pull
--for each color...
targetCells = {initialTargetCell} -- ...we start with our attempted movement...
local doneSearching
while not doneSearching do
nextTargetCells = {} -- ...then we create this array to save our next group of cells
local emptyCells = {}
for _, cell in pairs(targetCells) do
if self:isInBounds(cell) then
local entity = self:getCellInMatrix(self.collidableMatrices[color], cell)
if entity then
--something is here!!
if not entitiesToPull[entity] then --if the entity hasnt been found already
if entity:canMove() then
local projectedCells = entity:getOccupiedCells(dir) -- we project the movement here
entitiesToPull[entity] = entity
for _, projectedCell in ipairs(projectedCells) do
table.insert(nextTargetCells, projectedCell)
end
else
pull = false
doneSearching = true
end
end
else
--there's nothin there!!
table.insert(emptyCells, cell)
end
else
--we are out of bounds now
doneSearching = true
end
end
--if every projected cell is empty then we can do the move
if #emptyCells == #targetCells then
pull = true
doneSearching = true
end
targetCells = nextTargetCells
local pull = false
if self:isInBounds(initialTargetCell) then
pull, entitiesToPull = Movement.findMovableGroup(
{initialTargetCell}, dir,
function(cell) return self:getCellInMatrix(self.collidableMatrices[color], cell) end,
function(cell) return self:isInBounds(cell) end
)
end
if move then
@ -325,7 +249,11 @@ function Room:movePlayer(key)
end
if pull == true then
for _, entity in pairs(entitiesToPull) do
entity:move(axis, dir[axis])
-- A connected component can wrap around the player and be found by
-- both searches. Every entity still moves exactly one grid cell.
if not entitiesToPush[entity] then
entity:move(axis, dir[axis])
end
end
end
self.player[color]:move(axis, dir[axis])
@ -537,7 +465,7 @@ end
-- Instantiate one object from the flat {class,color,x,y} schema. `class` names an
-- art asset, and its .meta declares the behaviour ("door"/"switch"/"player"/
-- "moveable"); anything without a .meta defaults to immoveable. npc is the one
-- "moveable"/"sticky"/"skewer"); anything without a .meta defaults to immoveable. npc is the one
-- keyword handled directly since it has no art.
function Room:createEntity(class, color, x, y)
if class == "npc" then
@ -577,6 +505,10 @@ function Room:createEntity(class, color, x, y)
if cellShape and #cellShape == 0 then cellShape = nil end
if behavior == "moveable" then
entity = GenericMoveable:new(x, y, color, sprite, class, cellShape)
elseif behavior == "sticky" then
entity = GenericSticky:new(x, y, color, sprite, class, cellShape)
elseif behavior == "skewer" then
entity = GenericSkewer:new(x, y, color, sprite, class, cellShape)
else
entity = GenericUnmoveable:new(x, y, color, sprite, cellShape)
end