From 3930b2b5d45f96dc3e52f2b60fcc34279bb7820e Mon Sep 17 00:00:00 2001 From: parameterized Date: Fri, 21 Sep 2018 03:35:00 -0400 Subject: [PATCH] sort draw order by y/layer/type --- entities.lua | 22 ++++-- entityDefs/slime.lua | 8 +- hud.lua | 9 +++ loadassets.lua | 1 + lootBags.lua | 70 ++++++++--------- main.lua | 17 ++++- menu.lua | 3 +- player.lua | 178 +++++++++++++++++++++++-------------------- projectiles.lua | 57 +++++++------- scene.lua | 39 ++++++++++ utils.lua | 24 ++++++ 11 files changed, 273 insertions(+), 155 deletions(-) create mode 100644 scene.lua diff --git a/entities.lua b/entities.lua index 270f6e3..54b2ff2 100644 --- a/entities.lua +++ b/entities.lua @@ -61,12 +61,22 @@ end function entities.client.draw() for _, v in pairs(client.currentState.entities) do if not v.destroyed and v.drawBody then - v:drawBody() - end - end - for _, v in pairs(client.currentState.entities) do - if not v.destroyed and v.drawHP then - v:drawHP() + scene.add{ + draw = function() + v:drawBody() + end, + y = v.y, + type = 'entityBody' + } + if v.drawHP then + scene.add{ + draw = function() + v:drawHP() + end, + y = v.y, + type = 'entityHP' + } + end end end end diff --git a/entityDefs/slime.lua b/entityDefs/slime.lua index 2f64f25..adefc1e 100644 --- a/entityDefs/slime.lua +++ b/entityDefs/slime.lua @@ -41,7 +41,7 @@ function slime.server:spawn() if (i2-1) % 2 == 0 then -- x v[i2] = v2*img:getWidth() - img:getWidth()/2 else - v[i2] = v2*img:getWidth()*-1 + img:getHeight()/2 + v[i2] = v2*img:getWidth()*-1 end end end @@ -156,7 +156,7 @@ function slime.client:spawn() if (i2-1) % 2 == 0 then -- x v[i2] = v2*img:getWidth() - img:getWidth()/2 else - v[i2] = v2*img:getWidth()*-1 + img:getHeight()/2 + v[i2] = v2*img:getWidth()*-1 end end end @@ -215,7 +215,7 @@ function slime.client:drawBody() love.graphics.draw(img, 0, 0, 0, 1, 1, - lume.round(img:getWidth()/2), lume.round(img:getHeight()/2)) + lume.round(img:getWidth()/2), img:getHeight()) love.graphics.pop() love.graphics.setShader(_shader) end @@ -236,7 +236,7 @@ function slime.client:drawHP() love.graphics.push() local vx, vy = self.body:getPosition() love.graphics.translate(lume.round(vx), lume.round(vy)) - love.graphics.draw(canvases.hpBar, lume.round(-canvases.hpBar:getWidth()/2), 10) + love.graphics.draw(canvases.hpBar, lume.round(-canvases.hpBar:getWidth()/2), 2) love.graphics.pop() end diff --git a/hud.lua b/hud.lua index 1dfc44e..5823f12 100644 --- a/hud.lua +++ b/hud.lua @@ -149,6 +149,7 @@ end function hud.mousepressed(mx, my, btn) mx, my = window2game(mx, my) + mx, my = lume.round(mx), lume.round(my) local chatFieldPressed = false for _, v in pairs(hud.buttons) do if mx > v.x and mx < v.x + v.img:getWidth() and my > v.y and my < v.y + v.img:getHeight() then @@ -168,6 +169,7 @@ end function hud.draw() local mx, my = window2game(love.mouse.getPosition()) + mx, my = lume.round(mx), lume.round(my) love.graphics.setColor(1, 1, 1) love.graphics.draw(gfx.hud.frame, 0, 0) @@ -230,4 +232,11 @@ function hud.draw() love.graphics.setColor(1, 1, 1) love.graphics.setFont(fonts.c17) text.print(player.name, 44, 5) + + -- draggables + local heldItem = lootBags.client.heldItem + if heldItem.bagId then + love.graphics.setColor(1, 1, 1, 0.8) + love.graphics.rectangle('fill', mx + heldItem.offset.x, my + heldItem.offset.y, 15, 15) + end end diff --git a/loadassets.lua b/loadassets.lua index 298fd55..3f8adf1 100644 --- a/loadassets.lua +++ b/loadassets.lua @@ -6,6 +6,7 @@ math.randomseed(love.timer.getTime()) love.keyboard.setKeyRepeat(true) love.graphics.setDefaultFilter('nearest', 'nearest') +love.graphics.setLineStyle('rough') gsx, gsy = 480, 270 canvases = { diff --git a/lootBags.lua b/lootBags.lua index 44e52b1..050d74a 100644 --- a/lootBags.lua +++ b/lootBags.lua @@ -135,41 +135,41 @@ function lootBags.client.draw() mx, my = lume.round(mx), lume.round(my) mx, my = camera:screen2world(mx, my) for _, bag in pairs(client.currentState.lootBags) do - local a = 1 - if bag.life and client.serverTime - bag.spawnTime > bag.life - 3 then - local t = (client.serverTime - bag.spawnTime - bag.life + 3)/3 - a = math.cos(t*5*math.pi)/4 + 1/4 + (1-t)/2 - end - love.graphics.setColor(1, 1, 1, a) - love.graphics.push() - love.graphics.translate(lume.round(bag.x), lume.round(bag.y)) - local img = gfx.items[bag.type] - love.graphics.draw(img, 0, 0, 0, 1, 1, lume.round(img:getWidth()/2), img:getHeight()) - if bag.id == lootBags.client.closest.id and lootBags.client.closest.dist < 30 then - local img = gfx.ui.bag - love.graphics.push() - love.graphics.translate(-lume.round(img:getWidth()/2), -img:getHeight() - 20) - love.graphics.draw(img, 0, 0) - local bmx = mx - (lume.round(bag.x) - lume.round(img:getWidth()/2)) - local bmy = my - (lume.round(bag.y) - img:getHeight() - 20) - for _, slot in ipairs(lootBags.client.slots) do - if bmx >= slot.x and bmx <= slot.x + slot.w - and bmy >= slot.y and bmy <= slot.y + slot.h then - love.graphics.setColor(1, 1, 1, 0.8) - else - love.graphics.setColor(1, 1, 1, 0.2) + scene.add{ + draw = function() + local a = 1 + if bag.life and client.serverTime - bag.spawnTime > bag.life - 3 then + local t = (client.serverTime - bag.spawnTime - bag.life + 3)/3 + a = math.cos(t*5*math.pi)/4 + 1/4 + (1-t)/2 end - love.graphics.rectangle('fill', slot.x, slot.y, slot.w, slot.h) - end - love.graphics.setColor(1, 0, 0, 0.4) - love.graphics.rectangle('fill', bmx, bmy, 2, 2) - love.graphics.pop() - end - love.graphics.pop() - end - local heldItem = lootBags.client.heldItem - if heldItem.bagId then - love.graphics.setColor(1, 1, 1, 0.8) - love.graphics.rectangle('fill', mx + heldItem.offset.x, my + heldItem.offset.y, 15, 15) + love.graphics.setColor(1, 1, 1, a) + love.graphics.push() + love.graphics.translate(lume.round(bag.x), lume.round(bag.y)) + local img = gfx.items[bag.type] + love.graphics.draw(img, 0, 0, 0, 1, 1, lume.round(img:getWidth()/2), img:getHeight()) + if bag.id == lootBags.client.closest.id and lootBags.client.closest.dist < 30 then + local img = gfx.ui.bag + love.graphics.push() + love.graphics.translate(-lume.round(img:getWidth()/2), -img:getHeight() - 20) + love.graphics.draw(img, 0, 0) + local bmx = mx - (lume.round(bag.x) - lume.round(img:getWidth()/2)) + local bmy = my - (lume.round(bag.y) - img:getHeight() - 20) + for _, slot in ipairs(lootBags.client.slots) do + if bmx >= slot.x and bmx <= slot.x + slot.w + and bmy >= slot.y and bmy <= slot.y + slot.h then + love.graphics.setColor(1, 1, 1, 0.8) + else + love.graphics.setColor(1, 1, 1, 0.2) + end + love.graphics.rectangle('fill', slot.x, slot.y, slot.w, slot.h) + end + love.graphics.setColor(1, 0, 0, 0.4) + love.graphics.rectangle('fill', bmx, bmy, 2, 2) + love.graphics.pop() + end + love.graphics.pop() + end, + y = bag.y + } end end diff --git a/main.lua b/main.lua index bafe051..99866a5 100644 --- a/main.lua +++ b/main.lua @@ -12,6 +12,7 @@ require 'client' require 'menu' require 'hud' require 'physics' +require 'scene' require 'world' require 'player' require 'projectiles' @@ -24,6 +25,7 @@ function love.load() gameState = 'menu' time = 0 gameTime = 0 + gcTimer = 10 -- don't shoot if pressing ui uiMouseDown = false drawDebug = false @@ -52,12 +54,14 @@ function setGameCanvas2x() local _color = {love.graphics.getColor()} love.graphics.setShader() love.graphics.setCanvas(canvases.game2x) + love.graphics.setBlendMode('alpha', 'premultiplied') love.graphics.setColor(1, 1, 1) love.graphics.push() love.graphics.origin() love.graphics.draw(canvases.game, 0, 0, 0, 2, 2) love.graphics.pop() love.graphics.setCanvas(canvases.game) + love.graphics.setBlendMode('alpha') love.graphics.clear() love.graphics.setCanvas(canvases.game2x) love.graphics.setShader(_shader) @@ -74,6 +78,11 @@ function love.update(dt) client.update(dt) end menu.update(dt) + gcTimer = gcTimer - dt + if gcTimer < 0 then + collectgarbage() + gcTimer = 10 + end end function love.mousepressed(x, y, btn, isTouch) @@ -139,6 +148,8 @@ end function love.draw() local mx, my = window2game(love.mouse.getPosition()) + mx, my = lume.round(mx), lume.round(my) + love.graphics.setBlendMode('alpha') love.graphics.setCanvas(canvases.game2x) love.graphics.clear() love.graphics.setCanvas(canvases.game) @@ -152,6 +163,9 @@ function love.draw() projectiles.client.draw() player.draw() + scene.draw() + scene.reset() + if drawDebug then if server.running then local serverBodies = physics.server.world:getBodies() @@ -177,7 +191,7 @@ function love.draw() chat.draw() love.graphics.setColor(1, 1, 1) - love.graphics.draw(gfx.cursors.main, lume.round(mx), lume.round(my), 0, 1, 1, 0, 0) -- hotspot 0, 0 + love.graphics.draw(gfx.cursors.main, mx, my, 0, 1, 1, 0, 0) -- hotspot 0, 0 end menu.draw() @@ -185,6 +199,7 @@ function love.draw() -- draw game on game2x setGameCanvas2x() love.graphics.setCanvas() + love.graphics.setBlendMode('alpha', 'premultiplied') love.graphics.clear(0, 0, 0) love.graphics.setColor(1, 1, 1) love.graphics.draw(canvases.game2x, ssx/2-gameScale*gsx/2, ssy/2-gameScale*gsy/2, 0, gameScale/2, gameScale/2) diff --git a/menu.lua b/menu.lua index 04440da..75c66d8 100644 --- a/menu.lua +++ b/menu.lua @@ -288,6 +288,7 @@ end function menu.mousepressed(mx, my, btn) mx, my = window2game(mx, my) + mx, my = lume.round(mx), lume.round(my) if gameState == 'menu' then menu.activeInput = nil for _, v in pairs(menu.buttons[menu.state] or {}) do @@ -363,7 +364,7 @@ end function menu.draw() if gameState == 'menu' then local mx, my = window2game(love.mouse.getPosition()) - + mx, my = lume.round(mx), lume.round(my) if menu.state == 'main' then love.graphics.setColor(1, 1, 1) local logoFrameIdx = math.floor(menu.logoAnimTimer*12) % #anims.logo.quads + 1 diff --git a/player.lua b/player.lua index 0fe2a53..b206cac 100644 --- a/player.lua +++ b/player.lua @@ -59,6 +59,7 @@ end function player.swing() local mx, my = window2game(love.mouse.getPosition()) + mx, my = lume.round(mx), lume.round(my) player.direction = mx < gsx/2 and -1 or 1 player.swinging = true player.swingTimer = 0 @@ -77,6 +78,7 @@ end function player.update(dt) local mx, my = window2game(love.mouse.getPosition()) + mx, my = lume.round(mx), lume.round(my) if not chat.active then local dx, dy = 0, 0 @@ -133,30 +135,105 @@ function player.mousereleased(x, y, btn) end function player.draw() - local _canvas = love.graphics.getCanvas() - local _shader = love.graphics.getShader() -- other players for _, v in pairs(client.currentState.players) do -- or debugger.show if v.id ~= player.id then + scene.add{ + draw = function() + local _canvas = love.graphics.getCanvas() + local _shader = love.graphics.getShader() + -- shadow + love.graphics.setColor(0, 0, 0, 0.2) + local shadowWidth = 5 + love.graphics.ellipse('fill', lume.round(v.x), lume.round(v.y), shadowWidth, 2) + + -- player + love.graphics.setCanvas(canvases.tempGame) + love.graphics.setShader() + love.graphics.clear() + love.graphics.setColor(1, 1, 1) + local quad = anims.player.swing.quads[1] + local _, _, w, h = quad:getViewport() + love.graphics.draw(anims.player.swing.sheet, quad, + lume.round(v.x), lume.round(v.y), + 0, 1, 1, + 23, h) + + -- outline + love.graphics.setCanvas(_canvas) + love.graphics.setShader(shaders.outline) + love.graphics.setColor(1, 1, 1) + love.graphics.push() + love.graphics.origin() + shaders.outline:send('stepSize', { + 1/canvases.tempGame:getWidth(), + 1/canvases.tempGame:getHeight() + }) + love.graphics.draw(canvases.tempGame, 0, 0) + love.graphics.pop() + love.graphics.setShader(_shader) + + -- name + local font = fonts.c17 + love.graphics.setFont(font) + text.printSmall(v.name, lume.round(v.x) - font:getWidth(v.name)/4, lume.round(v.y) - 40) + end, + y = v.y + } + end + end + + -- local player + + local px, py = player.body:getPosition() + local xv, yv = player.body:getLinearVelocity() + local vd = math.sqrt(xv^2 + yv^2) + + scene.add{ + draw = function() + local _canvas = love.graphics.getCanvas() + local _shader = love.graphics.getShader() -- shadow love.graphics.setColor(0, 0, 0, 0.2) - local shadowWidth = 5 - love.graphics.ellipse('fill', lume.round(v.x), lume.round(v.y), shadowWidth, 2) + local walkFrameIdx = math.floor(player.walkTimer*12) % #anims.player.walk.quads + 1 + local shadowWidth = ({6, 5, 4, 5, 5})[walkFrameIdx] + if player.swinging or vd < 10 then shadowWidth = 6 end + love.graphics.ellipse('fill', lume.round(px), lume.round(py), shadowWidth, 2) -- player love.graphics.setCanvas(canvases.tempGame) love.graphics.setShader() love.graphics.clear() love.graphics.setColor(1, 1, 1) - local quad = anims.player.swing.quads[1] - local _, _, w, h = quad:getViewport() - love.graphics.draw(anims.player.swing.sheet, quad, - lume.round(v.x), lume.round(v.y), - 0, 1, 1, - 23, h) + if player.swinging then + local frameIdx = math.floor(player.swingTimer*12) + 1 + frameIdx = lume.clamp(frameIdx, 1, 5) + local quad = anims.player.swing.quads[frameIdx] + local _, _, w, h = quad:getViewport() + love.graphics.draw(anims.player.swing.sheet, quad, + lume.round(px), lume.round(py), + 0, player.direction, 1, + 23, h) + else + if vd < 10 then + local quad = anims.player.swing.quads[1] + local _, _, w, h = quad:getViewport() + love.graphics.draw(anims.player.swing.sheet, quad, + lume.round(px), lume.round(py), + 0, player.direction, 1, + 23, h) + else + local quad = anims.player.walk.quads[walkFrameIdx] + local _, _, w, h = quad:getViewport() + love.graphics.draw(anims.player.walk.sheet, quad, + lume.round(px), lume.round(py), + 0, player.direction, 1, + 8, h) + end + end -- outline love.graphics.setCanvas(_canvas) @@ -175,77 +252,14 @@ function player.draw() -- name local font = fonts.c17 love.graphics.setFont(font) - text.printSmall(v.name, lume.round(v.x) - font:getWidth(v.name)/4, lume.round(v.y) - 40) - end - end - - -- local player - - local px, py = player.body:getPosition() - local xv, yv = player.body:getLinearVelocity() - local vd = math.sqrt(xv^2 + yv^2) + text.printSmall(player.name, lume.round(px) - font:getWidth(player.name)/4, lume.round(py) - 40) - -- shadow - love.graphics.setColor(0, 0, 0, 0.2) - local walkFrameIdx = math.floor(player.walkTimer*12) % #anims.player.walk.quads + 1 - local shadowWidth = ({6, 5, 4, 5, 5})[walkFrameIdx] - if player.swinging or vd < 10 then shadowWidth = 6 end - love.graphics.ellipse('fill', lume.round(px), lume.round(py), shadowWidth, 2) - - -- player - love.graphics.setCanvas(canvases.tempGame) - love.graphics.setShader() - love.graphics.clear() - love.graphics.setColor(1, 1, 1) - if player.swinging then - local frameIdx = math.floor(player.swingTimer*12) + 1 - frameIdx = lume.clamp(frameIdx, 1, 5) - local quad = anims.player.swing.quads[frameIdx] - local _, _, w, h = quad:getViewport() - love.graphics.draw(anims.player.swing.sheet, quad, - lume.round(px), lume.round(py), - 0, player.direction, 1, - 23, h) - else - if vd < 10 then - local quad = anims.player.swing.quads[1] - local _, _, w, h = quad:getViewport() - love.graphics.draw(anims.player.swing.sheet, quad, - lume.round(px), lume.round(py), - 0, player.direction, 1, - 23, h) - else - local quad = anims.player.walk.quads[walkFrameIdx] - local _, _, w, h = quad:getViewport() - love.graphics.draw(anims.player.walk.sheet, quad, - lume.round(px), lume.round(py), - 0, player.direction, 1, - 8, h) - end - end - - -- outline - love.graphics.setCanvas(_canvas) - love.graphics.setShader(shaders.outline) - love.graphics.setColor(1, 1, 1) - love.graphics.push() - love.graphics.origin() - shaders.outline:send('stepSize', { - 1/canvases.tempGame:getWidth(), - 1/canvases.tempGame:getHeight() - }) - love.graphics.draw(canvases.tempGame, 0, 0) - love.graphics.pop() - love.graphics.setShader(_shader) - - -- name - local font = fonts.c17 - love.graphics.setFont(font) - text.printSmall(player.name, lume.round(px) - font:getWidth(player.name)/4, lume.round(py) - 40) - - if drawDebug then - love.graphics.setColor(1, 0, 0, 0.5) - love.graphics.circle('fill', - lume.round(px), lume.round(py), player.shape:getRadius()) - end + if drawDebug then + love.graphics.setColor(1, 0, 0, 0.5) + love.graphics.circle('fill', + lume.round(px), lume.round(py), player.shape:getRadius()) + end + end, + y = py + } end diff --git a/projectiles.lua b/projectiles.lua index dc93784..2640f9b 100644 --- a/projectiles.lua +++ b/projectiles.lua @@ -95,35 +95,40 @@ end function projectiles.client.draw() - local _canvas = love.graphics.getCanvas() - local _shader = love.graphics.getShader() for _, v in pairs(client.currentState.projectiles) do if v.startedMoving then - love.graphics.setCanvas(canvases.tempGame) - love.graphics.setShader() - love.graphics.clear() - love.graphics.setColor(192/255, 192/255, 192/255) - love.graphics.push() - love.graphics.translate(lume.round(v.x), lume.round(v.y)) - love.graphics.rotate(-v.angle) - for _, poly in pairs(v.polys) do - love.graphics.polygon('fill', poly) - end - love.graphics.pop() + scene.add{ + draw = function() + local _canvas = love.graphics.getCanvas() + local _shader = love.graphics.getShader() + love.graphics.setCanvas(canvases.tempGame) + love.graphics.setShader() + love.graphics.clear() + love.graphics.setColor(192/255, 192/255, 192/255) + love.graphics.push() + love.graphics.translate(lume.round(v.x), lume.round(v.y)) + love.graphics.rotate(-v.angle) + for _, poly in pairs(v.polys) do + love.graphics.polygon('fill', poly) + end + love.graphics.pop() - -- outline - love.graphics.setCanvas(_canvas) - love.graphics.setShader(shaders.outline) - love.graphics.setColor(1, 1, 1) - love.graphics.push() - love.graphics.origin() - shaders.outline:send('stepSize', { - 1/canvases.tempGame:getWidth(), - 1/canvases.tempGame:getHeight() - }) - love.graphics.draw(canvases.tempGame, 0, 0) - love.graphics.pop() - love.graphics.setShader(_shader) + -- outline + love.graphics.setCanvas(_canvas) + love.graphics.setShader(shaders.outline) + love.graphics.setColor(1, 1, 1) + love.graphics.push() + love.graphics.origin() + shaders.outline:send('stepSize', { + 1/canvases.tempGame:getWidth(), + 1/canvases.tempGame:getHeight() + }) + love.graphics.draw(canvases.tempGame, 0, 0) + love.graphics.pop() + love.graphics.setShader(_shader) + end, + y = v.y + } end end end diff --git a/scene.lua b/scene.lua new file mode 100644 index 0000000..2e70bd2 --- /dev/null +++ b/scene.lua @@ -0,0 +1,39 @@ + +scene = { + layers = {} +} + +-- todo: persistent scene: much faster sorting + +function scene.reset() + scene.layers = {} +end + +-- t = {draw=_, y=_, layer=_, type=_} +function scene.add(t) + if t.layer == nil then t.layer = 1 end + if scene.layers[t.layer] == nil then scene.layers[t.layer] = {} end + table.insert(scene.layers[t.layer], t) +end + +function scene.draw() + local layers = {} + for k, v in pairs(scene.layers) do + table.insert(layers, {k=k, v=v}) + end + layers = isort(layers, 'k') + for _, layer in ipairs(layers) do + local sorted = isort(layer.v, function(a, b) + if a.type == 'entityBody' and b.type == 'entityHP' then + return true + elseif a.type == 'entityHP' and b.type == 'entityBody' then + return false + else + return a.y < b.y + end + end) + for _, v in pairs(sorted) do + v.draw() + end + end +end diff --git a/utils.lua b/utils.lua index 84944df..0859fe5 100644 --- a/utils.lua +++ b/utils.lua @@ -45,3 +45,27 @@ ease = { function buildName(name, postfix) return name .. (postfix ~= 0 and '(' .. postfix .. ')' or '') end + +function isort(_t, comp, rev) + if comp == nil then + comp = function(a, b) return a < b end + elseif type(comp) ~= 'function' then + local k = comp + comp = function(a, b) return a[k] < b[k] end + end + if rev then + _comp = comp + comp = function(a, b) return not _comp(a, b) end + end + local t = {} + for i=1, #_t do + local v = _t[i] + local j = i - 1 + while j > 0 and not comp(t[j], v) do + t[j+1] = t[j] + j = j - 1 + end + t[j+1] = v + end + return t +end