Files
2026-07-21 08:56:10 +03:00

107 lines
3.5 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
/// <summary>
/// Manages selection state for placed interactable objects.
/// Listens to RayInteractor.OnSelectEvent (which only fires when no ghost is active).
/// Supports single and multi-select (Ctrl/Shift).
/// </summary>
public class SelectionManager : MonoBehaviour
{
private static SelectionManager instance;
public static SelectionManager getInstance() => instance;
private RayInteractor rayInteractor;
private BaseInputProvider inputProvider;
private readonly List<IInteractable> currentSelections = new List<IInteractable>();
private bool multiSelectEnabled = false;
public UnityEvent<IInteractable> SelectionEvent;
// -------------------------------------------------------------------------
// Unity lifecycle
// -------------------------------------------------------------------------
private void Awake()
{
if (instance == null) instance = this;
else Destroy(gameObject);
}
private void Start()
{
rayInteractor = RayInteractor.getInstance();
inputProvider = InputProviderManager.getInstance().getCurrentInputProvider();
inputProvider.OnEnableMultiSelect.AddListener(() => multiSelectEnabled = true);
inputProvider.OnDisableMultiSelect.AddListener(() => multiSelectEnabled = false);
// RayInteractor only fires this when no ghost is active, so we can safely handle selection here
rayInteractor.OnSelectEvent.AddListener(HandleSelect);
}
// -------------------------------------------------------------------------
// Selection logic
// -------------------------------------------------------------------------
private void HandleSelect(IInteractable interactable)
{
if (InputModeManager.Is(InputMode.UI)) return;
if (interactable == null)
{
SelectionEvent?.Invoke(interactable);
// Clicked empty space – clear selection unless multi-select is held
if (!multiSelectEnabled)
ClearSelection();
return;
}
if (multiSelectEnabled)
{
// Toggle the clicked interactable
if (currentSelections.Contains(interactable))
{
currentSelections.Remove(interactable);
interactable.highLightOff();
}
else
{
currentSelections.Add(interactable);
interactable.highLightOn();
}
}
else
{
// Replace selection with just this interactable
bool Exists = currentSelections.Contains(interactable);
ClearSelection();
if (!Exists) {
currentSelections.Add(interactable);
interactable.highLightOn();
}
}
SelectionEvent?.Invoke(interactable);
}
// -------------------------------------------------------------------------
// Public API
// -------------------------------------------------------------------------
public List<IInteractable> GetCurrentSelections() => currentSelections;
public void ClearSelection()
{
foreach (IInteractable selection in currentSelections)
selection.highLightOff();
currentSelections.Clear();
SelectionEvent?.Invoke(null);
}
public bool HasOneSelection()
{
return !(currentSelections.Count > 1 || currentSelections.Count == 0);
}
}