UI To show Pickup Issue

I’ve Implemented a UI to pickup Items instead of clicking the mouse button. But When I have like 3 pickups in an area and I picked up everything, the UI doesn’t hide again. What am I missing?

So with the ItemCollector on the user like this.

public class ItemCollector : MonoBehaviour, IAction
    {
        Pickup target;

        void Update()
        {
            if (target == null) return;
            if (!GetIsInRange(target.transform)) 
            {
                GetComponent<Mover>().MoveTo(target.transform.position, 1);
            }
            else
            {
                target.PickupItem();
                target = null;
            }
        }

        public void CollectItem(Pickup pickup)
        {
            GetComponent<ActionScheduler>().StartAction(this);
            target = pickup;
        }

        private bool GetIsInRange(Transform targetTransform)
        {
            return Vector3.Distance(transform.position, targetTransform.position) < 3;
        }

        public void Cancel()
        {
            target = null;
            GetComponent<Mover>().Cancel();
        }
    }

Then the ClickablePickup script

public class ClickablePickup : Pickup, IRaycastable
    {
        Pickup pickup;
        bool isInRange = false;
        PickupUI pickupUI;

        private void Awake()
        {
            pickup = GetComponent<Pickup>();
            pickupUI = FindObjectOfType<PickupUI>();
        }

        public CursorType GetCursorType()
        {
            return CursorType.Pickup;
        }

        public bool HandleRayCast(PlayerController callingController)
        {
            if (Input.GetKeyDown(KeyCode.E))
            {
                callingController.GetComponent<ItemCollector>().CollectItem(pickup);
            }
            return true;
        }
        private void OnTriggerEnter(Collider other)
        {
            if (other.CompareTag("Player"))
            {
                pickupUI.ShowUI();
            }
        }
        private void OnTriggerExit(Collider other)
        {
            if (other.CompareTag("Player"))
            {
                pickupUI.HideUI();
            }
        }
    }

Then I have a simple UI to show or hide a UI telling the user to click “[E] Pickup” like so:

public class PickupUI : MonoBehaviour
    {
        [SerializeField] private GameObject panel = null;
        [SerializeField] private TextMeshProUGUI text = null;

        private void Start()
        {
            HideUI();
        }

        public void ShowUI()
        {
            panel.SetActive(true);
            text.text = "[E] Pickup ";
        }

        public void HideUI()
        {
            panel.SetActive(false);
        }
    }

When you pick up the item, OnTriggerExit won’t fire, because the pickup will be destroyed.

void OnDestroy()
{
    pickupUI.HideUI();
}

should do the trick.

That being said, with multiple pickups, you’re going to run into an issue with concurrence. Suppose you have 3 pickups in range, all of which have triggered ShowUI()… when the first one is picked up, OnDestroy() is going to close the window.

This is a case where a static Observer pattern may be helpful:

ClickablePickup.cs:

public static event Action<Pickup> OnEnteredPickupRange;
public static event Action<Pickup> OnLeftPickupRange;

private void OnTriggerEnter(Collider other)
{
    if(other.CompareTag("Player"))
    {
         OnEnteredPickupRange?.Invoke(this);
     }
}
private void OnTriggerExit(Collider other)
{
    if(other.CompareTag("Player"))
    {
         OnLeftPickupRange?.Invoke(this);
     }
}

void OnDestroy()
{
     OnLeftPickupRange?.Invoke(this);
}

And in your PickupUI

public class PickupUI: MonoBehaviour
{
    [Serializefield] private GameObject panel = null;
    [Serializefield] private TextMeshProUGUI text = null;

     List<Pickup> pickups = new List<Pickup>();    

    private void Awake()
    {
           Pickup.OnEnteredPickupRange += OnEnteredPickupRangeHandler;
           Pickup.OnLeftPickupRange += OnLeftPickupRangeHandler;
     }
     private void Start()
     {
          HideUI();
     }
  
     private void OnDestroy()
     {
          Pickup.OnEnteredPickupRange-=OnEnteredPickupRangeHandler;
          Pickup.OnLeftPickupRange -= OnLeftPickupRangeHandler;
      }
      private void OnEnteredPickupRangeHandler(Pickup pickup)
      {
           if(!pickups.Contains(pickup)) pickups.Add(pickup);
           ShowUI();
      }
      private void OnLeftPickupRangeHandler(Pickup pickup)
      {
           pickups.Remove(pickup);
           if(pickups.Count==0) HideUI();
       }
       //your original ShowUI() and HideUI() methods follow
}

By using static events, and a List of Pickups to track what is currently “in range”, the UI will know when no more pickups are in range (either left range or destroyed) then the UI should hide.

Thank you Brian. Worked like a charm :slight_smile:

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms