Completely Broken Event Triggering

First off, I have checked with other programmers and they can see absolutely nothing wrong with this code, so either none of us can see it, or Unity isn’t interpreting the code properly, and at this point (several days into troubleshooting) I’m honestly not sure which is more likely.

The first script, InfoGraphIcon, is attached to a radial filled circle in the Canvas, and has a child text object.
The second, InfoGraphObject, is attached to a door model with a box collider on it; the radius is set to 3, and some sample text is in the text field.

The intent of this script set is that, when the player looks at the door AND is inside the radius, the radial circle fills, and once that has happened, the text for that object appears.
Once looking away, the circle and the text should disappear.

THIS DOES NOT HAPPEN.

After many many hours of messing around, rewriting and wondering if it worth the effort, I’m not much closer to working out what is wrong.

What actually happens with this is:
When I am in the radius AND looking at the object, nothing happens, but when I am in the radius AND NOT looking at the object, this works, sort of, the text sometimes appears early (before the lerp is complete).

Any ideas as to what could be wrong?

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

public class InfoGraphIcon : MonoBehaviour
{

    public Image icon;
    public Text text;

    void Start()
    {
        icon = GetComponent<Image>();
        text = GetComponentInChildren<Text>();
        UnloadIcon();
    }

    public void LoadIcon(float length, string info)
    {
        StartCoroutine(ControlIcon(0, 1, length, info));
    }

    public void UnloadIcon()
    {
        icon.fillAmount = 0;
        text.text = "";
    }

    IEnumerator ControlIcon(int start, int end, float length, string info)
    {
        float startTime = Time.time;
        float endTime = startTime + length;
        do
        {
            float timeProgressedPosition = (Time.time - startTime) / length;
            timeProgressedPosition = Mathf.Sin(timeProgressedPosition * Mathf.PI * 0.5f);
            timeProgressedPosition = timeProgressedPosition * timeProgressedPosition * timeProgressedPosition * (timeProgressedPosition * (6f * timeProgressedPosition - 15f) + 10f);
            icon.fillAmount = Mathf.Lerp(start, end, timeProgressedPosition);
            yield return new WaitForFixedUpdate();
        }
        while (Time.time < endTime);
        text.text = info;
    }
}
using UnityEngine;

public class InfoGraphObject : MonoBehaviour {

    public float radius = 1;
    private GameObject player;
    private float distance;
    public bool isInRange;

    [Multiline(10)]
    public string text;

    public InfoGraphIcon igi;

    private Renderer rend;

    void Start()
    {
        player = GameObject.FindGameObjectWithTag("Player");
        rend = GetComponent<Renderer>();
        igi = FindObjectOfType<InfoGraphIcon>();
    }

    void Update()
    {
        distance = Vector3.Distance(transform.position, player.transform.position);
        isInRange = distance <= radius;
    }

    void OnMouseOver()
    {
        OnMouseExit();

        if (isInRange)
        {
            igi.LoadIcon(1, text);
            //igi.text.text = text;
        }
    }

    void OnMouseExit()
    {
        igi.UnloadIcon();
        igi.icon.fillAmount = 0;
        igi.text.text = "";
    }

    private void DrawGizmo(bool selected)
    {
        var col = new Color(1.0f, 0.67f, 0.0f, 1.0f);
        col.a = selected ? 0.6f : 0.4f;
        Gizmos.color = col;
        Gizmos.matrix = transform.localToWorldMatrix;
        Gizmos.DrawCube(Vector3.zero, Vector3.one);
        col.a = selected ? 0.5f : 0.4f;
        Gizmos.color = col;
        Gizmos.DrawWireCube(Vector3.zero, Vector3.one);
    }

    public void OnDrawGizmos()
    {
        DrawGizmo(false);
    }
    public void OnDrawGizmosSelected()
    {
        DrawGizmo(true);
    }
}

A few observations:

  • OnMouseOver() is called every frame during which the mouse is over the object. Which means you’re also calling OnMouseExit() and UnloadIcon() every frame, competing with the coroutine for setting the fill amount.
  • Your lerp parameter appears to transition from -5 to +1 over the course of the loop. Which means for 5/6th of the duration, nothing will appear to be happening. Try it without the extra line of math to see if just the simple sine wave at least works.
  • Your yield waits for fixed update, but since what you’re doing appears to only affect rendering, you should only need to wait for a normal update, which can be achieved by yield returning a null value.
  • Neither OnMouseExit() nor UnloadIcon() kill any coroutine that is currently in progress, but it probably should. I’d recommend saving the return value of StartCoroutine() within LoadIcon() to a private class field, and then in UnloadIcon(), checking if that coroutine is null, and if not calling StopCoroutine() on it. Set it to null after stopping it of course, and also at the very end of ControlIcon().
  • Combining the concern of #1 with the solution of #4, LoadIcon() might first check to see if there’s already an in-progress coroutine, and if so, don’t start a new one. This means that the coroutine would only get kicked off on the first frame that OnMouseOver() gets called, not every subsequent frame. Though you might need to do something special to ensure that once the coroutine is complete and the coroutine field is set to null, not to start a new one simply because OnMouseOver() is still getting called. Lots of ways to do that; easiest might be to just not clear the field to null at the very end of ControlIcon().