【问题标题】:Why doesn't my Object stop moving on transform.Translate?为什么我的对象在 transform.Translate 上没有停止移动?
【发布时间】:2019-10-19 02:13:26
【问题描述】:

我希望一个对象在每次变换时使另一个对象移动。翻译但对象在到达目的地时并没有停止移动。

我在我的脚本中尝试了几件事,但我不知道可能是什么问题。一件事是:我的代码中有几种方法可以使不同的段落中的一些东西以不同的方式移动。因此,我编写了一个小方法,它在 Input.GetKey() 上执行特定方法,以查看当我不执行其他方法时它是否相同,此外我还注释掉了 Update 中调用的所有内容以确保确定。没有其他移动方法应该影响对象。因此,我只会发布在更新中在 GetKey 上调用的受影响方法。

“transPointFirst”到“transPointFourth”是在检查器中传递的空游戏对象。我还检查了 transPoints 是否在运行时移动,但不是,每帧的位置相同。

private void ElevateCaptain()
{
    targetRigid.isKinematic = true;

    var transFirst = new Vector3(transPointFirst.localPosition.x, transPointFirst.localPosition.y, 0);
    var transSecond = new Vector3(transPointSecond.localPosition.x, transPointSecond.localPosition.y, 0);
    var transThird = new Vector3(transPointThird.localPosition.x, transPointThird.localPosition.y, 0);
    var transFourth = new Vector3(transPointFourth.localPosition.x, transPointFourth.localPosition.y, 0);

    target.transform.Translate(transFirst * Time.deltaTime, Space.World);

    if (target.transform.position == transFirst)
        target.transform.Translate(transSecond * Time.deltaTime, Space.World);

    else if (target.transform.position == transSecond)
        target.transform.Translate(transThird * Time.deltaTime, Space.World);

    else if (target.transform.position == transThird)
        target.transform.Translate(transFourth * Time.deltaTime, Space.World);

    else if (target.transform.position == transFourth)
    {
        targetRigid.isKinematic = false;
    }
}

所以,我希望我的目标移动到第一个翻译,如果达到,移动到第二个翻译,依此类推。事实是:目标朝着正确的方向移动,但从未停止。如果代码是这样执行的,或者我在第一次 transform.Translate 调用后遗漏了所有内容,都没有关系。对象移动到第一个点并且越来越远......当我选择另一个这些点作为第一个翻译时也是一样的。我希望有人可以帮助我。

【问题讨论】:

  • 你有一个没有 if 检查的 transform.Translate,所以它也会继续移动,你依赖 == 3 个浮点数,最好使用 vector3。距离和近似函数来检查它们是否是相同的位置。
  • @Eddge 我还尝试使用 Vector3.Distance 检查 if 条件。但是,transform.Translate 不应该移动到那个给定点而不是进一步吗?
  • 不,那会朝着
  • @Eddge 在我的回答中提到了它,但是在两个 Vector3s 上使用 == 已经检查了近似相等。你的第一部分是完全正确的。
  • @Ruzihm,我宁愿在我的代码中具体说明我在做什么,而不是将其留给可以在任何更新时更改的 api 规范。

标签: c# unity3d


【解决方案1】:

这里发生了很多事情。

如果您的transPointFirsttransPointSecond 等有任何父游戏对象,将它们的localPositiontargetposition 进行比较可能会出现意外行为。最好直接比较他们的position 字段。另外,如果他们位置的Z分量已经是0,你不需要创建一个重复的Vector3

Translate 期望方向向量乘以距离,但您给它的似乎是位置向量。您可能想使用Vector3.MoveTowards 来计算target 每帧的位置。您需要一个变量来设置您想要移动的速度,理想情况下它是一个公共字段,因此您可以在检查器中设置它。

另外,正如 Eddge 所说,在任何违背你想要的逻辑的情况下,你首先要这样做Translate

但是,在 Unity 中,Vector3==!= 运算符已经检查了近似相等,所以你在那里很好。

您还需要考虑当对象位于两个位置之间时帧上会发生什么。如果你在应该移动的每一帧上调用ElevateCaptain,你可以检查它的当前位置是否位于每对连续的点之间,或者有一些变量来跟踪它“触摸”了哪些点,所以远的。

更简单的方法是使用Coroutines,然后在您希望它开始移动时只调用一次ElevateCaptain。下面是一个示例,说明您的代码在这些更改和使用协程后可能会是什么样子:

public float elevateSpeed;
private bool captainElevating;

Start() 
{
    // ...
    captainElevating = false; 
    // ...
}

private void ElevateCaptain()
{
    if (!captainElevating) 
    {
        captainElevating = true;
        StartCoroutine("ElevateCaptainCoroutine");
    }
}

private IEnumerator ElevateCaptainCoroutine() 
{
    targetRigid.isKinematic = true

    while (target.transform.position != transPointFirst.position)
    {
        target.transform.position = Vector3.MoveTowards(
                target.transform.position,   
                transPointFirst.position,
                elevateSpeed * Time.deltaTime);
        yield return null;
    }

    while (target.transform.position != transPointSecond.position)
    {
        target.transform.position = Vector3.MoveTowards(
                target.transform.position,   
                transPointSecond.position,
                elevateSpeed * Time.deltaTime);
        yield return null;
    }

    while (target.transform.position != transPointThird.position)
    {
        target.transform.position = Vector3.MoveTowards(
                target.transform.position,   
                transPointThird.position,
                elevateSpeed * Time.deltaTime);
        yield return null;
    }

    while (target.transform.position != transPointFourth.position)
    {
        target.transform.position = Vector3.MoveTowards(
                target.transform.position,   
                transPointFourth.position,
                elevateSpeed * Time.deltaTime);
        yield return null;
    }

    targetRigid.isKinematic = false;
    captainElevating = false;
}

如果您决定走Coroutine 路线,您应该尝试只在希望目标开始 移动时调用ElevateCaptain 一次,尽管包含captainElevating 变量应该防止它在已经发生时被调用。

协程或其他方式,对此的改进可能是使用GameObjectList 并让协程循环遍历列表,将target 依次移向每个列表。这样,在检查器中,您可以将任意数量的transPoint GameObjects 拖到列表中并轻松更改它。协程方法的重复结构非常适合这样的循环。

【讨论】:

  • 这完全有效!非常感谢!实际上,我之前曾尝试过使用 MoveTowards 进行此操作,但是当我决定将 Object 设置为 kinematic 时,并没有考虑再次使用它,哈哈!我今天也讨论过使用协程,但没有明白这一点,直到你来了。但我从未想过使用 while 语句(可能是因为它通常会使我的游戏崩溃)。非常感谢您的时间和分享您的知识!这份清单也是我没想到的好主意。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-12
  • 1970-01-01
相关资源
最近更新 更多