【问题标题】:Can't move a gemeObject smoothly with MoveTowards or Lerp无法使用 MoveTowards 或 Lerp 平滑移动 gemeObject
【发布时间】:2019-11-08 01:07:50
【问题描述】:

我是一个极端的业余爱好者,目标非常简单。在 OnGui 里面我有一个按钮。我希望按下此按钮以移动它所连接的游戏对象,以便以平滑的动作向右移动一段距离。我已经成功地设置了我想要移动的距离,但我无法使移动顺利以挽救我的生命。

    private void OnGUI()
{
    if (GUI.Button(new Rect(165, 300, 150, 350), "right"))
    {            
        var pos = transform.position;
        float rightMovement = pos.x + 0.5f;

      Vector3 targetPosition = new Vector3(rightMovement, transform.position.y, transform.position.z);

        while (Vector3.Distance(transform.position, targetPosition) > 0.1f)
        {
            float step = speed * Time.deltaTime;
            transform.position = Vector3.MoveTowards(transform.position, targetPosition, step);
        }
        Debug.Log("Clicked rightMovement");
    }

(Speed = 5f) 这是我最接近目标的感觉。目前它会移动距离,但只是在一帧中。我还尝试使用内部基本上具有相同代码的 IEnumerator,并从 OnGui 内部调用所述 IEnumerator,但无济于事。

【问题讨论】:

  • 如您所见,整个循环将在一帧内完成。 IEnumerator 方法是在正确的轨道上。你能从那次尝试中发布你的代码吗?
  • OnGUI 每帧调用多次。 Time.deltaTime 是帧之间的时间。这可能是导致它不平滑的原因。
  • 不要使用OnGUI,它是遗留的......而使用UI.Button

标签: c# unity3d vector


【解决方案1】:

主要问题是这个循环

while (Vector3.Distance(transform.position, targetPosition) > 0.1f)
{
    float step = speed * Time.deltaTime;
    transform.position = Vector3.MoveTowards(transform.position, targetPosition, step);
}

这一步会移动您的对象,因为同时不会渲染任何帧。 while 会阻塞整个线程,直到它完成(在这种情况下我并没有那么长),然后在完成后渲染帧。

此外,正如 cmets 中提到的那样,OnGUI 每帧被调用多次,因此情况变得更糟。


正如我还评论的那样,OnGUI 是一种遗留物,除非您确切地知道自己在做什么以及在做什么,否则您不应该再使用它。

宁可使用UI.Button in a Canvas


如果我没看错,你想在按钮保持按下状态时移动。

不幸的是,没有内置按钮来处理“当按钮保持按下状态”之类的事情,因此您必须使用IPointerDownHandlerIPointerUpHandler 接口。

把这个类放在UI.Button对象上

public class MoveButton : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerDownHandler, IPointerUpHandler
{
    public enum Alignment
    {
        Global,
        Local
    }

    // Configure here the movement step per second in all three axis
    public Vector3 moveStep;

    // Here reference the object that shall be move by this button
    public Transform targetObject;

    // Configure here wether you want the movement in
    // - Global = World-Space
    // - Local = Object's Local-Space
    public Alignment align;

    private Button button;

    private void Awake ()
    {
        button = GetComponent<Button>();
    }

    //Detect current clicks on the GameObject (the one with the script attached)
    public void OnPointerDown(PointerEventData pointerEventData)
    {
        // Ignore if button is disabled
        if(!button.interactible) return;

        StartCoroutine (Move());
    }

    public void OnPointerUp(PointerEventData pointerEventData)
    {
        StopAllCoroutines();
    }

    public void OnPointerExit(PointerEventData pointerEventData)
    {
        StopAllCoroutines();
    }

    // Actually not really needed but I'm not sure right now
    // if it is required for OnPointerExit to work
    // E.g. PointerDown doesn't work if PointerUp is not present as well
    public void OnPointerEnter(PointerEventData pointerEventData)
    {

    }

    // And finally to the movement
    private IEnumerator Move()
    {
        // Whut? Looks dangerous but is ok as long as you yield somewhere
        while(true)
        {
            // Depending on the alignment move one step in the given direction and speed/second
            if(align == Alignment.Global)
            {
                targetObject.position += moveStep * Time.deltaTime;
            }
            else
            {
                targetObject.localPosition += moveStep * Time.deltaTime;
            }

            // Very important! This tells the routine to "pause"
            // render this frame and continue from here
            // in the next frame.
            // without this Unity freezes so careful ;)
            yield return null;
        }
    }
}

或者,您可以坚持使用您的代码,但将按钮与移动分开,例如

private bool isPressed;

private void OnGUI()
{
    isPressed = GUI.Button(new Rect(165, 300, 150, 350), "right");
}

private void Update()
{  
    if(!isPressed) return;

    var pos = transform.position;
    var targetPosition = pos + Vector3.right * 0.5f;

    if (Vector3.Distance(transform.position, targetPosition) > 0.1f)
    {
        float step = speed * Time.deltaTime;
        transform.position = Vector3.MoveTowards(transform.position, targetPosition, step);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多