summaryrefslogtreecommitdiff
path: root/world.lua
diff options
context:
space:
mode:
authorcursed22bc <admin@pixeldawn.org>2026-03-08 23:15:16 +0200
committercursed22bc <admin@pixeldawn.org>2026-03-08 23:15:16 +0200
commit97d0d1ecc0cfd5516cfad2d477faa4d35992e7ba (patch)
tree5ba61a59723d5c9ceb8059388d35bdcb069af743 /world.lua
parentaeb596379bbf1bec84efb294ff5bbbee922364ba (diff)
liquid shader and basic text render
Diffstat (limited to 'world.lua')
-rw-r--r--world.lua146
1 files changed, 126 insertions, 20 deletions
diff --git a/world.lua b/world.lua
index 5eaf1ce..86ab7ba 100644
--- a/world.lua
+++ b/world.lua
@@ -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