【问题标题】:How to continuously move a GameObject between two positions?如何在两个位置之间连续移动游戏对象?
【发布时间】:2019-05-24 00:09:26
【问题描述】:

我正在编写我的游戏 Boss 行为,在战斗的最后阶段,Boss 应该冲向玩家,然后回到原来的位置。等待 5 秒,然后执行相同操作。

我尝试使用协程和 Vector2.MoveTowards() 来实现这一点,但没有得到想要的效果,首先老板没有“移向”玩家,而是立即出现在目标位置,然后就呆在那里,没有后退。

下面是我的代码:

private Vector2 chargeTarget;
private Vector2 tankStartPosition;

void Start()
{
    chargeTarget = new Vector2(-5.0f, transform.position.y);
    tankStartPosition = transform.position;
}

void Update()
{
    if (Time.time > nextCharge)
    {
        StartCoroutine(TankCharge());
        nextCharge = Time.time + chargeRate;
    }
}

IEnumerator TankCharge()
{
    transform.position = Vector2.MoveTowards(tankStartPosition, chargeTarget, Time.deltaTime * chargeSpeed);

    transform.position = Vector2.MoveTowards(chargeTarget, tankStartPosition, Time.deltaTime * returnSpeed);
}

知道我在这里做错了什么吗?以及如何获得我想要的操作?

谢谢

【问题讨论】:

标签: c# unity3d


【解决方案1】:

调用MoveTowards 一次只会在游戏循环的迭代期间移动游戏对象一次。调用MoveTowards 一次不会将游戏对象一直移动到其目标(除非maxDistanceDelta 参数大到足以在一次迭代中将游戏对象移动到其目标)。

如果boss瞬间出现在目标身上,我猜你的chargeSpeed太大了。

您想要做的是每个Update 周期调用一次MoveTowards。但是,按照您执行协程的方式,协程只会移动游戏对象一次然后退出。通常协程内部会有一个循环(否则协程将在运行一次后退出)。像这样的:

IEnumerator TankCharge()
{
    while (Vector3.Distance(transform.position, chargeTarget.position) > Mathf.Epsilon)
    {
        // Adjust this so this game object doesn't move the entire
        // distance in one iteration
        float distanceToMove = Time.deltaTime * chargeSpeed;

        transform.position = Vector3.MoveTowards(transform.position, chargeTarget.position, distanceToMove)

        yield return null;
    }
}

但是,对于您的情况,您实际上并不需要协程。您可以直接在Update() 中执行此操作

    private bool returnToStart = false;
    private float timer;

    void Update
    {
        float distanceToMove = Time.deltaTime * chargeSpeed;

        if (timer <= 0)
        {
            if (!returnToStart)
            {
                transform.position = Vector3.MoveTowards(transform.position, chargeTarget.position, distanceToMove)

                // Target reached?  If so, start moving back to the original position
                if (Vector3.Distance(transform.position, chargeTarget.position) <= Mathf.Epsilon)
                {
                    returnToStart = true;
                    this.timer = this.chargeRate;
                }
            }
            else
            {
                transform.position = Vector3.MoveTowards(transform.position, tankStartPosition.position, distanceToMove)

                // Original position reached?  If so, start moving to the target
                if (Vector3.Distance(transform.position, tankStartPosition.position) <= Mathf.Epsilon)
                {
                    returnToStart = false;
                    this.timer = this.chargeRate;
                }
            }
        }
        else
        {
            this.timer -= Time.time;
        }
    }    

【讨论】:

  • 它应该是 if(transform.position == tankStartPosition.position) 和双 ==。还值得一提的是,Vector3== 运算符实际上使用 0.00001 的精度来表示相等,因此对象可能无法准确到达正确的位置。
  • @BenRubin 感谢您的解决方案。我在没有协程的情况下尝试了Update 内建议的方法,但它无法正常工作。每次if (Time.time &gt; nextCharge) 为真时,它都会逐渐向玩家移动。在较低的chargeSpeed 时,它会逐步移动,而在较高的值时,它会在两到三个即时移动中覆盖间隙。当它到达目标时,bool 设置为true,然后它开始逐步向后移动。它没有达到MoveTowards 的预期效果:(
  • @StuckInPhD 如果您使用我的方法在没有协程的情况下使用Update 完成所有操作,那么您不应该在其中包含if (Time.time &gt; nextCharge) 部分。如果删除后仍然无法正常工作,请使用新代码更新您的问题,我会看看能否给您答案。
  • @BenRubin 是的,你是对的,在删除 if (Time.time &gt; nextCharge) 条件后它工作得很好。但是,有了这个if 条件,我将如何控制两次收费之间的时间?现在它只是不断地来回走动。这很好,但我希望玩家在冲锋攻击后稍微喘口气。谢谢
  • @StuckInPhD 我编辑了我的答案以包括收费之间的延迟。
猜你喜欢
  • 2014-08-21
  • 2012-08-02
  • 2023-03-24
  • 1970-01-01
  • 1970-01-01
  • 2016-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多