139 lines
4.6 KiB
C#
139 lines
4.6 KiB
C#
using Interaction;
|
|
using Interaction.Conditions;
|
|
using UnityEngine;
|
|
|
|
namespace Player
|
|
{
|
|
public class PlayerAimOutlineHighlighter : MonoBehaviour
|
|
{
|
|
[Header("Raycast")]
|
|
[SerializeField] private Transform cameraTransform;
|
|
[SerializeField] private float interactRange = 3f;
|
|
[SerializeField] private LayerMask interactLayer;
|
|
[SerializeField] private float refreshInterval = 0.05f;
|
|
|
|
[Header("Outline")]
|
|
[SerializeField] private Material outlineMaterial;
|
|
[SerializeField] private Color canInteractColor = new Color(0.1f, 1f, 0.25f, 1f);
|
|
[SerializeField] private Color lockedColor = new Color(1f, 0.55f, 0.1f, 1f);
|
|
[SerializeField] private Color blockedColor = new Color(1f, 0.55f, 0.1f, 1f);
|
|
|
|
[Header("Behavior")]
|
|
[SerializeField] private bool useLockedColorWhenLocked = true;
|
|
|
|
[Header("Debug")]
|
|
[SerializeField] private bool debugLog;
|
|
|
|
private float nextTime;
|
|
private InteractOutlineTarget currentTarget;
|
|
private Color currentColor;
|
|
|
|
private void Awake()
|
|
{
|
|
if (cameraTransform == null)
|
|
{
|
|
cameraTransform = GetComponentInChildren<Camera>()?.transform;
|
|
}
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (cameraTransform == null) return;
|
|
if (outlineMaterial == null) return;
|
|
if (refreshInterval > 0f && Time.time < nextTime) return;
|
|
|
|
nextTime = refreshInterval > 0f ? Time.time + refreshInterval : Time.time;
|
|
|
|
Ray ray = new Ray(cameraTransform.position, cameraTransform.forward);
|
|
if (!Physics.Raycast(ray, out RaycastHit hit, interactRange, interactLayer))
|
|
{
|
|
Clear();
|
|
return;
|
|
}
|
|
|
|
var hitCollider = hit.collider;
|
|
if (hitCollider == null)
|
|
{
|
|
Clear();
|
|
return;
|
|
}
|
|
|
|
var interactable = hitCollider.GetComponentInParent<IInteractable>();
|
|
if (interactable == null)
|
|
{
|
|
Clear();
|
|
return;
|
|
}
|
|
|
|
var conditions = hitCollider.GetComponentsInParent<InteractConditionBehaviour>();
|
|
bool allowed = true;
|
|
string failReason = null;
|
|
for (int i = 0; i < conditions.Length; i++)
|
|
{
|
|
var condition = conditions[i];
|
|
if (condition == null) continue;
|
|
if (!condition.CanInteract(gameObject, out failReason))
|
|
{
|
|
allowed = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool locked = false;
|
|
if (!allowed && useLockedColorWhenLocked)
|
|
{
|
|
var unlockGate = hitCollider.GetComponentInParent<RequireUnlockedInteractCondition>();
|
|
var unlockState = hitCollider.GetComponentInParent<InteractUnlockState>();
|
|
if (unlockState != null && !unlockState.IsUnlocked && (unlockGate != null || unlockState.BlocksInteractionWhenLocked))
|
|
{
|
|
locked = true;
|
|
}
|
|
}
|
|
|
|
Color color = allowed ? canInteractColor : (locked ? lockedColor : blockedColor);
|
|
|
|
var target = hitCollider.GetComponentInParent<InteractOutlineTarget>();
|
|
if (target == null)
|
|
{
|
|
target = interactable is MonoBehaviour mb ? mb.GetComponentInParent<InteractOutlineTarget>() : null;
|
|
}
|
|
|
|
if (target == null)
|
|
{
|
|
Clear();
|
|
if (debugLog)
|
|
{
|
|
Debug.Log($"[PlayerAimOutlineHighlighter] Missing InteractOutlineTarget on '{hitCollider.name}'", hitCollider);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (currentTarget != target)
|
|
{
|
|
Clear();
|
|
currentTarget = target;
|
|
currentTarget.SetOutlineMaterial(outlineMaterial);
|
|
}
|
|
|
|
if (currentTarget != null && currentColor != color)
|
|
{
|
|
currentColor = color;
|
|
currentTarget.SetHighlighted(true, currentColor);
|
|
}
|
|
else if (currentTarget != null && currentColor == color)
|
|
{
|
|
currentTarget.SetHighlighted(true, currentColor);
|
|
}
|
|
}
|
|
|
|
private void Clear()
|
|
{
|
|
if (currentTarget != null)
|
|
{
|
|
currentTarget.SetHighlighted(false, currentColor);
|
|
currentTarget = null;
|
|
}
|
|
}
|
|
}
|
|
}
|