lua os.clock

发表评论 阅读评论

我们游戏中两次切场景时间不能太短,所以我们在第一次切场景时记录当前时间,当用户再次切场景时使用判断记录的时间是否超过3秒,如果没有则提示“场景切换太频繁请等待xx秒再操作”,为了精确度量时间所以我用了lua的os.clockAPI,代码如下

出现问题

local time = os.clock()
local function checkTime()
    local now = os.clock()
    local remain = 3 + time - now
    if remain <= 0 then
        time = now
        return true
    end

    -- 显示提示
    return false
end

local function changeScene()
    if checkTime() then
        -- 真正的切场景
    end
end

每次切场景前调用changeScene()就可以了,经过测试没出现问题,就上线了。 第二天就有玩家反馈说提示需要28496秒才能切场景,而这个时间并不是固定,有时多,有时少。

解决历程

我设置的最大时间是3秒,显示结果竟然会大于3秒,肯定是 now 小于 time。但是为什么当前时间会小于过去的时间呢。我首先想到会不会是用户把时间调到之前的时间了,经测试还真的能够出现。 再跟玩家沟通后发现玩家并没有调整时间,再继续找问题。

经过Google搜索一番,发现lua的os.clock()会调用c的clock函数,该函数返回值依赖于操作系统,但依然返回一个从启动到现在的cpu执行时间。 查看os.clock的源码也验证了这一点。

clock函数有3个关键信息需要关心:

  1. clock 返回cpu滴答次数而非秒数
  2. clock_t clock (void) 返回类型为 clock_t,该类型在32位系统中是4字节,64位系统中是8字节
  3. CLOCKS_PER_SEC 表示每秒钟的时钟滴答次数

在mac上测试得到到CLOCKS_PER_SEC为1000000,也就是说 clock()/CLOCKS_PER_SEC为执行的秒数,如果在32位系统中有效时间最大为1小时10分钟。

Android系统都是32位,而且玩家挂机时很容易就能超过1小时的运行时间,所以问题就出在了clock溢出了。 所以只需要将上面的代码从os.clock修改为os.time就能解决当前时间小于过去时间的问题了。

再谈os.clock

上面使用os.time替换了os.clock解决了时间倒退的问题,但是丢失了时间的精度,因为os.time最小精度为1秒。还好切场景等待时间误差1秒也没关系。

有没有什么地方需要时间精度少于1秒呢,当然是有的,比如掉血后的血条过渡效果。

当显示血量从100掉到50时,血条需要花费1秒时间从100过渡到50,而不是立刻到达50。这时再用os.time将不能达到流畅的过渡效果,所以还得使用os.clock

既然os.clock在32位系统有溢出问题,导致当前时间小于过去的时间,显然不能不做处理就直接使用。 由于需要度量的时间很小,不会超过1小时(os.clock在32位系统的最大时间),那么可以在检查到溢出时修正当前时间就好。

local function clock(old)
    if not old then
        return os.clock()
    end

    local now = os.clock()
    if now < old then
        -- 4294.967296 = math.pow(2, 32)/CLOCKS_PER_SEC
        now = now + 4294.967296
    end
    return now
end
-- 使用
local begin = clock()
local function delatTime()
    return clock() - begin
end

总结

os.clock特点:

  • 可以度量小于1秒的时间
  • 在32位系统中有溢出风险,最大可度量的时间为 4294.967296,约1小时10分钟
  • 多线程/多进程中不同平台的返回时间不同

虽然os.clock有一些限制,但是在游戏中的一些短时间应用还是没有问题的。

标签: ,

  1. 本文目前尚无任何评论.
  1. 本文目前尚无任何 trackbacks 和 pingbacks.
回到顶部