Нужна помощь в выходе из IEnumerator, когда игрок движется - PullRequest
0 голосов
/ 08 ноября 2018

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

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

using System.Collections;
using UnityEngine;

public class Mining : MonoBehaviour, IInteractable
{
    private Coroutine gatherRoutine;
    private Vector3 playerPosition;

    [SerializeField]
    private float timeToGather;

    [SerializeField]
    private LootTable lootTable;

    [SerializeField]
    [Tooltip("Leave blank if there is no achievement attached to this object")]
    private string achievementName;

    [Header("Interaction Cursor")]
    [SerializeField]
    private float interactDistance;

    [SerializeField]
    private Texture2D cursorTexture;

    [SerializeField]
    private CursorMode cursorMode = CursorMode.Auto;

    [SerializeField]
    private Vector2 hotSpot = Vector2.zero;

    private void OnMouseEnter()
    {
        if ((Vector3.Distance(Player.MyInstance.MyTransform.position, transform.position) < interactDistance) && !Player.MyInstance.MyIsGathering)
        {
            Cursor.SetCursor(cursorTexture, hotSpot, cursorMode);
            Player.MyInstance.MyInteractable = GetComponent<IInteractable>();
        }
        else
        {
            Cursor.SetCursor(null, Vector2.zero, cursorMode);
        }
    }

    private void OnMouseExit()
    {
        Cursor.SetCursor(null, Vector2.zero, cursorMode);
    }

    public void Interact()
    {
        if (Vector3.Distance(Player.MyInstance.MyTransform.position, transform.position) < interactDistance && Player.MyInstance.MyHasPickaxe == true)
        {
            playerPosition = Player.MyInstance.MyTransform.position;
            gatherRoutine = StartCoroutine(Gather(timeToGather));
        }
        else
        {
            GameManager.MyInstance.SendMessageToChat("You need to equip a 'Pickaxe' to mine this resource.", Message.MessageType.warning);
        }
    }

    public void StopInteract()
    {
        Player.MyInstance.MyIsGathering = false;
        Player.MyInstance.animator.SetBool("Mining", Player.MyInstance.MyIsGathering);

        if (gatherRoutine != null)
        {
            StopCoroutine(gatherRoutine);
        }
    }

    private IEnumerator Gather(float time)
    {
        Player.MyInstance.MyIsGathering = true;
        Player.MyInstance.animator.SetBool("Mining", Player.MyInstance.MyIsGathering);

        yield return new WaitForSeconds(time);

        Player.MyInstance.MyIsGathering = false;
        Player.MyInstance.animator.SetBool("Mining", Player.MyInstance.MyIsGathering);

        lootTable.ShowLoot();

        if (achievementName != null)
        {
            AchievementManager.MyInstance.EarnAchievement(achievementName);
        }

        Destroy(gameObject);
        Cursor.SetCursor(null, Vector2.zero, cursorMode);
    }
}

1 Ответ

0 голосов
/ 08 ноября 2018

Вы должны остановить Coroutine с точно таким же параметром, как и при его запуске.

С StopCoroutine :

StopCoroutine принимает один из трех аргументов, которые указывают, какая сопрограмма остановлена:

  • Строковая функция с именем активной сопрограммы
  • Переменная IEnumerator, использованная ранее для создания сопрограммы.
  • Coroutine, чтобы остановить созданную вручную Coroutine.

Примечание : не смешивайте три аргумента. Если в качестве аргумента в StartCoroutine используется строка, используйте строку в StopCoroutine. Аналогично, используйте IEnumerator как в StartCoroutine, так и в StopCoroutine. Наконец, используйте StopCoroutine с Coroutine, использованным для создания.

Таким образом, вы должны назначить gatherRoutine заранее

gatherRoutine = Gather(timeToGather);
StartCoroutine(gatherRoutine);

и позже

StopCoroutine(gatherRoutine);

В качестве альтернативы вы можете использовать StopAllCoroutines(), чтобы остановить сопрограмму без необходимости обрабатывать параметр (следует использовать, только если в этом классе есть только одна сопрограмма).

public void StopInteract()
{
    Player.MyInstance.MyIsGathering = false;
    Player.MyInstance.animator.SetBool("Mining", Player.MyInstance.MyIsGathering);

    if (gatherRoutine != null)
    {
        StopAllCoroutines();
    }
}

Или вы можете использовать bool и сделать

private interuptRoutine = false;

public void Interact()
{
    if (Vector3.Distance(Player.MyInstance.MyTransform.position, transform.position) < interactDistance && Player.MyInstance.MyHasPickaxe == true)
    {
        playerPosition = Player.MyInstance.MyTransform.position;
        // before starting the routine set the interupt flag to false
        interuptRoutine = false;
        StartCoroutine(Gather(timeToGather));
    }
    else
    {
        GameManager.MyInstance.SendMessageToChat("You need to equip a 'Pickaxe' to mine this resource.", Message.MessageType.warning);
    }
}

public void StopInteract()
{
    Player.MyInstance.MyIsGathering = false;
    Player.MyInstance.animator.SetBool("Mining", Player.MyInstance.MyIsGathering);

    if (gatherRoutine != null)
    {
        // only set the interupt flag
        interuptRoutine = true;
    }
}

private IEnumerator Gather(float time)
{
    Player.MyInstance.MyIsGathering = true;
    Player.MyInstance.animator.SetBool("Mining", Player.MyInstance.MyIsGathering);

    // does the same as WaitForSeconds but manually and interupts the routine
    // if interuptRoutine was set to true
    var timePast = 0;
    while(timePast <= time)
    {
        if(interuptRoutine) yield brake;
        timePast += Time.deltaTime;
    }


    Player.MyInstance.MyIsGathering = false;
    Player.MyInstance.animator.SetBool("Mining", Player.MyInstance.MyIsGathering);

    lootTable.ShowLoot();

    if (achievementName != null)
    {
        AchievementManager.MyInstance.EarnAchievement(achievementName);
    }

    Destroy(gameObject);
    Cursor.SetCursor(null, Vector2.zero, cursorMode);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...