【问题标题】:How can you check if object is moving/not moving?如何检查物体是否在移动/不移动?
【发布时间】:2019-02-13 13:37:13
【问题描述】:

我想做一个简单的脚本,当你点击屏幕时,游戏中的球会向右移动 (20000 * Time.deltaTime),然后如果我再次点击,它会向左移动然后对,以此类推。

我设法让球向右移动,但我需要它在动画完成后等待,因为我需要检查玩家是否再次点击(如果他再次点击,我需要检查移动的方向球)。 我尝试了很多我在网上找到的方法,比如检查 Rigidbody.velocity.magnitude == 0.0f 是否意味着球没有移动..

public Rigidbody rb;
public Transform PlayerPosition;
// Start is called before the first frame update
void Start()
{

}

// Update is called once per frame
void Update()
{
    if (Input.GetMouseButtonDown(0))
    {
        rb.AddForce(20000 * Time.deltaTime, 0, 0); // moving ball to the right
        while (rb.velocity.magnitude != 0.0f) // I tried to check until the ball is not moving 
        {

        }
        Debug.Log(PlayerPosition.position.x);
    }
}

这是我最近的尝试:

void Update()
{
    if (Input.GetMouseButtonDown(0))
    {
        rb.AddForce(20000 * Time.deltaTime, 0, 0); // moving ball to the right
        if(rb.velocity.magnitude < 0.05f) // if i click the ball it just prints it and not wating for the ball to not move
        {
            Debug.Log(PlayerPosition.position.x);
        }
    }
}

我希望输出等到动画完成,而是在我单击鼠标的那一刻打印 vaule(x)。

【问题讨论】:

    标签: c# unity3d


    【解决方案1】:

    编辑

    您需要检查您的动画是否仍在播放。你只检查你的速度是否大于 0.05f,这是正确打印出语句。

    使用Animation.IsPlaying(string name)。需要注意的是,此方法将返回 false 与调用它的 Update 相同的帧,因为从技术上讲,动画直到之后才开始。

    void Update()
    {
        if (!rb.velocity.magnitude <= 0.01f && !Animation.IsPlaying(nameOfAnimation))
        {
            Debug.Log("We're not moving and the animation is not playing");
        }
    }
    

    原创

    您不需要在 Update 方法中使用 while

    Update 中使用if 语句

    void Update()
    {
        if (rb.velocity.magnitude > 0.01f) Debug.Log("We're moving!");
    }
    

    【讨论】:

    • 我收到此错误:运算符“>”不能应用于“Vector3”类型的操作数
    • 我已将答案更新为使用rb.velocity.magnitude 来获取浮点数
    • 所以为了检查它是否没有移动你做 if (rb.velocity.magnitude != 0)?
    • “幅度”是一个绝对数字。我会检查它是否是&gt; 0 而不是!= 0,因为float 几乎永远不会是0。它们最终会变成0.000001
    • 您可以简单地检查幅度是否小于一个小值,例如 0.05 就像这样 rb.velocity.magnitude &lt; 0.05f
    【解决方案2】:

    第一

    rb.velocity.magnitude != 0.0f
    

    由于single precision floatong point ,几乎总是true:两个浮点值,即使它们看起来在逻辑上相等,也很可能不是。

    所以你可以使用你已经尝试过的阈值

    if(rb.velocity.magnitude <= 0.5f)
    

    或使用Mathf.Approximately,它使用非常小的Epsilon 或阈值进行比较

    if(Mathf.Approximately(rb.velocity.magintude, 0))
    

    听起来你想等到球停止移动然后输出位置 - 例如台球游戏。所以实际上似乎没有Animation参与。

    在大多数情况下,当您想到/提到“动画”时,实际上是指“随着时间的推移做某事”,不要将 AnimatorAnimation 组件与 Unity 中的 AnimationClips 混淆。

    您可以/应该为此使用Coroutine

    public Rigidbody rb;
    public Transform PlayerPosition;
    
    // a flag to make sure there is only one animation at a time
    private bool isMoving;
    
    // a flag for altering between left and right movement
    private bool isMovingRight;
    
    // Update is called once per frame
    void Update()
    {
        // only allow clicks while not moving already
        if (!isMoving && Input.GetMouseButtonDown(0))
        {
            // stop further input until not moving anymore
            isMoving = true;
    
            // add the force 
            // (you might btw want to skip that Time.deltaTime here it makes no sense)
            rb.AddForce(isMovingRight ? 20000 : -20000 * Time.deltaTime, 0, 0);
    
            // alter the direction for the next call
            isMovingRight = !isMovingRight;
    
            // if you rather want to be able to interrupt the current animation by clicking again
            // remove the isMoving flag and instead use this
            //StopCoroutine(WaitForMoveStops());  
    
            // Start the routine
            StartCoroutine(WaitForMoveStops());
        }
    }
    
    private IEnumerator WaitForMoveStops()
    {
        // Inside a Coroutine while is okey now
        // as long as you yield somwhere
    
        // check if velocity is below threshold
        while (!Mathf.Approximately(rb.velocity.magnitude, 0) 
        {
            // yield in simple words means "leave" this method here, render the frame
            // and than continue from here in the next frame
            yield return null;
        }
    
        // I would now hard reset the velocity just to be sure
        rb.velocity = Vector3.zero;
    
        Debug.Log(PlayerPosition.position.x);
    
        // whatever you want to do now
    
        // reset the flag to allow input again
        isMoving = false;
    }
    

    【讨论】:

      【解决方案3】:

      我想你想在它停止时移动它,然后只在它空闲时调用 AddForce:

      var wasMovingLastTime = false;    
      
      void Update()
      {
          var isMoving = rb.velocity.magnitude > 0f;
      
          if (wasMovingLastTime && !isMoving)
          {
              /// Has just finished moving
              Debug.Log(PlayerPosition.position.x);
          }
      
          if (Input.GetMouseButtonDown(0))
          {
              if (!isMoving)
              {
                  rb.AddForce(20000 * Time.deltaTime, 0, 0);
              }
          }
      
          wasMovingLastTime = isMoving;
      }
      

      【讨论】:

      • 感谢为我解决了一个问题,但是如果我想在动画完成后打印 x 值呢?
      • @yarinCohen 你必须使用一个标志。查看更新
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-02-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多