From 55f0d2f0da00a5df3d4421b01ccb3a1432b3748d Mon Sep 17 00:00:00 2001 From: Vodkannelle Date: Sat, 8 May 2021 18:13:33 +0200 Subject: [PATCH] added a timer for cleaner execution, goodbye resolver! --- crate.lua | 31 +++--- deps/knife/timer.lua | 244 +++++++++++++++++++++++++++++++++++++++++++ main.lua | 8 ++ 3 files changed, 268 insertions(+), 15 deletions(-) create mode 100644 deps/knife/timer.lua diff --git a/crate.lua b/crate.lua index 7c9ecfd..f6a8dbf 100644 --- a/crate.lua +++ b/crate.lua @@ -1,7 +1,9 @@ -- Chuchu by Makaron -- Crates are the main thing so here we go +local Timer = require('deps.knife.timer') -local CONST_ITERATIONS_RESOLVE = 1 +local CONST_ITERATIONS_RESOLVE = .01 +local CONST_TIME_TO_RELOAD = .4 local Crates = { world = nil, @@ -22,15 +24,16 @@ function Crate.new(world, x, y) object.attached = false object.contact = { } object.joint = nil - object.resolver = nil object.collider:setPresolve(function (shape1, shape2, contact) - print(shape2:getClass()) if shape2:getClass() == 'Player' and object.attached == false then contact:setEnabled(false) object.contact.x, object.contact.y = contact:getPositions() - object.resolver = CONST_ITERATIONS_RESOLVE object.attached = true + Timer.after(CONST_ITERATIONS_RESOLVE, function () + object.joint = Crates.world:addJoint('revolute', Crates.player.collider, object.collider, object.contact.x, object.contact.y, true) + table.insert(Crates.attached, object) + end) end end) @@ -49,23 +52,21 @@ function Crates:spawn(x, y) end function Crates:update(dt) - for key in pairs(self.list) do - if self.list[key].resolver ~= nil then - self.list[key].resolver = self.list[key].resolver - 1 - if self.list[key].resolver <= 0 then - curContact = self.list[key].contact - self.world:addJoint('revolute', self.player.collider, self.list[key].collider, curContact.x, curContact.y, true) - self.list[key].resolver = nil - table.insert(self.attached, self.list[key]) - end - end - end + Timer.update(dt) end function Crates:getAttached() return self.attached end +function Crates:detach(key) + self.attached[key].joint._joint:destroy() + Timer.after(CONST_TIME_TO_RELOAD, function () + self.attached[key].attached = false + table.remove(self.attached, key) + end) +end + return setmetatable(Crates, { __call = function(_, ...) return new(...) end }) diff --git a/deps/knife/timer.lua b/deps/knife/timer.lua new file mode 100644 index 0000000..0256c2c --- /dev/null +++ b/deps/knife/timer.lua @@ -0,0 +1,244 @@ +local Timer = {} + +-- group management + +local function detach (group, item) + local index = item.index + + group[index] = group[#group] + group[index].index = index + group[#group] = nil + item.groupField = nil +end + +local function attach (group, item) + if item.groupField then + detach (item.groupField, item) + end + + local index = #group + 1 + + item.index = index + group[index] = item + item.groupField = group + item.lastGroup = group +end + +-- instance update methods + +local function updateContinuous (self, dt) + local cutoff = self.cutoff + local elapsed = self.elapsed + dt + + if self:callback(dt) == false or elapsed >= cutoff then + if self.finishField then + self:finishField(elapsed - cutoff) + end + self:remove() + end + + self.elapsed = elapsed + + return +end + +local function updateIntermittent (self, dt) + local duration = self.delay or self.interval + local elapsed = self.elapsed + dt + + while elapsed >= duration do + elapsed = elapsed - duration + if self.limitField then + self.limitField = self.limitField - 1 + end + if self:callback(elapsed) == false + or self.delay or self.limitField == 0 then + if self.finishField then + self:finishField(elapsed) + end + self:remove() + return + end + end + + self.elapsed = elapsed +end + +local function updateTween (self, dt) + local elapsed = self.elapsed + dt + local plan = self.plan + local duration = self.duration + + self.elapsed = elapsed + + if elapsed >= duration then + for index = 1, #plan do + local task = plan[index] + + task.target[task.key] = task.final + end + if self.finishField then + self:finishField(elapsed - duration) + end + self:remove() + return + end + + local ease = self.easeField + + for index = 1, #plan do + local task = plan[index] + local target, key = task.target, task.key + local initial, change = task.initial, task.change + + target[key] = ease(elapsed, initial, change, duration) + end + +end + +-- shared instance methods + +local defaultGroup = {} + +local function group (self, group) + if not group then + group = defaultGroup + end + + attach(group, self) + + return self +end + +local function remove (self) + if self.groupField then + detach(self.groupField, self) + end + + return self +end + +local function register (self) + attach(self.lastGroup, self) + + return self +end + +local function limit (self, limitField) + self.limitField = limitField + + return self +end + +local function finish (self, finishField) + self.finishField = finishField + + return self +end + +local function ease (self, easeField) + self.easeField = easeField + + return self +end + +-- tweening helper functions + +local function planTween (definition) + local plan = {} + + for target, values in pairs(definition) do + for key, final in pairs(values) do + local initial = target[key] + + plan[#plan + 1] = { + target = target, + key = key, + initial = initial, + final = final, + change = final - initial, + } + end + end + + return plan +end + +local function easeLinear (elapsed, initial, change, duration) + return change * elapsed / duration + initial +end + +-- instance initializer + +local function initialize (timer) + timer.elapsed = 0 + timer.group = group + timer.remove = remove + timer.register = register + + attach(defaultGroup, timer) + + return timer +end + +-- static api + +function Timer.after (delay, callback) + return initialize { + delay = delay, + callback = callback, + update = updateIntermittent, + } +end + +function Timer.every (interval, callback) + return initialize { + interval = interval, + callback = callback, + update = updateIntermittent, + limit = limit, + finish = finish, + } +end + +function Timer.prior (cutoff, callback) + return initialize { + cutoff = cutoff, + callback = callback, + update = updateContinuous, + finish = finish, + } +end + +function Timer.tween (duration, definition) + return initialize { + duration = duration, + plan = planTween(definition), + update = updateTween, + easeField = easeLinear, + ease = ease, + finish = finish, + } +end + +function Timer.update (dt, group) + if not group then + group = defaultGroup + end + for index = #group, 1, -1 do + group[index]:update(dt) + end +end + +function Timer.clear (group) + if not group then + group = defaultGroup + end + for i = 1, #group do + group[i] = nil + end +end + +Timer.defaultGroup = defaultGroup + +return Timer diff --git a/main.lua b/main.lua index cd2486c..0ab1696 100644 --- a/main.lua +++ b/main.lua @@ -59,6 +59,7 @@ function love.load() input:bind(love.keyboard.getKeyFromScancode('d'), 'moveRight') input:bind(love.keyboard.getKeyFromScancode('s'), 'moveDown') input:bind(love.keyboard.getKeyFromScancode('space'), 'switch') + input:bind(love.keyboard.getKeyFromScancode('lshift'), 'detach') crates:init(world, magnet) crates:spawn(120, 400) @@ -91,6 +92,13 @@ function love.update(dt) else magnet.side = 'LEFT' end + elseif input:pressed('detach') then + velocity = {0, 0} + + local attached = crates:getAttached() + for key in pairs(attached) do + crates:detach(key) + end else if input:down('moveUp') or input:down('moveLeft') or input:down('moveRight') or input:down('moveDown') then if input:down('moveUp') then velocity[2] = -player.maxSpeed.y