You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity开发FlappyBird如何实现开局1秒临时修改gravityScale后恢复

问题根因

你的计时器无法正常生效的核心原因是gravityTimer被声明为PlayerHalt方法的局部变量,每次方法被调用时(每帧都会执行一次),变量都会被重置为0f,永远无法累加到1秒阈值,因此重力始终被锁在0.2。

常见疑问解答
  • 计时器是否可以在非Update的函数中正常运行?
    可以,只需满足两个条件:
    1. 存储计时累计值的变量必须是类级别的成员字段,不能是方法内的局部变量,否则每次调用方法都会重置计时值。
    2. 计时逻辑需要能逐帧推进:要么承载逻辑的方法被逐帧调用,要么使用Unity协程、Invoke等原生延时调度接口,不需要依赖Update也能正常计时。比如完全可以把开局重力缓冲的逻辑全写在Start方法里通过协程实现。
  • 是否可以对gravity scale执行Lerp插值操作?
    完全可以。Rigidbody2D.gravityScale是可读写的float类型属性,只要传入合法浮点值就能正常生效,不存在引擎层面的限制,你注释里的Lerp写法逻辑本身是正确的。
修正后的实现代码

基于原有Update逻辑的修正版

先把计时器变量提为类成员,避免每帧重置:

// 类成员变量,不要声明在方法内部
private float gravityTimer = 0f;
private Rigidbody2D rb;

void Start()
{
    rb = GetComponent<Rigidbody2D>();
    // 开局初始化缓冲重力
    rb.gravityScale = 0.2f;
}

void Update()
{
    Jump();
    Rotation();
    PlayerHalt();
}

private void PlayerHalt()
{
    // 重力恢复完成后直接返回,减少不必要计算
    if (gravityTimer >= 1f)
    {
        rb.gravityScale = 1f;
        return;
    }

    gravityTimer += Time.deltaTime;
    // 1秒后直接切换重力的写法
    // if (gravityTimer < 1f)
    // {
    //     rb.gravityScale = 0.2f;
    // }
    // else
    // {
    //     rb.gravityScale = 1f;
    // }

    // 平滑过渡的Lerp写法,取消注释即可使用
    rb.gravityScale = Mathf.Lerp(0.2f, 1f, gravityTimer / 1f);
}

不依赖Update的协程实现(写在Start中即可正常运行)

如果不想把计时逻辑塞到Update里,可以用协程实现,逻辑更内聚:

void Start()
{
    rb = GetComponent<Rigidbody2D>();
    StartCoroutine(GravityRecover());
}

private IEnumerator GravityRecover()
{
    float duration = 1f;
    float timer = 0f;
    rb.gravityScale = 0.2f;
    while (timer < duration)
    {
        timer += Time.deltaTime;
        rb.gravityScale = Mathf.Lerp(0.2f, 1f, timer / duration);
        yield return null; // 等待下一帧继续执行
    }
    rb.gravityScale = 1f;
}

内容的提问来源于stack exchange,提问作者FratNightGaming

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 11:03:23