播放器移动时需要帮助退出IEnumerator

时间:2018-11-07 21:24:02

标签: c# unity3d

我环顾四周,并尝试了不同的方法来实现这一目标,但是我没有得到正确的结果。我知道我要的很多,但是我碰到了这堵砖墙,如果可以的话,我将不胜感激。

当玩家挖掘资源时,如果他们从起始位置移动,我希望它停止挖掘。我已经发布了完整的课程,以便您可以看到我在做什么,并希望有人可以指出正确的方向。

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 :(得分:0)

您必须使用与启动协程完全相同的参数来停止协程。

来自StopCoroutine

  

StopCoroutine采用以下三个参数之一,该参数指定停止哪个协程:

     
      
  • 命名活动协程的字符串函数
  •   
  • 之前用于创建协程的IEnumerator变量。
  •   
  • 协程以停止手动创建的协程。
  •   
     

注意:请勿混合使用三个参数。如果在StartCoroutine中将字符串用作参数,请在StopCoroutine中使用该字符串。同样,在StartCoroutine和StopCoroutine中都使用IEnumerator。最后,将StopCoroutine与用于创建的协同程序一起使用。

因此,您应该预先分配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);
}