diff options
| author | cursed22bc <admin@pixeldawn.org> | 2026-03-08 23:15:16 +0200 |
|---|---|---|
| committer | cursed22bc <admin@pixeldawn.org> | 2026-03-08 23:15:16 +0200 |
| commit | 97d0d1ecc0cfd5516cfad2d477faa4d35992e7ba (patch) | |
| tree | 5ba61a59723d5c9ceb8059388d35bdcb069af743 /world.lua | |
| parent | aeb596379bbf1bec84efb294ff5bbbee922364ba (diff) | |
liquid shader and basic text render
Diffstat (limited to 'world.lua')
| -rw-r--r-- | world.lua | 146 |
1 files changed, 126 insertions, 20 deletions
@@ -2,6 +2,7 @@ local Tilemap = require("tilemap") local Entity = require("entity") local Player = require("player") local Camera = require("camera") +local Textbox = require("textbox") local World = {} World.__index = World @@ -21,12 +22,16 @@ function World:new() self.liquidPolygons = {} self.liquidSurfaces = {} self.liquidSurfaceFixtures = {} + self.refractionCanvas = nil + self.liquidShader = nil + self.activeSplashes = {} self.camera = nil self.groundContacts = {} self.waterContacts = {} self.contactCounts = {} self.contactEntity = {} self.contactKind = {} + self.playerTextbox = Textbox:new() return self end @@ -129,6 +134,12 @@ function World:load(mapPath, tilesets) table.insert(self.liquidSurfaceFixtures, { body = body, fixture = fixture }) end + local ok, shader = pcall(love.graphics.newShader, "shaders/liquid.glsl") + self.liquidShader = ok and shader or nil + if not self.liquidShader then + print("Warning: liquid.glsl not loaded, using fallback (no refraction)") + end + end function World:_addContact(entity, kind) @@ -188,15 +199,19 @@ function World:_onBeginContact(udA, udB, nx, ny, contact) local function doWaterSplash(waterData, entity) if not (waterData and waterData.water and waterData.water.splash) then return end local centerX = 0 + local centerY = waterData.water.y or 0 local ok, x1, y1, x2, y2 = pcall(function() return contact:getPositions() end) if ok and x1 then centerX = (x1 + (x2 or x1)) * 0.5 + centerY = (y1 + (y2 or y1)) * 0.5 elseif entity and entity.body then centerX = entity.body:getX() + centerY = entity.body:getY() else centerX = waterData.water.x or 0 end waterData.water:splash(centerX, 2) + table.insert(self.activeSplashes, { x = centerX, y = centerY, t = 0 }) end if type(udA) == "table" and udA.type == "water" and self:_isTrackedEntity(udB) then @@ -325,32 +340,100 @@ function World:draw() 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) + local hasLiquid = (#self.liquidPolygons > 0 or #self.liquidSurfaces > 0) + local useRefraction = hasLiquid and self.liquidShader - love.graphics.setColor(0.25, 0.5, 0.9, 0.6) + if useRefraction then + local mainCanvas = love.graphics.getCanvas() + local cw, ch = mainCanvas:getDimensions() + if not self.refractionCanvas or self.refractionCanvas:getWidth() ~= cw or self.refractionCanvas:getHeight() ~= ch then + if self.refractionCanvas then self.refractionCanvas:release() end + self.refractionCanvas = love.graphics.newCanvas(cw, ch) + self.refractionCanvas:setFilter("linear", "linear") + end -for _, liquid in ipairs(self.liquidPolygons) do - if liquid.triangles then - for _, tri in ipairs(liquid.triangles) do - love.graphics.polygon("fill", tri) + love.graphics.push() + love.graphics.setCanvas(self.refractionCanvas) + love.graphics.clear(0, 0, 0, 1) + 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 + end + drawTileLayer(self.tilemap:getForegroundLayer(), mapTileW, mapTileH, tileGidInfo, viewMinX, viewMinY, viewMaxX, viewMaxY) + love.graphics.setCanvas(mainCanvas) + love.graphics.pop() + + love.graphics.push() + love.graphics.origin() + love.graphics.draw(self.refractionCanvas, 0, 0) + love.graphics.pop() + + local splash = self.activeSplashes[#self.activeSplashes] + local splashCenterX, splashCenterY = 0.5, 0.5 + local splashTime = 0 + if splash and self.camera then + local snapX = math.floor(self.camera.x) + local snapY = math.floor(self.camera.y) + local scale = self.camera._lastScale or 2 + splashCenterX = ((splash.x - snapX) * scale) / cw + splashCenterY = ((splash.y - snapY) * scale) / ch + splashTime = splash.t + end + + self.liquidShader:send("scene", self.refractionCanvas) + self.liquidShader:send("time", love.timer.getTime()) + self.liquidShader:send("resolution", { cw, ch }) + self.liquidShader:send("splashCenter", { splashCenterX, splashCenterY }) + self.liquidShader:send("splashTime", splashTime) + love.graphics.setShader(self.liquidShader) + + love.graphics.setColor(0.25, 0.5, 0.9, 0.5) + for _, liquid in ipairs(self.liquidPolygons) do + if liquid.triangles then + for _, tri in ipairs(liquid.triangles) do + love.graphics.polygon("fill", tri) + end + end + end + + for _, surface in ipairs(self.liquidSurfaces) do + if surface.drawFill then + surface:drawFill() + end + end + + love.graphics.setShader() + else + drawTileLayer(self.tilemap:getBackgroundLayer(), mapTileW, mapTileH, tileGidInfo, viewMinX, viewMinY, viewMaxX, viewMaxY) + drawTileLayer(self.tilemap:getGroundLayer(), mapTileW, mapTileH, tileGidInfo, viewMinX, viewMinY, viewMaxX, viewMaxY) + + love.graphics.setColor(0.25, 0.5, 0.9, 0.6) + for _, liquid in ipairs(self.liquidPolygons) do + if liquid.triangles then + for _, tri in ipairs(liquid.triangles) do + end + end end - end -end -love.graphics.setColor(1,1,1,1) + for _, surface in ipairs(self.liquidSurfaces) do + if surface.drawFill then + end + end + end -for _, surface in ipairs(self.liquidSurfaces) do - if surface.draw then - surface:draw() + for _, surface in ipairs(self.liquidSurfaces) do + if surface.drawLine then + surface:drawLine() + end end -end + love.graphics.setColor(1, 1, 1, 1) -for _, p in ipairs(self.liquidPolygons) do - love.graphics.circle("fill", p.x, p.y, 3) -end - for _, e in ipairs(self.entities) do - if e.draw then e:draw() else World.drawEntityDefault(e) end + if not useRefraction then + for _, e in ipairs(self.entities) do + if e.draw then e:draw() else World.drawEntityDefault(e) end + end + drawTileLayer(self.tilemap:getForegroundLayer(), mapTileW, mapTileH, tileGidInfo, viewMinX, viewMinY, viewMaxX, viewMaxY) end if DEBUG then @@ -358,7 +441,7 @@ end World.drawPhysicsBodyOutlines(self.groundEntities) end - drawTileLayer(self.tilemap:getForegroundLayer(), mapTileW, mapTileH, tileGidInfo, viewMinX, viewMinY, viewMaxX, viewMaxY) + self.playerTextbox:draw() end function World.drawPhysicsBodyOutlines(entityList) @@ -401,6 +484,11 @@ function World:update(dt) for _, liquid in ipairs(self.liquidPolygons) do if liquid:containsEntity(self.player) then self.player.isInLiquid = true break end end + if self.player.isInLiquid and not self.player.wasInLiquid then + local px = self.player.x + (self.player.width or 16) / 2 + local py = self.player.y - 20 + self.playerTextbox:show("Entered water!", { px, py, "center" }, "write", { life = 2, fontSize = 9, centeredText = true, wrapToFit = true }) + end end @@ -416,10 +504,28 @@ function World:update(dt) if surface.update then surface:update(dt) end end + for i = #self.activeSplashes, 1, -1 do + self.activeSplashes[i].t = self.activeSplashes[i].t + dt * 2 + if self.activeSplashes[i].t >= 1 then + table.remove(self.activeSplashes, i) + end + end + if #self.activeSplashes > 4 then + for _ = 1, #self.activeSplashes - 4 do + table.remove(self.activeSplashes, 1) + end + end + if self.camera then self.camera:setTarget(self.player) self.camera:update(dt) end + + if self.playerTextbox.active and self.player then + self.playerTextbox.x = self.player.x + (self.player.width or 16) / 2 + self.playerTextbox.y = self.player.y - 20 + end + self.playerTextbox:update(dt) end return World |
