24. 继续,定时器,输入处理
周五,继续学习。
Timer
- 简单的 ID 自增
- 可以绑定一个
{min, max}的随机 delay - 可以绑定一个
count参数,表示 every 的重复次数 - 有安全隐患,在一次
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 TimerInput
简化再简化,只做了最简单的原生 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 Inputlua
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