构建递增计数器

当你在游戏中完成一个关卡时,它有时会以动画的方式显示你的分数。有时这涉及数字“旋转”,使得它们从最右边的列计数到下一列,依此类推,就像汽车的里程表,但速度要快得多。

在 Corona 中实现这种效果涉及一些简单的数学。让我们从一些初始设置开始

local scoreText = display.newText( "000000", display.contentCenterX, 60, native.systemFont, 48 )

这段代码非常简单——我们只需创建一个文本对象 scoreText,初始显示为 000000,位于屏幕的顶部中央区域。

控制速率

首先要理解的是,Corona 是一个基于帧的系统。这意味着屏幕基本上以固定的速度更新,通常称为**每秒帧数**。在每秒 60 帧的情况下,屏幕只能每 1/60 秒(16.6667 毫秒)更新一次,因此尝试强制更快的更新速率是徒劳的。

显然,游戏分数可能会有很大差异——一个游戏的最高分可能是 100 分,而另一个游戏的最高分可能是数百万分。因此,我们不希望计数器在每次帧更新时都以固定数量(如 +1)递增。如果是这样,1,000,000 的分数更新所需的时间太长——以每秒 60 帧的速度大约需要 16667 秒——而像 100 这样的分数完成得太快(大约 1.67 秒).

更好的解决方案是确定**动画应该运行多长时间**,然后计算每次帧更新时应该递增的数量。

确定增量

确定递增分数的数量可以通过一种称为**线性插值**的方法来完成。这基本上允许你根据某些条件计算两个值之间的中间点。让我们将一个用于此目的的函数添加到我们现有的代码中

local scoreText = display.newText( "000000", display.contentCenterX, 60, native.systemFont, 48 )

local function lerp( v0, v1, t )
    return v0 + t * (v1 - v0)
end

这个 lerp() 函数足够简单。我们取起始值和结束值之间的差v1 - v0并将其乘以我们想要知道增量的时间分数 (t)(更多内容见下文)。然后我们将其添加到起始值 (v0) 中。

递增分数

现在让我们添加一个 incrementScore() 函数,它将完成大部分实际工作

local scoreText = display.newText( "000000", display.contentCenterX, 60, native.systemFont, 48 )

local function lerp( v0, v1, t )
    return v0 + t * (v1 - v0)
end

local function incrementScore( target, amount, duration, startValue )

    local newScore = startValue or 0
    local passes = (duration/1000) * display.fps
    local increment = lerp( 0, amount, 1/passes )

    local count = 0
    local function updateText()
        if ( count <= passes ) then
            newScore = newScore + increment
            target.text = string.format( "%06d", newScore )
            count = count + 1
        else
            Runtime:removeEventListener( "enterFrame", updateText )
            target.text = string.format( "%06d", amount + (startValue or 0) )
        end
    end

    Runtime:addEventListener( "enterFrame", updateText )
end

如你所见,此函数接受四个参数

**在函数内部**,我们基本上采取以下步骤

  1. 我们设置一个临时值 newScore,其值为 startValue 参数(如果未提供 startValue,则为 0)。

  2. 接下来,我们计算达到最终分数值所需的“遍数”。这是由指定的持续时间(从毫秒转换为秒)乘以应用程序的每秒帧数设置确定的。例如,如果我们指定持续时间为 4000(4 秒),并且应用程序以每秒 60 帧的速度运行,则结果为4 * 60240 次。

  3. 在此之后,我们使用计算出的值运行 lerp() 函数。这将返回每次传递时计数器递增的数量,我们将其存储为 increment 变量。

  4. 在下一个块中,我们使用一个基本的计数器变量 (count) 和一个嵌套的 updateText() 函数。此函数将每帧运行一次(如步骤 5 中所述),总共运行指定的遍数,每次将 increment 值添加到分数中。然后将更新后的值设置为目标显示对象 (scoreText) 的 text 属性,但在使用 string.format() 将其**格式化**为显示为 6 位数字(带前导零)之前不会设置。

当计数持续时间完成时,我们停止每帧执行 updateText() 函数,然后将分数计数器设置为最终值,再次格式化为显示为 6 位数字(带前导零)。

注意
  • 分数计数器值的正确格式 (string.format()) 将取决于你的特定场景。如果你只计数到最大分数 100,则可能不应该将其格式化为 6 位数字,带前导零 —在这种情况下,格式说明符 "%03d"(3 位数字)比 "%06d" 更好。另请注意,格式化是完全可选的,如果不需要,则不需要应用**任何**格式化。

  • 有关字符串格式的进一步探讨,请参阅格式化字符串值教程。

  1. 在函数内的最后一行(第 25 行),我们只需启动在每个运行时帧上执行的 updateText() 函数(如上所述,当计数完成时,此过程将在第 20 行停止).

运行过程

运行计数过程很简单——只需使用所需的参数调用 incrementScore() 函数,例如

incrementScore( scoreText, 750800, 4000 )

这将使 scoreText 文本对象在 4 秒的总时间内从 000000 计数到 750800

总结

希望本教程能够帮助你开始为你的游戏使用经典的“旋转分数计数器”功能。只需 sedikit kreativitas,你就可以对其进行调整以适应几乎任何场景和任何最大分数阈值!