eye-therapy-2 / Assets / Scripts / Eye Simulation / EyePOIManager.cs
EyePOIManager.cs
Raw
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

[RequireComponent(typeof(EyeSimulation))]
public class EyePOIManager : MonoBehaviour, IListener
{
    private EyeSimulation eyeSim;
    private List<EyePOI> POIs;
    private EyePOI currentPOI = null;
    private Camera headCam;
    private float poiCheckTime = 2f;
    private float t = 0f;

    private void Awake()
    {
        eyeSim = GetComponent<EyeSimulation>();
        POIs = FindObjectsOfType<EyePOI>().ToList();
        headCam = Camera.main;
    }

    private void Start()
    {
        TestCurrentPOI();

        EventManager.Instance.AddListener(EVENT_TYPE.ON_EYE_POI_APPEARED, this);
        EventManager.Instance.AddListener(EVENT_TYPE.ON_EYE_POI_DISAPPEARED, this);
    }

    private void Update()
    {
        TestCurrentPOI();
    }

    public void OnEvent<T>(EVENT_TYPE eventType, Component Sender, T param = default)
    {
        switch(eventType)
        {
            case EVENT_TYPE.ON_EYE_POI_APPEARED:
                break;
            case EVENT_TYPE.ON_EYE_POI_DISAPPEARED:
                break;
        }
    }

    /// <summary>
    /// Searches for active POI in camera frustrum and chooses the one with highest weight and closest to eyes.
    /// </summary>
    private void GetNewPOI()
    {
        Plane[] camPlanes = GeometryUtility.CalculateFrustumPlanes(headCam);
        List<EyePOI> activePOIsInCamera = new List<EyePOI>();
        foreach(EyePOI poi in POIs)
        {
            if (poi.IsActive && GeometryUtility.TestPlanesAABB(camPlanes, poi.GetComponent<Collider>().bounds))
            {
                activePOIsInCamera.Add(poi);
            }
        }
        if (activePOIsInCamera.Count == 0)
        {
            currentPOI = null;
            return;
        }
        
        int maxWeightId = activePOIsInCamera.Count - 1;
        float maxWeight = activePOIsInCamera[maxWeightId].Weight;
        for (int i = activePOIsInCamera.Count - 2; i >= 0; i--)
        {
            if (activePOIsInCamera[i].Weight < maxWeight)
            {
                activePOIsInCamera.RemoveAt(i);
                maxWeightId--;
            }
            else if (activePOIsInCamera[i].Weight > maxWeight)
            {
                activePOIsInCamera.RemoveAt(maxWeightId);
                maxWeightId = i;
                maxWeight = activePOIsInCamera[i].Weight;
            }
        }
        if (activePOIsInCamera.Count == 1)
        {
            currentPOI = activePOIsInCamera[0];
            return;
        }

        EyePOI closest = activePOIsInCamera[0];
        float minDistance = Vector3.Distance(transform.position, closest.transform.position);
        for (int i = 1; i < activePOIsInCamera.Count; i++)
        {
            float distance = Vector3.Distance(transform.position, activePOIsInCamera[i].transform.position);
            if (distance < minDistance)
            {
                closest = activePOIsInCamera[i];
                minDistance = distance;
            }
        }
        currentPOI = closest;
    }

    private void TestCurrentPOI()
    {
        t += Time.deltaTime;
        Plane[] camPlanes = GeometryUtility.CalculateFrustumPlanes(headCam);
        if (t >= poiCheckTime || (currentPOI != null && !(currentPOI.IsActive && GeometryUtility.TestPlanesAABB(camPlanes, currentPOI.GetComponent<Collider>().bounds))))
        {
            t = 0f;
            GetNewPOI();
            if (currentPOI != null) eyeSim.target = currentPOI.transform;
            else eyeSim.target = null;
        }
    }
}