【问题标题】:Decrease variable over a specific amount of time在特定时间内减少变量
【发布时间】:2018-01-25 23:14:43
【问题描述】:

所以当我的角色被敌人的火焰吐息击中时,我想营造角色被点燃的感觉。因此,当角色着火时,我希望他在特定的时间内失去特定的生命值。

例如;假设他着火了 3 秒,我想让他因为着火而失去 30 生命值,我将如何平均分配失去 30 生命值 3 秒?我不希望 30 点伤害立即施加到生命值上,我希望它慢慢地在玩家生命值上滴答作响,以便在 3 秒标记处造成 30 点伤害。

游戏是用c#制作的。

谢谢。

【问题讨论】:

  • Mathf.Lerp() 也可能很方便。这可以在没有协程的情况下轻松完成,只需在 Update() 中使用 bool 输入“decreaseHealth”方法。
  • 所以我尝试让计时器变量从 3 开始,然后从中减去 Time.deltaTime,直到计时器变为 0,从角色中减去 1 生命值。但是,如果我没记错的话,这显然不起作用,因为 Time.delta 时间是基于帧速率的。所以最终发生的事情是我的玩家会在这 3 秒内损失大量生命值。
  • 这样的事情应该在协程中完成,而不是在 void/Update 函数中。当我说东西时,我的意思是 “在 x 时间内做某事” 问题。检查我留下的答案。这应该可以解决您的问题。
  • 我最终使用了 couroutine

标签: c# unity3d


【解决方案1】:

所以这就是我最终要做的。它会导致着火的角色失去 30 点生命值,您可以看到生命值在滴答作响,而不是每隔一段时间就会发生。

  IEnumerator OnFire()
    {
        bool burning = true;
        float timer = 0;
        while (burning)
        {
            yield return new WaitForSeconds(0.1f);
            hp -= 1;
            timer += 0.1f;
            if (timer >= 3)
            {
                burning = false;
            }
        }
    }

【讨论】:

  • 这个计时器应该可以工作。我不知道您为什么选择硬编码每个值,而不是使用我提供的自动为您执行此操作的解决方案。如果要更改 30 生命值、递减持续时间或递减值,则基本上必须更改大部分值。编码愉快!
  • 我对其进行了硬编码只是为了在此处显示它,但我不会在我的代码中对其进行硬编码。感谢您的回答
【解决方案2】:

你可以使用 couroutines。像这样:

void OnHitByFire()
{
    StartCoroutine(DoFireDamage(5f, 4, 10f));
}

IEnumerator DoFireDamage(float damageDuration, int damageCount, float damageAmount)
{
    int currentCount = 0;
    while (currentCount < damageCount)
    {
        HP -= damageAmount;
        yield return new WaitForSeconds(damageDuration);
        currentCount++;
    }
}

【讨论】:

  • 为什么这甚至被投票或接受为答案? 1.这行不通。它会在持续时间内减少一次生命,而不是在持续时间内。由于WaitForSeconds(damageDuration),它将简单地在一个循环中完成。 damageCount 和 damageAmount 参数....它们的意思不是一样的吗?不要盲目投票或接受答案。阅读代码并确保它完成了它应该做的事情。这个答案不会帮助有同样问题的人。
  • WaitForSeconds(damageDuration) 不会让它运行一次,它会让它等待 5 秒,然后根据他的示例再次运行,但它仍然会运行 4 次。我真正需要做的就是使用我自己的价值观来获得我想要的结果
  • WaitForSeconds(damageDuration) 将等待传递给它的持续时间,并且不会超时执行此操作。 “它没有专门回答这个问题” 程序员的answer 确实用正确的代码回答了您的问题,该代码可以正常运行并且可能会帮助其他人。我并不是要告诉你接受哪个答案。只是想说接受无效的答案对社区没有帮助。如果这对你有用,那么很好,但它不是因为我测试了两个答案,而程序员的答案是唯一有效的答案。
  • 好吧,这很公平。所以我不接受这个并发布我用作答案的内容。
  • 嗯,这就是为什么我的答案以 something like this 开头的原因。正如我所说,这只是协程如何工作的一个例子,而不是最后一段代码。冷静点,@PassetCronUs
【解决方案3】:

这就像moving Gameobject over time 或随着时间的推移做某事。唯一的区别是您必须使用Mathf.Lerp 而不是Vector3.Lerp。您还需要通过从玩家生命的当前值中减去您想要随着时间而失去的值来计算最终值。您将其传递给bMathf.Lerp 函数的第二个参数。

bool isRunning = false;

IEnumerator loseLifeOvertime(float currentLife, float lifeToLose, float duration)
{
    //Make sure there is only one instance of this function running
    if (isRunning)
    {
        yield break; ///exit if this is still running
    }
    isRunning = true;

    float counter = 0;

    //Get the current life of the player
    float startLife = currentLife;

    //Calculate how much to lose
    float endLife = currentLife - lifeToLose;

    //Stores the new player life
    float newPlayerLife = currentLife;

    while (counter < duration)
    {
        counter += Time.deltaTime;
        newPlayerLife = Mathf.Lerp(startLife, endLife, counter / duration);
        Debug.Log("Current Life: " + newPlayerLife);
        yield return null;
    }

    //The latest life is stored in newPlayerLife variable
    //yourLife = newPlayerLife; //????

    isRunning = false;
}

用法

假设玩家的生命是50,我们想在3 秒内删除2。新玩家的生命应该是在3秒之后的48

StartCoroutine(loseLifeOvertime(50, 2, 3));

请注意,玩家的生命存储在newPlayerLife 变量中。在协程函数结束时,您必须手动使用来自newPlayerLife 变量的值来分配玩家的生命。

【讨论】:

  • 就我而言,while 循环只运行一次。 counter 绝对小于duration(正如我使用Debug.Log() 检查的那样)。为什么会发生这种情况?澄清一下,这个脚本每次迭代都应该将newPlayerLife写入日志,不是吗(在我的情况下只写入日志一次,让我相信while循环只执行一次)?
  • 将编辑添加到您的question,后跟您当前使用的代码以及您的使用方式。我会更愿意提供帮助。
  • 如果您在协程仍在运行时再次尝试减少生命,这将不起作用。所以如果你多次受到伤害,它只会减少一次。
【解决方案4】:

我想,您正在寻找的是协程。查看 herehere 获取文档。它将允许您与更新功能分开执行您的自定义健康减少操作。使用协程,您可以通过滴答声来完成某些事情,并且您可以确定滴答声的时间。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-12-09
    • 2021-03-19
    • 2023-02-02
    • 1970-01-01
    • 1970-01-01
    • 2020-08-22
    • 2013-03-17
    • 1970-01-01
    相关资源
    最近更新 更多