如何检查物体是否在移动/静止?

3
我想编写一个简单的脚本,当您点击屏幕时,游戏中的球将向右移动(20000 * Time.deltaTime),然后如果再次点击,它将向左侧移动,然后向右侧移动,依此类推。
我已经成功让球向右移动,但我需要等待动画完成,因为我需要检查玩家是否再次点击(如果是,我需要检查要移动球的方向)。我尝试了许多在网上找到的方法,例如检查 Rigidbody.velocity.magnitude == 0.0f 是否等于0,这意味着球没有移动...
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);
        }
    }
}

最初的回答:我期望输出等待动画完成后再执行,但实际上,当我点击鼠标时,它立即打印出值(x)。
我希望输出在动画结束后才出现,但实际上,当我点击鼠标时,它就已经输出值(x)了。
3个回答

3

编辑

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

使用Animation.IsPlaying(string name)方法。 一个注意点是,此方法将在调用它的Update帧中返回false,因为动画直到之后才真正开始。

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”的操作数。 - yarin Cohen
所以为了检查它是否没有移动,你可以这样写:if (rb.velocity.magnitude != 0)? - yarin Cohen
"Magnitude" 本质上是一个绝对数。我只需检查它是否 > 0 而不是 != 0,因为 float 几乎永远不会为 0。它们最终会变成类似于 0.000001 的值。 - Eliasar
1
你可以通过以下方式检查矢量的大小是否小于一个小值,例如 0.05rb.velocity.magnitude < 0.05f - Milad Qasemi
虽然问题确实陈述了“如何检查物体是否在移动?”,但我们可以使用rb.velocity.magnitude > 0.05f - Eliasar
显示剩余4条评论

1

首先

rb.velocity.magnitude != 0.0f

由于单精度浮点数,几乎总是会true:即使两个浮点值看起来相等,它们在逻辑上最有可能不相等。

因此,您可以像之前尝试过的那样使用阈值。

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

或者使用Mathf.Approximately,它使用非常小的Epsilon或阈值进行比较。
if(Mathf.Approximately(rb.velocity.magintude, 0))

看起来你想要等待球停止移动,然后输出位置,比如台球游戏。因此,实际上似乎没有涉及到动画

在大多数情况下,当你考虑/谈论一个"动画"时,实际上是指"随着时间的推移做某事",不要与Unity中使用AnimatorAnimation组件和AnimationClip混淆。

你可以/应该使用协程来实现:

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;
}

0

我认为你想要在它停止时移动它,然后只有在它空闲时才调用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值怎么办? - yarin Cohen
@yarinCohen 你需要使用一个标志。查看更新。 - Orkhan Alikhanov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接