首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >游戏角色没有用MoveTowards直线向目标跑去。

游戏角色没有用MoveTowards直线向目标跑去。
EN

Stack Overflow用户
提问于 2022-01-11 11:53:26
回答 1查看 74关注 0票数 0

这是一个基于回合的游戏,其中敌人的角色运行和击中玩家的角色,然后返回到它的开始位置。敌人的目标目标(玩家的角色之一)在每次回合后更新。在第一轮,一切都是正确的,字符沿着一条直线向目标移动。然而,在接下来的回合中,当目标发生变化时,它首先向前一个目标的位置跑去,然后移动到正确的目标,然后它不会立即返回开始位置。就像我说的,第一轮一切都是正确的,但是当目标改变时,这些行为就会发生。

代码语言:javascript
运行
复制
public Vector3 startPos;
public Vector3 targetPos;

void Start() 
{
  startPos = transform.position;
  targetPos = playerCharacter1.transform.position;
}

void Update() 
{
Move(targetPos);
}

public void Move(Vector3 targetPos)
{
        StartCoroutine(MoveOverTime());
       
        IEnumerator MoveOverTime()
        {
           while (transform.position != targetPos)
      
            {
                    transform.position = Vector3.MoveTowards(transform.position, targetPos, 0.04f * Time.deltaTime);
                    animator.Play("Run");
                    yield return null;
            }

                animator.Play("Attack");
                yield return new WaitForSeconds(0.2f);

            if (transform.localScale.x > 0f)
            {
                transform.localScale = new Vector3(-0.175f, 0.175f, 1f);
            }
            else
            {
                transform.localScale = new Vector3(0.175f, 0.175f, 1f);
            }
        
           while (transform.position != startPos)
            {
              
                transform.position = Vector3.MoveTowards(transform.position, startPos, 0.04f * Time.deltaTime);
                animator.Play("Run");
                yield return null;
            }

            if (transform.localScale.x < 0f)
            {
                transform.localScale = new Vector3(0.175f, 0.175f, 1f);
            }
            else
            {
                transform.localScale = new Vector3(-0.175f, 0.175f, 1f);
            }
            yield return null;
        }
}
EN

回答 1

Stack Overflow用户

发布于 2022-01-12 00:45:26

将targetPos移动到一个公共的全局值并不是一个好的解决方案!

使用您提供的代码,您实际上正在使用每个更新循环创建一个新的CoRoutine (正如@Fredrik所指出的)。使targetPos全球化似乎“有效”的原因是所有这些协作机制都将这个新的位置作为目标。然而,,您仍然在创建和执行许多只在它们最终到达transform.position == targetPos时才会停止的协同机制。

在这里,有一些事情你应该修复:

  1. 不要像您一样比较Vector3s (transform.position),因为它们是浮点数。使用:

代码语言:javascript
运行
复制
if (Vector3.Distance(transform.position, targetPos) < 0.001f)
...
OR
if (Vector3.Distance(transform.position, targetPos) < Vector3.kEpsilon)

请参阅此页面上的统一示例:https://docs.unity3d.com/ScriptReference/Vector3.MoveTowards.html

  1. 只创建一个协同器,并让它为您完成工作。StartCoRoutine返回一个CoRoutine值,该值可用于停止特定的Coroutine。(https://docs.unity3d.com/ScriptReference/MonoBehaviour.StopCoroutine.html)

代码语言:javascript
运行
复制
Coroutine moveRoutine;
...
if (moveRoutine == null)
    moveRoutine = StartCoroutine(MoveOverTime());

在您的MoveOverTime协同器的末尾,只需设置moveRoutine = null;,然后您将确保如果需要另一个coroutine,将启动一个。或者,您也可以使用设置的布尔值来跟踪是否有协同线。同样的原则。

  1. 更好的方法是,在Start()期间只启动1 Coroutine,并将其修改为不退出。创建协同线的开销很小。如果您知道您计划让1在您的MonoBehaviour还活着的整个时间运行,那么为什么不从一开始就启动一个并添加条件让它休眠(当您不希望它做任何事情时,就添加条件)。或者让它检查它是否必须做任何工作,如果没有,就立即进行yield return null;

  1. 考虑缓存您的WaitForSeconds。与任何其他对象一样,这只是一个对象,因此您可以执行以下操作:

代码语言:javascript
运行
复制
WaitForSeconds attackPause;
void Start()
{
    attackPause = new WaitForSeconds(0.2f);
}

然后,在您的协同线而不是yield return new WaitForSeconds(0.2f);中使用yield return attackPause;

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70666352

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档