Невозможно плавно переместить gemeObject с помощью MoveTowards или Lerp - PullRequest
0 голосов
/ 06 ноября 2019

Я экстремальный любитель с очень простой целью. Внутри 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");
    }

(Скорость = 5f) Это то, что я почувствовал, как будто получил меняближе всего к моей цели. В настоящее время он перемещает расстояние, но только в одном кадре. Я также пытался использовать IEnumerator, который в основном имеет тот же код внутри, и просто вызывал IEnumarator изнутри OnGui, но безрезультатно.

1 Ответ

1 голос
/ 07 ноября 2019

Основная проблема заключается в следующем цикле

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

Это перемещает ваш объект за один шаг, потому что пока что кадр не отображается. while скорее блокирует весь поток до тех пор, пока это не будет сделано (что в данном случае не так долго), а затем визуализирует кадр, когда это будет сделано.

Кроме того, как также упоминается в комментариях, OnGUI называется множественнымраз за кадр, так что становится еще хуже.


Как я уже говорил, OnGUI является своего рода наследием, и вы не должны больше его использовать, если не знаете точно, как и что вы делаете.

Скорее используйте UI.Button в Canvas.


Если я вижу это правильно, вы хотите двигаться, пока кнопка остается нажатой.

К сожалению, нет встроенной кнопки для управления чем-то вроде «пока кнопка остается нажатой», поэтому вам придется использовать интерфейсы IPointerDownHandler и IPointerUpHandler.

Putэтот класс для 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);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...