diff --git a/room.lua b/room.lua index a906c69..3f4b5b4 100644 --- a/room.lua +++ b/room.lua @@ -131,6 +131,10 @@ function Room:update(dt) end 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) -- 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 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 + -- 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 _, switch in pairs(self.switches[channel]) do switch:draw(channel) end for _, switch in ipairs(self.wiredSwitches) do switch:draw(channel) end diff --git a/world.lua b/world.lua index e455ba8..518be54 100644 --- a/world.lua +++ b/world.lua @@ -796,6 +796,8 @@ function World:nextRoom(room, pos) elseif pos.y > gridHeight then exit, entry.y = "bottom", 1 elseif pos.y < 1 then exit, entry.y = "top", gridHeight end 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() self:markDirty(room) local destination = self.levels[nextName] @@ -817,6 +819,13 @@ function World:nextRoom(room, pos) end room.activeColors = {red = false, green = false, blue = false} 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) for _, color in ipairs(activeColors) do currentRoom.player[color].x, currentRoom.player[color].y = entry.x, entry.y @@ -884,6 +893,48 @@ function World:drawOverlaps(room, color) 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) return math.floor(mouseX / (width / self.width)) + 1, math.floor(mouseY / (height / self.height)) + 1 end