diff options
| -rw-r--r-- | camera.lua | 1 | ||||
| -rw-r--r-- | main.lua | 9 | ||||
| -rw-r--r-- | world.lua | 96 |
3 files changed, 76 insertions, 30 deletions
@@ -97,6 +97,7 @@ function Camera:set(padding) local scaleY = canvasH / viewH local scale = math.floor(math.min(scaleX, scaleY)) + self._lastScale = scale love.graphics.scale(scale) @@ -1,7 +1,8 @@ local VIRTUAL_WIDTH, VIRTUAL_HEIGHT = 16*10*3, 9*10*3 local CANVAS_PADDING = 6 -DEBUG = true +DEBUG = false + local CANVAS_WIDTH = VIRTUAL_WIDTH + CANVAS_PADDING local CANVAS_HEIGHT = VIRTUAL_HEIGHT + CANVAS_PADDING local WORLD_TO_CANVAS = 3 @@ -50,7 +51,6 @@ function states.game.load() end function states.game.update(dt) - if camera then camera:update(dt) end if world then world:update(dt) end end @@ -147,8 +147,9 @@ function love.draw() subDx, subDy = world.camera:getSubPixelOffset() end - local uvOffsetX = subDx * WORLD_TO_CANVAS / CANVAS_WIDTH - local uvOffsetY = subDy * WORLD_TO_CANVAS / CANVAS_HEIGHT + local camScale = (world and world.camera and world.camera._lastScale) or 2 + local uvOffsetX = subDx * camScale / CANVAS_WIDTH + local uvOffsetY = subDy * camScale / CANVAS_HEIGHT if shaderEnabled and smoothCameraShader and (subDx ~= 0 or subDy ~= 0) then smoothCameraShader:send("offset", { uvOffsetX, uvOffsetY }) @@ -206,30 +206,62 @@ function World:getMapData() return self.mapData end -local function drawTileLayer(layer, mapTileW, mapTileH, tileGidInfo) +local function drawTileLayer(layer, mapTileW, mapTileH, tileGidInfo, viewMinX, viewMinY, viewMaxX, viewMaxY) if not layer or not layer.visible or not layer.data then return end local w = layer.width or 0 + local h = layer.height or 0 + if w == 0 or h == 0 then return end + + local minCol, maxCol, minRow, maxRow + if viewMinX and viewMaxX and viewMinY and viewMaxY then + minCol = math.max(0, math.floor(viewMinX / mapTileW)) + maxCol = math.min(w - 1, math.floor(viewMaxX / mapTileW)) + minRow = math.max(0, math.floor(viewMinY / mapTileH)) + maxRow = math.min(h - 1, math.floor(viewMaxY / mapTileH)) + else + minCol, maxCol = 0, w - 1 + minRow, maxRow = 0, h - 1 + end + + -- Collect tiles by image for SpriteBatch (reduces 770 draw calls to 1-2 batch draws) + local batches = {} + local fallbacks = {} local data = layer.data - for i, gid in ipairs(data) do - if gid and gid ~= 0 then - local idx = i - 1 - local tx = idx % w - local ty = math.floor(idx / w) - local x = tx * mapTileW - local y = ty * mapTileH - local info = tileGidInfo and tileGidInfo[gid] - if info then - love.graphics.draw(info.image, info.quad, x, y) - else - local r = ((gid * 17) % 256) / 255 - local g = ((gid * 31 + 50) % 256) / 255 - local b = ((gid * 47 + 100) % 256) / 255 - love.graphics.setColor(r, g, b, 1) - love.graphics.rectangle("fill", x, y, mapTileW, mapTileH) - love.graphics.setColor(1, 1, 1, 1) + for ty = minRow, maxRow do + for tx = minCol, maxCol do + local idx = ty * w + tx + 1 + local gid = data[idx] + if gid and gid ~= 0 then + local x = tx * mapTileW + local y = ty * mapTileH + local info = tileGidInfo and tileGidInfo[gid] + if info then + local img = info.image + batches[img] = batches[img] or {} + table.insert(batches[img], { quad = info.quad, x = x, y = y }) + else + table.insert(fallbacks, { x = x, y = y, gid = gid }) + end end end end + + for img, tiles in pairs(batches) do + local batch = love.graphics.newSpriteBatch(img, #tiles, "static") + for _, t in ipairs(tiles) do + batch:add(t.quad, t.x, t.y) + end + love.graphics.draw(batch) + end + + for _, t in ipairs(fallbacks) do + local r = ((t.gid * 17) % 256) / 255 + local g = ((t.gid * 31 + 50) % 256) / 255 + local b = ((t.gid * 47 + 100) % 256) / 255 + love.graphics.setColor(r, g, b, 1) + love.graphics.rectangle("fill", t.x, t.y, mapTileW, mapTileH) + love.graphics.setColor(1, 1, 1, 1) + end end function World:draw() @@ -237,8 +269,20 @@ function World:draw() local mapTileH = self.tilemap:getTileHeight() local tileGidInfo = self.tilemap:getTileGidInfo() - drawTileLayer(self.tilemap:getBackgroundLayer(), mapTileW, mapTileH, tileGidInfo) - drawTileLayer(self.tilemap:getGroundLayer(), mapTileW, mapTileH, tileGidInfo) + local viewMinX, viewMinY, viewMaxX, viewMaxY + if self.camera then + local cx, cy = self.camera.x, self.camera.y + local cw = self.camera.width or 0 + local ch = self.camera.height or 0 + local pad = math.max(mapTileW, mapTileH) * 2 + viewMinX = cx - pad + viewMinY = cy - pad + viewMaxX = cx + cw + pad + viewMaxY = cy + ch + pad + end + + drawTileLayer(self.tilemap:getBackgroundLayer(), mapTileW, mapTileH, tileGidInfo, viewMinX, viewMinY, viewMaxX, viewMaxY) + drawTileLayer(self.tilemap:getGroundLayer(), mapTileW, mapTileH, tileGidInfo, viewMinX, viewMinY, viewMaxX, viewMaxY) for _, e in ipairs(self.entities) do if e.draw then e:draw() else World.drawEntityDefault(e) end @@ -249,7 +293,7 @@ function World:draw() World.drawPhysicsBodyOutlines(self.groundEntities) end - drawTileLayer(self.tilemap:getForegroundLayer(), mapTileW, mapTileH, tileGidInfo) + drawTileLayer(self.tilemap:getForegroundLayer(), mapTileW, mapTileH, tileGidInfo, viewMinX, viewMinY, viewMaxX, viewMaxY) end function World.drawPhysicsBodyOutlines(entityList) @@ -280,17 +324,17 @@ function World:update(dt) if not self.physicsWorld then return end self.physicsWorld:update(PHYSICS_DT) - if self.camera then - self.camera:setTarget(self.player) - self.camera:update(dt) - end - for _, e in ipairs(self.entities) do if e.body then e:syncFromPhysicsBody() end if e.update then e:update(dt) end end + + if self.camera then + self.camera:setTarget(self.player) + self.camera:update(dt) + end end return World |
