Есть ли способ запустить метод с помощью нажатия кнопки, не используя функцию Update () в единстве - PullRequest
0 голосов
/ 08 января 2019

Ниже мой C # скрипт. Я добавил кнопку в свой проект с событием On Click и вызвал метод Rotate (). Но почему-то не работает

using System.Threading;
using UnityEngine;

public class Orbit : MonoBehaviour {

    public GameObject sun;
    public float speed;

    // Use this for initialization
    void Start () {

    }

    public void Update()
    {
        Rotate();
    }

    public void Rotate()
    {
        transform.RotateAround(sun.transform.position, Vector3.up, speed * 
        Time.deltaTime);
    }
}

Я прокомментировал метод Update () при вызове метода Rotate (). Я также создал игровой объект для сценария.

Ответы [ 2 ]

0 голосов
/ 08 января 2019

Поищите в статье информацию о функциональных возможностях нажатия клавиш. Это очень поможет вам в поиске вашего ответа. Обновление используется, если нам нужно что-то делать непрерывно в нашем проекте, когда используется нажатая клавиша, когда мы делаем это один раз

the Example for the Update issue

этот пример также используется для решения вашей проблемы и использования этого скрипта при нажатии определенной кнопки

0 голосов
/ 08 января 2019

Причина, по которой он работает только в Update, заключается в том, что

public void Rotate()
{
    transform.RotateAround(sun.transform.position, Vector3.up, speed * Time.deltaTime);
}

нужно вызывать многократно. В противном случае он будет вращаться только на один кадр, а Time.deltaTime приведет к очень небольшому количеству. Но событие onClick компонента Button вызывается только один раз. Это похоже, например, на Input.GetKeyDown, который вызывается только один раз при нажатии клавиши. В компоненте Button отсутствует реализация для продолжения нажатия кнопки.


Вместо этого, насколько я понимаю, вы хотите повернуть объект после нажатия кнопки

  • начать вращаться навсегда
  • на определенный срок
  • пока вы не нажмете кнопку снова
  • до тех пор, пока она не будет отпущена (-> нажмите кнопку непрерывного запуска, см. Ниже)

Один компонент Button может выполнять только первые три:

Поворот навсегда

Либо с использованием сопрограммы

private bool isRotating;

public void Rotate()
{
    // if aready rotating do nothing
    if(isRotating) return;

    // start the rotation
    StartCoroutine(RotateRoutine());

    isRotating = true;
}

private IEnumerator RotateRoutine()
{
    // whuut?!
    // Don't worry coroutines work a bit different
    // the yield return handles that .. never forget it though ;)
    while(true)
    {
         // rotate a bit
         transform.RotateAround(sun.transform.position, Vector3.up, speed * Time.deltaTime);

        // leave here, render the frame and continue in the next frame
        yield return null;
    }
}

или все еще делаете это в Update

private bool isRotating = false;

private void Update()
{
    // if not rotating do nothing
    if(!isRotating) return;

    // rotate a bit
    transform.RotateAround(sun.transform.position, Vector3.up, speed * Time.deltaTime);
}

public void Rotate()
{
    // enable the rotation
    isRotating = true;
}

Обратите внимание, что решение Update предназначено только для вашего понимания происходящего. Его не следует использовать таким образом, поскольку он не так эффективен, поскольку Update вызывается непрерывно и проверяет также bool, если он еще не вращается. Это приводит к ненужным накладным расходам. То же самое относится к всем следующим примерам: Предпочитайте использовать сопрограммы вместо Update ( В этом случае! В других случаях лучше и эффективнее использовать один Update метод вместо нескольких одновременных сопрограмм .. но это другая история.)

Поворот на определенную длительность

Как сопрограмма

// adjust in the inspector
// how long should rotation carry on (in seconds)?
public float duration = 1;

private bool isAlreadyRotating;

public void Rotate()
{
    // if aready rotating do nothing
    if(isAlreadyRotating) return;

    // start a rottaion
    StartCoroutine(RotateRoutine());
}

private IEnumerator RotateRoutine()
{
    // set the flag to prevent multiple callse
    isAlreadyRotating = true;

    float timePassed = 0.0f;
    while(timePassed < duration)
    {
         // rotate a small amount
         transform.RotateAround(sun.transform.position, Vector3.up, speed * Time.deltaTime);

         // add the time passed since last frame
         timePassed += Time.deltaTime;

         // leave here,  render the frame and continue in the next frame
         yield return null;
    }

    // reset the flag so another rotation might be started again
    isAlreadyRotating = false;
}

или Update

public float duration;

private bool isRotating;
private float timer;

private void Update()
{
    // if not rotating do nothing
    if(!isRotating) return;

    // reduce the timer by passed time since last frame
    timer -= Time.deltaTime;

    // rotate a small amount
    transform.RotateAround(sun.transform.position, Vector3.up, speed * Time.deltaTime);

    // if the timer is not 0 return
    if(timer > 0) return;

    // stop rottaing
    isRotating = false;
}

