using PixelPlay.OffScreenIndicator;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
///
/// Attach the script to the off screen indicator panel.
///
[DefaultExecutionOrder(-1)]
public class OffScreenIndicator : MonoBehaviour
{
[Range(0.5f, 0.9f)]
[Tooltip("Distance offset of the indicators from the centre of the screen")]
[SerializeField] private float screenBoundOffset = 0.9f;
private Camera mainCamera;
private Vector3 screenCentre;
private Vector3 screenBounds;
private List targets = new List();
public static Action TargetStateChanged;
void Awake()
{
mainCamera = Camera.main;
screenCentre = new Vector3(Screen.width, Screen.height, 0) / 2;
screenBounds = screenCentre * screenBoundOffset;
TargetStateChanged += HandleTargetStateChanged;
}
void LateUpdate()
{
DrawIndicators();
}
///
/// Draw the indicators on the screen and set thier position and rotation and other properties.
///
void DrawIndicators()
{
foreach(Target target in targets)
{
Vector3 screenPosition = OffScreenIndicatorCore.GetScreenPosition(mainCamera, target.transform.position);
bool isTargetVisible = OffScreenIndicatorCore.IsTargetVisible(screenPosition);
float distanceFromCamera = target.NeedDistanceText ? target.GetDistanceFromCamera(mainCamera.transform.position) : float.MinValue;// Gets the target distance from the camera.
Indicator indicator = null;
if(target.NeedBoxIndicator && isTargetVisible)
{
screenPosition.z = 0;
indicator = GetIndicator(ref target.indicator, IndicatorType.BOX); // Gets the box indicator from the pool.
}
else if(target.NeedArrowIndicator && !isTargetVisible)
{
float angle = float.MinValue;
OffScreenIndicatorCore.GetArrowIndicatorPositionAndAngle(ref screenPosition, ref angle, screenCentre, screenBounds);
indicator = GetIndicator(ref target.indicator, IndicatorType.ARROW); // Gets the arrow indicator from the pool.
indicator.transform.rotation = Quaternion.Euler(0, 0, angle * Mathf.Rad2Deg); // Sets the rotation for the arrow indicator.
}
if(indicator)
{
indicator.SetImageColor(target.TargetColor);// Sets the image color of the indicator.
indicator.SetDistanceText(distanceFromCamera); //Set the distance text for the indicator.
indicator.transform.position = screenPosition; //Sets the position of the indicator on the screen.
indicator.SetTextRotation(Quaternion.identity); // Sets the rotation of the distance text of the indicator.
}
}
}
///
/// 1. Add the target to targets list if is true.
/// 2. If is false deactivate the targets indicator,
/// set its reference null and remove it from the targets list.
///
///
///
private void HandleTargetStateChanged(Target target, bool active)
{
if(active)
{
targets.Add(target);
}
else
{
target.indicator?.Activate(false);
target.indicator = null;
targets.Remove(target);
}
}
///
/// Get the indicator for the target.
/// 1. If its not null and of the same required
/// then return the same indicator;
/// 2. If its not null but is of different type from
/// then deactivate the old reference so that it returns to the pool
/// and request one of another type from pool.
/// 3. If its null then request one from the pool of .
///
///
///
///
private Indicator GetIndicator(ref Indicator indicator, IndicatorType type)
{
if(indicator != null)
{
if(indicator.Type != type)
{
indicator.Activate(false);
indicator = type == IndicatorType.BOX ? BoxObjectPool.current.GetPooledObject() : ArrowObjectPool.current.GetPooledObject();
indicator.Activate(true); // Sets the indicator as active.
}
}
else
{
indicator = type == IndicatorType.BOX ? BoxObjectPool.current.GetPooledObject() : ArrowObjectPool.current.GetPooledObject();
indicator.Activate(true); // Sets the indicator as active.
}
return indicator;
}
private void OnDestroy()
{
TargetStateChanged -= HandleTargetStateChanged;
}
}