Я немного новичок, так что наберитесь терпения. Я работаю над созданием движения для модели игрока, где оно циклически переключается между набором спрайтов для движения вверх, вниз, влево и вправо, но если я двигаюсь в другом направлении до завершения текущего цикла, скрипт начинает накладывать спрайты. с обеих сторон друг на друга. Я ищу способ отменить текущий рендеринг спрайта при вводе нового направления. Какие-либо предложения?

public class PlayerMovement : MonoBehaviour
{
    public Sprite[] moveArray;
    public SpriteRenderer spriteRenderer;
    public PlayerController playerController;


    IEnumerator ChangeSprite()
    {
        if (playerController.horizontal >= .1f && playerController.horizontal > playerController.vertical)
        {
            spriteRenderer.sprite = moveArray[6];
            yield return new WaitForSeconds(0.3f);
            spriteRenderer.sprite = moveArray[7];
            yield return new WaitForSeconds(0.3f);
            spriteRenderer.sprite = moveArray[8];
            yield return new WaitForSeconds(0.3f);
            spriteRenderer.sprite = moveArray[7];
            yield return new WaitForSeconds(0.3f);
        }
        if (playerController.horizontal <= -.1f && playerController.horizontal < playerController.vertical)
        {
            spriteRenderer.sprite = moveArray[3];
            yield return new WaitForSeconds(0.3f);
            spriteRenderer.sprite = moveArray[4];
            yield return new WaitForSeconds(0.3f);
            spriteRenderer.sprite = moveArray[5];
            yield return new WaitForSeconds(0.3f);
            spriteRenderer.sprite = moveArray[4];
            yield return new WaitForSeconds(0.3f);
        }
        if (playerController.vertical <= -.1f && playerController.vertical < playerController.horizontal)
        {
            spriteRenderer.sprite = moveArray[0];
            yield return new WaitForSeconds(0.3f);
            spriteRenderer.sprite = moveArray[1];
            yield return new WaitForSeconds(0.3f);
            spriteRenderer.sprite = moveArray[2];
            yield return new WaitForSeconds(0.3f);
            spriteRenderer.sprite = moveArray[1];
            yield return new WaitForSeconds(0.3f);
        }
        if (playerController.vertical >= .1f && playerController.vertical > playerController.horizontal)
        {
            spriteRenderer.sprite = moveArray[9];
            yield return new WaitForSeconds(0.3f);
            spriteRenderer.sprite = moveArray[10];
            yield return new WaitForSeconds(0.3f);
            spriteRenderer.sprite = moveArray[11];
            yield return new WaitForSeconds(0.3f);
            spriteRenderer.sprite = moveArray[10];
            yield return new WaitForSeconds(0.3f);
        }
    }

    void Update()
    {
        if (playerController.vertical != 0f || playerController.horizontal != 0f)
        {
            StartCoroutine(ChangeSprite());
        }

        else if (playerController.vertical == 0f && playerController.horizontal == 0f)
        {
            StopCoroutine(ChangeSprite());
        }
    }
}```
-1
Donald Puggini 4 Май 2021 в 23:27

2 ответа

Лучший ответ

Вы используете StopCoroutine неправильно, вам нужно сохранить либо IEnumerable, возвращенный вызовом анимации, либо Coroutine, возвращенный StartCoroutine, и передать , что < / em> в StopCoroutine:

public class PlayerMovement : MonoBehaviour
{
    // ...

    private Coroutine _movementAnimation;

    // ...

    void Update()
    {
        if (playerController.vertical != 0f || playerController.horizontal != 0f)
        {
            // Store the Coroutine into a variable to be able to refer to it later
            _movementAnimation = StartCoroutine(ChangeSprite());
        }

        else if (playerController.vertical == 0f && playerController.horizontal == 0f && _movementAnimation != null)
        {
            // Stop the running coroutine, and clear it so we don't try to stop it many times.
            StopCoroutine(_movementAnimation);
            _movementAnimation = null;
        }
    }
}

Хотя документация Unity подразумевает, что сопрограммы в чем-то особенные, синтаксис IEnumerator и yield return - это особенности C #, а в C # вызов функции всегда будет выполнять свой код и никогда не будет повторно использовать предыдущие вызовы.

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


С учетом сказанного, я не думаю, что это хороший способ реализации анимации, у вас много магических чисел в вашем коде, а это означает, что вам придется изменить код, чтобы иметь возможность изменять количество или порядок кадров. .

Я бы порекомендовал изучить компонент unity Animator, или если вы хотите Собственный, рассмотрите более управляемый данными дизайн, который получает порядок кадров и задержки из какой-то структуры данных.

1
Kroltan 4 Май 2021 в 20:48

Я бы порекомендовал изучить компоненты «анимация» и «аниматор» в единстве.

Жесткое кодирование собственных аниматоров может быть очень утомительным, и вам следует избегать его любой ценой.

Посмотрите пару видеороликов о том, как анимация работает в единстве, и как только вы это сделаете. Вы можете отключить компонент анимации, чтобы остановить анимацию

0
Arcturus groviteer 4 Май 2021 в 21:53