acgstone

“跳啊!”
“我跳了!我真的跳了!!”
“我@#¥%……”

作为玩家的你在玩平台跳跃游戏的时候(e.g 硬核的超级肉食男孩,I wanna系列, 画面精美的Celeste等等)一定注意过一些问题,那就是跳跃“节奏”,这些跳跃游戏在“手感”的把握上极其出色,在不失爽快感的前提下保证玩家小心翼翼的操作,在玩家看来这是理所应当的。其实不然,今天看到了Lisa Brown的一篇文章《GameMaker Platformer Jumping Tips》,才发现游戏开发者设置其中的奥妙。

1. 土狼时间

这是一个2D平台跳跃游戏的术语,指玩家离开跳跃平台边缘,在短短数帧之内跳跃仍然有效的一段时间。这显然是违背真实世界的常理的,一般而言我们的游戏逻辑是:

IF(玩家在地面上)
    IF(玩家按下跳跃键)
        起跳!

这是理所当然的,不然牛顿就不高兴了。然而这是游戏的虚拟时间,一切皆有可能!我们就是这个世界的神!(笑)我们不妨来想一想,玩家总是希望自己的跳跃距离尽可能的远,那么一定会在最靠近边缘的地方按下跳跃键,然而游戏是以极高的帧数运行的,只靠人肉眼的反应时间是很难把握“最佳跳跃时间”,这时最有希望的措施就是给予一定的“宽限时间”,即土狼时间,外文称coyote time,Ledge Assistance,或grace period jumping。让我们在肉眼几乎捕捉不到的时间内使跳跃生效,看起来没有什么异常不是吗?

IF(玩家按下跳跃键)   
    重置宽限时间
IF(在宽限时间内)
    IF(玩家在地面上)
        起跳!

关于时间的把握,考虑到人反应时间大约220ms,通常的做法是把土狼时间设置在6帧左右,但要根据你游戏节奏来调整。这么说可能比较抽象,那么让我们来直观体验一下操作手感。

Lisa Brown制作的demo:Try the Ledge Assistance Demo

demo左上角调整宽限帧数(默认为0), 然后试着最大化跳跃到另一个平台。如果没有土狼时间,那么我们不可能完成目标!然而加上宽限时间这样就可以让玩家不打乱自己的“手感”而集中精神在“最佳时间”完成任务。

下面以unity为例,实现平台跳跃的土狼时间:

这是我们一般实现跳跃的主代码。

if (Input.GetKeyDown(KeyCode.Space))
{
    if (onGround)
    {
        rb2d.velocity = Vector2.up * jumpForce;
    }
}

image

我们先加入控制变量:graceJumpTime是宽限帧数,10帧只是为了体验相对清晰,可以适当调整。graceTimer为宽限时间计数器。

public int graceJumpTime = 10;
public int graceTimer;
    
//离开地面开始计时否则重置计时器
if (onGround)
{
    graceTimer = graceJumpTime;
}
else
{
    graceTimer--;
}
//加入土狼时间的跳跃
if (Input.GetKeyDown(KeyCode.Space))
{
    if (onGround|| graceTimer > 0)
    {
        rb2d.velocity = Vector2.up * jumpForce;
        graceTimer = 0;
    }
}

image

2. 跳跃输入缓冲

另一个技巧是输入缓冲,也许你仍然没听过,但别急,你肯定用过很多次在各种各样的游戏中。跳跃输入缓冲指玩家在未落地的数帧之内按下跳跃键使跳跃仍然有效的指令。理由同上,假设游戏以60帧的帧率运行,要想在player落地的那一帧快速按下跳跃是几乎不可能的,让我们亲自体验一下:

Lisa Brown制作的demo:Try the Ledge Assistance Demo

image

废话不多说,我们看一下unity实现:

 //input_buffer跳跃
if (Input.GetKeyDown(KeyCode.Space))
{
    jumpBufferTimer = jumpBuffer;
}

if (jumpBufferTimer > 0)
{
    if (onGround)
    {
        rb2d.velocity = Vector2.up * jumpForce;
        jumpBufferTimer = 0;
        }
        jumpBufferTimer--;
    }

image

下面整合一下以上两个技巧代码:

if (onGround)
{
    graceTimer = graceJumpTime;
}
else
{
    graceTimer--;
}
//input_buffer跳跃
if (Input.GetKeyDown(KeyCode.Space))
{
    jumpBufferTimer = jumpBuffer;
}
if (jumpBufferTimer > 0)
{
    if (onGround || graceTimer > 0)
    {
        rb2d.velocity = Vector2.up * jumpForce;
        jumpBufferTimer = 0;
        graceTimer = 0;
    }
    jumpBufferTimer--;
    mainCamera.backgroundColor = Color.red;
}

看!短短几行代码就可以时跳跃手感大大增加,是不是很神奇!附上文章相关连接,如果你有兴趣或正在做一款平台跳跃游戏,那么强烈建议去看一看这些细致的讲解。一定会受益匪浅。

GameMaker Platformer Jumping Tips

Platforming Ledge Forgiveness

Jump Input Buffering


附上工程源码的github地址:PlatformerJumpingTips

后记:作为unity初学者,这是我的第一篇博文,手打,测试,后期整理有些头疼(笑),一些东西可能没讲清,请多多包含。我的github页面,会偶尔更新一些有趣的unity知识,欢迎大家和我交流。

相关文章: