Add world-level movement and seam rendering
This commit is contained in:
parent
a60f46d585
commit
1965e548b4
3 changed files with 386 additions and 27 deletions
97
room.lua
97
room.lua
|
|
@ -132,6 +132,7 @@ function Room:draw()
|
|||
for _, channel in ipairs(self.colorsPlayerHas) do
|
||||
if self.player[channel] then self.player[channel]:draw(channel) end
|
||||
for _, entity in pairs(self.collideables[channel]) do entity:draw(channel) end
|
||||
if gameWorld and gameWorld.levels and gameWorld.levels[self.name] == self then gameWorld:drawOverlaps(self, channel) end
|
||||
for _, blocker in pairs(self.playerBlockers[channel]) do blocker:draw(channel) end
|
||||
for _, switch in pairs(self.switches[channel]) do switch:draw(channel) end
|
||||
for _, npc in ipairs(self.npcs) do npc:draw(channel) end
|
||||
|
|
@ -181,7 +182,7 @@ function Room:createEntityMatrix(entities)
|
|||
for _, entity in pairs(entities) do
|
||||
for _, occupiedCells in pairs(entity:getOccupiedCells()) do
|
||||
--we store a table reference so we can call a method on it during a chec_
|
||||
matrix[occupiedCells.y][occupiedCells.x] = entity
|
||||
if self:isInBounds(occupiedCells) then matrix[occupiedCells.y][occupiedCells.x] = entity end
|
||||
end
|
||||
end
|
||||
-- printMatrix(matrix)
|
||||
|
|
@ -193,7 +194,9 @@ function Room:getCellInMatrix(matrix, cell)
|
|||
return matrix[cell.y][cell.x]
|
||||
end
|
||||
|
||||
function Room:movePlayer(key)
|
||||
-- Kept for isolated room tests/editor previews. The live game goes through
|
||||
-- World:movePlayer so no gameplay decision is room-local.
|
||||
function Room:movePlayerLocal(key)
|
||||
|
||||
local moved = false
|
||||
local previousPositions = {} --these are so we can perform the overlap chec_
|
||||
|
|
@ -224,23 +227,36 @@ function Room:movePlayer(key)
|
|||
x = pos.x + dir.x, y = pos.y + dir.y
|
||||
} -- this is for reference for each color as we change the targetCells table
|
||||
|
||||
local useWorld = gameWorld and gameWorld.levels and gameWorld.levels[self.name] == self
|
||||
local context = useWorld and gameWorld:movementContext(self, color)
|
||||
local worldTarget = useWorld and context:worldCell(initialTargetCell)
|
||||
local initialTargetEntity
|
||||
|
||||
if self:isInBounds(initialTargetCell) then
|
||||
if useWorld then
|
||||
initialTargetEntity = context:entityAt(worldTarget)
|
||||
elseif self:isInBounds(initialTargetCell) then
|
||||
initialTargetEntity = self:getCellInMatrix(self.collidableMatrices[color], initialTargetCell)
|
||||
end
|
||||
|
||||
if initialTargetEntity then initialTargetEntity:bump() end
|
||||
local playerBlocker
|
||||
if self:isInBounds(initialTargetCell) and self.playerBlockerMatrices and self.playerBlockerMatrices[color] then
|
||||
if useWorld then
|
||||
playerBlocker = context:playerBlockerAt(worldTarget)
|
||||
elseif self:isInBounds(initialTargetCell) and self.playerBlockerMatrices and self.playerBlockerMatrices[color] then
|
||||
playerBlocker = self:getCellInMatrix(self.playerBlockerMatrices[color], initialTargetCell)
|
||||
end
|
||||
|
||||
if not self:isInBounds(initialTargetCell) then
|
||||
if useWorld and not context:isInBounds(worldTarget) then
|
||||
move = true
|
||||
elseif not useWorld and not self:isInBounds(initialTargetCell) then
|
||||
-- let's us move out of bounds to Change Rooms without pulling a bloc_
|
||||
move = true
|
||||
elseif playerBlocker and playerBlocker:blocksPlayer() then
|
||||
move = false
|
||||
elseif useWorld then
|
||||
move, entitiesToPush = Movement.findMovableGroup({worldTarget}, dir,
|
||||
function(cell) return context:entityAt(cell) end,
|
||||
function(cell) return context:isInBounds(cell) end)
|
||||
else
|
||||
move, entitiesToPush = Movement.findMovableGroup(
|
||||
{initialTargetCell}, dir,
|
||||
|
|
@ -253,7 +269,11 @@ function Room:movePlayer(key)
|
|||
|
||||
local initialTargetCell = {x = pos.x - dir.x, y = pos.y - dir.y}
|
||||
local pull = false
|
||||
if self:isInBounds(initialTargetCell) then
|
||||
if useWorld and context:isInBounds(context:worldCell(initialTargetCell)) then
|
||||
pull, entitiesToPull = Movement.findMovableGroup({context:worldCell(initialTargetCell)}, dir,
|
||||
function(cell) return context:entityAt(cell) end,
|
||||
function(cell) return context:isInBounds(cell) end)
|
||||
elseif not useWorld and self:isInBounds(initialTargetCell) then
|
||||
pull, entitiesToPull = Movement.findMovableGroup(
|
||||
{initialTargetCell}, dir,
|
||||
function(cell) return self:getCellInMatrix(self.collidableMatrices[color], cell) end,
|
||||
|
|
@ -262,10 +282,15 @@ function Room:movePlayer(key)
|
|||
end
|
||||
|
||||
if move then
|
||||
for _, entity in pairs(entitiesToPush) do
|
||||
entity:move(axis, dir[axis])
|
||||
if useWorld then
|
||||
local group = {}
|
||||
for entity in pairs(entitiesToPush) do group[entity] = entity end
|
||||
if pull then for entity in pairs(entitiesToPull) do group[entity] = entity end end
|
||||
gameWorld:moveGroup(group, dir)
|
||||
else
|
||||
for _, entity in pairs(entitiesToPush) do entity:move(axis, dir[axis]) end
|
||||
end
|
||||
if pull == true then
|
||||
if pull == true and not useWorld then
|
||||
for _, entity in pairs(entitiesToPull) do
|
||||
-- A connected component can wrap around the player and be found by
|
||||
-- both searches. Every entity still moves exactly one grid cell.
|
||||
|
|
@ -281,12 +306,20 @@ function Room:movePlayer(key)
|
|||
end
|
||||
|
||||
if moved then
|
||||
self:playerJoinCheck(previousPositions, newPositions)
|
||||
if useWorld then gameWorld:playerJoinCheck(self, previousPositions, newPositions)
|
||||
else self:playerJoinCheck(previousPositions, newPositions) end
|
||||
self:tick()
|
||||
end
|
||||
end
|
||||
|
||||
function Room:switchPlayerColor(color)
|
||||
function Room:movePlayer(key)
|
||||
if gameWorld and gameWorld.levels and gameWorld.levels[self.name] == self then
|
||||
return gameWorld:movePlayer(self, key)
|
||||
end
|
||||
return self:movePlayerLocal(key)
|
||||
end
|
||||
|
||||
function Room:switchPlayerColorLocal(color)
|
||||
-- Number keys can request a colour the player has not collected yet. Do
|
||||
-- nothing in that case: there is no corresponding player object to switch
|
||||
-- to (or use as the sound source).
|
||||
|
|
@ -304,6 +337,13 @@ function Room:switchPlayerColor(color)
|
|||
return canSwitch
|
||||
end
|
||||
|
||||
function Room:switchPlayerColor(color)
|
||||
if gameWorld and gameWorld.levels and gameWorld.levels[self.name] == self then
|
||||
return gameWorld:switchPlayerColor(self, color)
|
||||
end
|
||||
return self:switchPlayerColorLocal(color)
|
||||
end
|
||||
|
||||
function Room:setActiveColor(color, bool)
|
||||
self.activeColors[color] = bool
|
||||
end
|
||||
|
|
@ -361,7 +401,7 @@ function Room:onlyColorIsActive(color)
|
|||
end
|
||||
end
|
||||
|
||||
function Room:tick()
|
||||
function Room:tickLocal()
|
||||
for color, entityArray in pairs(self.collideables) do
|
||||
for _, entity in pairs(entityArray) do
|
||||
entity:tick()
|
||||
|
|
@ -371,6 +411,11 @@ function Room:tick()
|
|||
self:createPlayerBlockerMatrix()
|
||||
self:createSwitchMatrix()
|
||||
self:resolveSwitchesAndDoors()
|
||||
end
|
||||
|
||||
function Room:tick()
|
||||
if gameWorld and gameWorld.levels and gameWorld.levels[self.name] == self then return gameWorld:tick(self) end
|
||||
self:tickLocal()
|
||||
self:nextRoomCheck()
|
||||
end
|
||||
|
||||
|
|
@ -445,7 +490,14 @@ function Room:switchCheck()
|
|||
for color, switchArray in pairs(self.switches) do
|
||||
local onSwitches = {}
|
||||
for _, switch in pairs(switchArray) do
|
||||
local targetCell = self:getCellInMatrix(self.collidableMatrices[color], switch:getGridPos())
|
||||
local targetCell
|
||||
if gameWorld and gameWorld.levels and gameWorld.levels[self.name] == self then
|
||||
local cell = gameWorld:worldCell(self, switch:getGridPos())
|
||||
local row = cell and gameWorld.collidableMatrices[color][cell.y]
|
||||
targetCell = row and row[cell.x]
|
||||
else
|
||||
targetCell = self:getCellInMatrix(self.collidableMatrices[color], switch:getGridPos())
|
||||
end
|
||||
local player = self.player[color]
|
||||
-- Players are not stored in collidableMatrices, but a colour copy
|
||||
-- standing on its matching switch presses it just like a block does.
|
||||
|
|
@ -769,6 +821,7 @@ function Room:serialize(includePlayers)
|
|||
end
|
||||
|
||||
function nextRoom(pos)
|
||||
if gameWorld and currentRoom then return gameWorld:nextRoom(currentRoom, pos) end
|
||||
local exit
|
||||
local newPos = {x = pos.x, y = pos.y}
|
||||
if pos.x > gridWidth then
|
||||
|
|
@ -791,13 +844,17 @@ function nextRoom(pos)
|
|||
|
||||
-- Missing map neighbours intentionally wrap back into the room just exited.
|
||||
-- A placed neighbour gets the same carried player state at its opposite edge.
|
||||
currentRoom = Room:new{
|
||||
name = nextName or currentName,
|
||||
runtime = true,
|
||||
player = {
|
||||
x = newPos.x, y = newPos.y, activeColors = currentRoom:getActiveColors()
|
||||
}
|
||||
}
|
||||
local playerState = {x = newPos.x, y = newPos.y, activeColors = currentRoom:getActiveColors()}
|
||||
currentRoom = gameWorld and gameWorld.levels[nextName or currentName] or Room:new{name = nextName or currentName, runtime = true}
|
||||
if currentRoom then
|
||||
currentRoom.activeColors = {red = false, green = false, blue = false}
|
||||
for _, color in ipairs(playerState.activeColors) do
|
||||
if currentRoom.player[color] then currentRoom.player[color].x, currentRoom.player[color].y = playerState.x, playerState.y
|
||||
else currentRoom:registerPlayer(Player:new(playerState.x, playerState.y, color), color) end
|
||||
currentRoom:setActiveColor(color, true)
|
||||
end
|
||||
gameWorld:playerJoinCheck(currentRoom)
|
||||
end
|
||||
if gameWorld then gameWorld:setLastRoom(currentRoom.name) end
|
||||
if currentRoom.name then setEditorRoomName(currentRoom.name) end
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue