跳转至内容

24. 继续,定时器,输入处理

周五,继续学习。

Timer

  1. 简单的 ID 自增
  2. 可以绑定一个 {min, max} 的随机 delay
  3. 可以绑定一个 count 参数,表示 every 的重复次数
  4. 有安全隐患,在一次 pairs 循环中,删除 task 或增加 task 可能会导致问题
lua
local Timer = Object:extend()
local ID = 0

local function nextID()
    ID = ID + 1
    return tostring(ID)
end

local function random(a, b)
    a, b = a or 0, b or 1
    if a > b then a, b = b, a end
    return math.random() * (b - a) + a
end

function Timer:new()
    self.tasks = {}
end

function Timer:update(dt)
    for tag, task in pairs(self.tasks) do
        task.time = task.time + dt

        if task.type == 'after' then
            if task.time >= task.delay then
                task.action()
                self:cancel(tag)
            end
        elseif task.type == 'every' then
            if task.time >= task.delay then
                task.action()
                task.time = 0
                task.delay = self:getResolvedDelay(task.origin_delay)
                if task.count > 0 then
                    task.counter = task.counter + 1
                    if task.counter >= task.count then
                        task.after()
                        self:cancel(tag)
                    end
                end
            end
        end
    end
end

function Timer:after(delay, action, tag)
    tag = tag or nextID()
    self:cancel(tag)
    self.tasks[tag] = {
        type = 'after',
        time = 0,
        delay = self:getResolvedDelay(delay),
        action = action
    }
    return tag
end

function Timer:every(delay, action, count, after, tag)
    if type(count) == 'string' then
        tag, count = count, 0
    elseif type(count) == 'number' and type(after) == 'string' then
        tag = after
    else
        tag = tag or nextID()
    end

    self:cancel(tag)
    self.tasks[tag] = {
        type = 'every',
        time = 0,
        delay = self:getResolvedDelay(delay),
        origin_delay = delay,
        action = action,
        counter = 0,
        count = count or 0,
        after = after or function() end
    }
    return tag
end

function Timer:cancel(tag)
    self.tasks[tag] = nil
end

function Timer:destroy()
    self.tasks = {}
end

function Timer:getResolvedDelay(delay)
    if type(delay) == 'number' then
        return delay
    elseif type(delay) == 'table' then
        return random(delay[1], delay[2])
    end
end

return Timer

Input

简化再简化,只做了最简单的原生 API 封装,先试试够不够用。

lua
local Input = Object:extend()

function Input:new()
    self.binds = {}
    self.states = {}
    self.prev_states = {}
end

function Input:update()
    self.prev_states = {}
    for k, v in pairs(self.states) do
        self.prev_states[k] = v
    end
end

function Input:bind(key, action)
    if not self.binds[action] then
        self.binds[action] = {}
    end
    table.insert(self.binds[action], key)
end

function Input:unbind(action)
    self.binds[action] = nil
end

function Input:pressed(action)
    local keys = self.binds[action]
    for _, key in ipairs(keys) do
        if self.states[key] and not self.prev_states[key] then
            return true
        end
    end
    return false
end

function Input:released(action)
    local keys = self.binds[action]
    for _, key in ipairs(keys) do
        if not self.states[key] and self.prev_states[key] then
            return true
        end
    end
    return false
end

function Input:down(action)
    local keys = self.binds[action]
    for _, key in ipairs(keys) do
        if self.states[key] then
            return true
        end
    end
    return false
end

function Input:keypressed(key)
    self.states[key] = true
end

function Input:keyreleased(key)
    self.states[key] = false
end

function Input:mousepressed(button)
    self.states['m' .. button] = true
end

function Input:mousereleased(button)
    self.states['m' .. button] = false
end

return Input
lua
function love.load()
    input = Input()
    input:bind("space", "print")
    input:bind("m1", "print")
end

function love.update(dt)
    if input:pressed("print") then
        print("pressed")
    end

    if input:released("print") then
        print("released")
    end

    if input:down("print") then
        print("down")
    end

    input:update()
end

function love.keypressed(key)
    input:keypressed(key)
end

function love.keyreleased(key)
    input:keyreleased(key)
end

function love.mousepressed(x, y, button)
    input:mousepressed(button)
end

function love.mousereleased(x, y, button)
    input:mousereleased(button)
end