public void Rotate()
{
    // if already rotating do nothing
    if(isRotating) return;

    // start rotating
    isRotating = true;

    // enable timer
    timer = duration;
}

Переключение вращения

Это очень похоже на предыдущее, но на этот раз вместо таймера вы останавливаете вращение, нажимая снова. (Вы даже можете объединить их, но будьте осторожны, чтобы правильно сбросить флаг isRotating;))

Как сопрограмма

private bool isRotating;

public void ToggleRotation()
{
    // if rotating stop the routine otherwise start one
    if(isRotating)
    {
        StopCoroutine(RotateRoutine());
        isRotating = false;
    }
    else
    {
        StartCoroutine(RotateRoutine());
        isRotating = true;
    }
}

private IEnumerator RotateRoutine()
{
    // whuut?!
    // Don't worry coroutines work a bit different
    // the yield return handles that .. never forget it though ;)
    while(true)
    {
        // rotate a bit
        transform.RotateAround(sun.transform.position, Vector3.up, speed * Time.deltaTime);

        // leave here, render the frame and continue in the next frame
        yield return null;
    }
}

или как Update

private bool isRotating;

private void Update()
{
    // if not rotating do nothing
    if(!isRottaing) return;

    // rotate a bit
    transform.RotateAround(sun.transform.position, Vector3.up, speed * Time.deltaTime);
}

public void ToggleRotation()
{
    // toggle the flag
    isRotating = !isRotating;
}

Повернуть до отпускания

Это самая «сложная» часть, так как только Button не может этого сделать (нет «на выпуске»). Но вы можете реализовать это, используя IPointerXHandler интерфейсы.

Хорошая новость: вы можете сохранить свой оригинальный скрипт, как он есть у вас сейчас

public void Rotate()
{
    transform.RotateAround(sun.transform.position, Vector3.up, speed * 
    Time.deltaTime);
}

Теперь вам нужно расширение для кнопки. Он будет вызывать событие whilePressed несколько раз в каждом кадре, например Update, поэтому вам просто нужно ссылаться на ваш метод Rotate в whilePressed вместо onClick.

Опять же, есть два варианта, либо реализовать его как сопрограмму:

[RequireComponent(typeof(Button))]
public class HoldableButton : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerExitHandler
{
    // reference the same way as in onClick
    public UnityEvent whilePressed;       

    private Button button;
    private bool isPressed;

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

        if(!button)
        {
            Debug.LogError("Oh no no Button component on this object :O",this);
        }
    }

    // Handle pointer down
    public void OnPointerDown()
    {
        // skip if the button is not interactable
        if(!button.enabled || !button.interactable) return;

        // skip if already rotating
        if(isPressed) return;

        StartCoroutine(PressedRoutine());
        isPressed= true;

    }

    // Handle pointer up
    public void OnPointerUp()
    {
        isPressed= false;
    }

    // Handle pointer exit
    public void OnPointerExit()
    {
        isPressed= false;
    }

    private IEnumerator RotateRoutine()
    {
        // repeatedly call whilePressed until button isPressed turns false
        while(isPressed)
        {
            // break the routine if button was disabled meanwhile
            if(!button.enabled || !button.interactable)
            {
                isPressed = false;
                yield break;
            }

            // call whatever is referenced in whilePressed;
            whilePressed.Invoke();

            // leave here, render the frame and continue in the next frame
            yield return null;
        }
    }
}

или вы можете сделать то же самое в Update еще раз

[RequireComponent(typeof(Button))]
public class HoldableButton : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerExitHandler
{
    public UnityEvent whilePressed;

    private bool isPressed;
    private Button button;

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

        if(!button)
        {
            Debug.LogError("Oh no no Button component on this object :O",this);
        }
    }


    private void Update()
    {
        // if button is not interactable do nothing
        if(!button.enabled || !button.interactable) return;

        // if not rotating do nothing
        if(!isPressed) return;

        // call whatever is referenced in whilePressed;
        whilePressed.Invoke();
    }

    // Handle pointer down
    public void OnPointerDown()
    {
        // enable pressed
        isPressed= true;
    }

    // Handle pointer up
    public void OnPointerUp()
    {
        // disable pressed
        isPressed= false;
    }

    // Handle pointer exit
    public void OnPointerExit()
    {
        // disable pressed
        isPressed= false;
    }
}

Поместите этот компонент рядом с Button компонентом. Вам не нужно ссылаться на что-либо в onClick, просто оставьте это пустым. Вместо этого укажите что-то в onPressed. Оставьте компонент Button, поскольку он также обрабатывает стиль интерфейса для нас (например, при наведении курсора изменяет цвет / спрайт и т. Д.)


Опять же: решения Update могут пока выглядеть чище / проще, но они не так эффективны (в данном случае) и просты в управлении (это может быть основано на мнении), как решения Coroutine.

...