Preview adjacent rooms during transitions

This commit is contained in:
Your Name 2026-08-12 02:50:48 -04:00
parent 23fe9d1c58
commit 794b4dc162
2 changed files with 62 additions and 1 deletions

View file

@ -131,6 +131,10 @@ function Room:update(dt)
end end
function Room:draw() function Room:draw()
if gameWorld and gameWorld.levels and gameWorld.levels[self.name] == self and
not gameWorld.drawingRoomNeighborhood then
return gameWorld:drawRoomNeighborhood(self)
end
self:drawWiresAt(0, 0, width / gridWidth, nil, false) self:drawWiresAt(0, 0, width / gridWidth, nil, false)
-- draw only the channels the player has. Each object just exposes sprites per -- draw only the channels the player has. Each object just exposes sprites per
@ -139,7 +143,13 @@ function Room:draw()
for _, channel in ipairs(self.colorsPlayerHas) do for _, channel in ipairs(self.colorsPlayerHas) do
if self.player[channel] then self.player[channel]:draw(channel) end if self.player[channel] then self.player[channel]:draw(channel) end
for _, entity in pairs(self.collideables[channel]) do entity: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 -- The zoomed-out neighbourhood already draws every room directly. Calling
-- the legacy seam helper from each miniature room duplicates foreign
-- entities, which can screen-blend red and green into a false yellow.
if gameWorld and gameWorld.levels and gameWorld.levels[self.name] == self and
not gameWorld.drawingRoomNeighborhood then
gameWorld:drawOverlaps(self, channel)
end
for _, blocker in pairs(self.playerBlockers[channel]) do blocker:draw(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 _, switch in pairs(self.switches[channel]) do switch:draw(channel) end
for _, switch in ipairs(self.wiredSwitches) do switch:draw(channel) end for _, switch in ipairs(self.wiredSwitches) do switch:draw(channel) end

View file

@ -796,6 +796,8 @@ function World:nextRoom(room, pos)
elseif pos.y > gridHeight then exit, entry.y = "bottom", 1 elseif pos.y > gridHeight then exit, entry.y = "bottom", 1
elseif pos.y < 1 then exit, entry.y = "top", gridHeight end elseif pos.y < 1 then exit, entry.y = "top", gridHeight end
local nextName = self:getNeighbor(room.name, exit) or room.name local nextName = self:getNeighbor(room.name, exit) or room.name
local sourceLocation = self:roomLocation(room.name)
local destinationLocation = self:roomLocation(nextName)
local activeColors = room:getActiveColors() local activeColors = room:getActiveColors()
self:markDirty(room) self:markDirty(room)
local destination = self.levels[nextName] local destination = self.levels[nextName]
@ -817,6 +819,13 @@ function World:nextRoom(room, pos)
end end
room.activeColors = {red = false, green = false, blue = false} room.activeColors = {red = false, green = false, blue = false}
currentRoom = destination currentRoom = destination
if sourceLocation and destinationLocation and nextName ~= room.name then
self.roomTransition = {
startedAt = love.timer.getTime(), duration = 0.28,
dx = destinationLocation.x - sourceLocation.x,
dy = destinationLocation.y - sourceLocation.y,
}
end
self:markDirty(currentRoom) self:markDirty(currentRoom)
for _, color in ipairs(activeColors) do for _, color in ipairs(activeColors) do
currentRoom.player[color].x, currentRoom.player[color].y = entry.x, entry.y currentRoom.player[color].x, currentRoom.player[color].y = entry.x, entry.y
@ -884,6 +893,48 @@ function World:drawOverlaps(room, color)
end end
end end
-- Render the active room at a small zoom-out, together with the eight world
-- neighbours around it. This is display-only: individual rooms still own
-- their data, collision, and authored boundary walls.
function World:drawRoomNeighborhood(room)
if self.drawingRoomNeighborhood then return end
local location = self:roomLocation(room.name)
if not location then return end
-- Leave enough margin to read several cells of each neighbour, not merely
-- its boundary wall. This keeps a nearby separated player discoverable.
local zoom = 0.78
local originX = (width - width * zoom) / 2
local originY = (height - height * zoom) / 2
local cameraX, cameraY = 0, 0
local transition = self.roomTransition
if transition then
local progress = math.min(1, (love.timer.getTime() - transition.startedAt) / transition.duration)
-- Smoothstep keeps the scene anchored at both ends instead of snapping
-- into or out of its small neighbourhood preview.
local eased = progress * progress * (3 - 2 * progress)
cameraX = transition.dx * (1 - eased)
cameraY = transition.dy * (1 - eased)
if progress >= 1 then self.roomTransition = nil end
end
self.drawingRoomNeighborhood = true
for roomY = -1, 1 do
for roomX = -1, 1 do
local name = self:roomAt(location.x + roomX, location.y + roomY)
local adjacent = name and self.levels[name]
if adjacent then
love.graphics.push()
love.graphics.translate(originX + (roomX + cameraX) * width * zoom,
originY + (roomY + cameraY) * height * zoom)
love.graphics.scale(zoom, zoom)
adjacent:draw()
love.graphics.pop()
end
end
end
self.drawingRoomNeighborhood = false
end
function World:getCellFromMousePos(mouseX, mouseY) function World:getCellFromMousePos(mouseX, mouseY)
return math.floor(mouseX / (width / self.width)) + 1, math.floor(mouseY / (height / self.height)) + 1 return math.floor(mouseX / (width / self.width)) + 1, math.floor(mouseY / (height / self.height)) + 1
end end