Files
VOIDRPG/Assets/90 - Scripts/Generic/Player/HighlightManager.cs
T
2026-07-09 21:33:33 +02:00

179 lines
6.6 KiB
C#

using System;
using System.Collections.Generic;
using QuickOutline;
using Sirenix.OdinInspector;
using UnityEngine;
using VOID.Generic.Dict;
using VOID.Generic.Objects.Abstract;
using VOID.Generic.Objects.Item;
using VOID.Generic.Objects.Unit;
using VOID.Generic.Player.Input;
using VOID.Generic.Player.Util;
using VOID.Generic.Triggers;
using VOID.UserInterface.Game.Party;
using VOID.Generic.Util;
using VOID.Generic.World;
namespace VOID.Generic.Player
{
/// <summary>
/// Manages Highlights and Outlines of <see cref="UnitObject"/>s and <see cref="ItemObject"/>s in 2 modes:<br/>
/// - When cursor is over specific object - highlight that object<br/>
/// - When button is pressed - highlight all objects in range<br/>
/// <br/>
/// <see cref="UnitObject"/> can be selected from SCENE or <see cref="UnitPortraitUI"/>
/// </summary>
[DefaultExecutionOrder(-1)]
public class HighlightManager : MonoBehaviour, IDynamicTrigger
{
public static HighlightManager current { get; private set; }
[Title("Shaders used")]
[SerializeField] public Shader[] shaders;
[Title("Colors")]
[SerializeField] private Color _enemyColor;
[SerializeField] private Color _cautiousColor;
[SerializeField] private Color _neutralColor;
[SerializeField] private Color _friendlyColor;
[SerializeField] private Color _companionColor;
[SerializeField] private Color _selfColor;
[SerializeField] private Color _itemColor;
[Title("Outline")]
[SerializeField] private float _outlineWidth;
[SerializeField] private Outline.Mode _outlineMode;
[Title("Group Outline")]
[SerializeField] private float _range = Area.Size;
// Runtime
private GameObject _highlightGameObject;
private SphereCollider _collider;
private Transform _stickTo;
private readonly List<UnitObject> _unitsInRange = new();
// private readonly List<AbstractObject> _objectsInRange = new();
private AbstractObject _objectUnderCursor;
private void Awake()
{
current = this;
_highlightGameObject = new GameObject("Highlight Range");
_highlightGameObject.transform.parent = gameObject.transform;
_highlightGameObject.layer = LayerManager.TriggerIndex;
_collider = _highlightGameObject.AddComponent<SphereCollider>();
_collider.radius = _range;
_collider.isTrigger = true;
}
private void Start()
{
PlayerController.current.OnActiveUnitChange += OnActiveUnitChange;
PlayerInputManager.current.OnHighlightStart += ShowHighlightForAllInRange;
PlayerInputManager.current.OnHighlightEnd += HideHighlightForAllInRange;
}
private void FixedUpdate()
{
StickTo();
HighlightUnderCursor();
}
private void StickTo()
{
if (_stickTo) _highlightGameObject.transform.position = _stickTo.position;
}
private void HighlightUnderCursor()
{
// Find whats under cursor, we allow only ItemObject (from scene) and UnitObject (from scene and portraits)
var select = SelectUtil.Select();
// There is nothing under cursor, but something was previous frame!
if (!select.selectObject && _objectUnderCursor)
{
HideHighlight(_objectUnderCursor);
_objectUnderCursor = null;
}
// Nothing to highlight
if (!select.selectObject) return;
// This one was already under cursor and is highlighted previously
if (select.selectObject == _objectUnderCursor) return;
// There is something new under cursor - hide previous object highlight and continue
if (_objectUnderCursor) HideHighlight(_objectUnderCursor);
_objectUnderCursor = select.selectObject;
ShowHighlight(_objectUnderCursor);
}
private void OnActiveUnitChange(UnitObject unitObject)
{
_stickTo = unitObject.transform;
}
public void OnObjectEnter(AbstractObject obj)
{
if (obj is not UnitObject unit) return;
_unitsInRange.Add(unit);
if (PlayerInputManager.current.isHighlight) ShowHighlight(unit);
}
public void OnObjectExit(AbstractObject obj)
{
if (obj is not UnitObject unit) return;
_unitsInRange.Remove(unit);
if (PlayerInputManager.current.isHighlight) HideHighlight(unit);
}
private void ShowHighlight(AbstractObject obj)
{
// Highlighting only when object allow that on itself
if (!obj.basicData.canBeSelected) return;
var outline = obj.gameObject.GetComponent<Outline>();
if (!outline) outline = obj.gameObject.AddComponent<Outline>();
if (obj is UnitObject unit) outline.OutlineColor = GetColorForUnit(unit);
else outline.OutlineColor = _itemColor;
outline.OutlineMode = _outlineMode;
outline.OutlineWidth = _outlineWidth;
outline.enabled = true;
}
private void HideHighlight(AbstractObject obj)
{
if (PlayerInputManager.current.isHighlight && obj is UnitObject unit && _unitsInRange.Contains(unit)) return;
if (obj.TryGetComponent<Outline>(out var outline)) outline.enabled = false;
}
private void ShowHighlightForAllInRange()
{
_unitsInRange.ForEach(ShowHighlight);
}
private void HideHighlightForAllInRange()
{
_unitsInRange.ForEach(HideHighlight);
}
private Color GetColorForUnit(UnitObject unit)
{
if (!PlayerController.current.activeUnit) return _neutralColor;
if (unit == PlayerController.current.activeUnit) return _selfColor;
var attitudeType = PlayerController.current.activeUnit.unitAttitude.GetAttitudeWith(unit);
return attitudeType switch
{
AttitudeType.Hostile => _enemyColor,
AttitudeType.Cautious => _cautiousColor,
AttitudeType.Neutral => _neutralColor,
AttitudeType.Friendly => _friendlyColor,
AttitudeType.Companion => _companionColor,
_ => throw new ArgumentOutOfRangeException(nameof(attitudeType), attitudeType, null)
};
}
}
}