using System.Collections.Generic; using Cirno.Scripts.Interactables; using Godot; namespace Cirno.Scripts.Components.FSM._3DPlayer; public partial class SelectorController : Node { [Signal] public delegate void ShowSelectorEventHandler(); [Signal] public delegate void HideSelectorEventHandler(); [Signal] public delegate void ChangePositionEventHandler(Vector2 position); [Signal] public delegate void ChangeParent3DEventHandler(Node3D node); private bool _canSelect = true; public bool CanSelect => _canSelect; private bool _autoSelect = false; private double _cooldownTimer = 0f; private Interactable _lastInteractable; private List _interactables = []; private int _selectedInteractable; private int SelectedInteractableIndex { get => _selectedInteractable; set { if (value >= _interactables.Count) { _selectedInteractable = 0; return; } if (value < 0) { _selectedInteractable = _interactables.Count - 1; // if (_selectedInteractable < 0) // { // _selectedInteractable = 0; // } return; } _selectedInteractable = value; } } public IInteractable GetSelectedInteractable() { return SelectedInteractableIndex < 0 ? null : _interactables.Count > 0 ? SelectedInteractableIndex >= _interactables.Count ? _interactables[^1] : _interactables[SelectedInteractableIndex] : null; } public IInteractable SelectedInteractable { // The problem here is that if it's deselected the index is -1 // get => // SelectedInteractableIndex < 0 // ? null // : _interactables.Count > 0 // ? SelectedInteractableIndex >= _interactables.Count // ? _interactables[^1] // : _interactables[SelectedInteractableIndex] // : null; set { // Passing null deselects the interactable if (value == null) { _selectedInteractable = -1; NotifyChanged(null); return; } // If it's already in the list, set the current one to it, otherwise add it if (!_interactables.Contains(value)) { AddInteractable(value); } SelectedInteractableIndex = _interactables.IndexOf(value); NotifyChanged(value); } } public void SelectNext() { SelectedInteractableIndex += 1; // _selectedInteractable += 1; // if (_selectedInteractable >= _interactables.Count) // { // _selectedInteractable = 0; // } if (_interactables.Count <= 0) { SelectedInteractable = null; //SelectedInteractableIndex = -1; } // No need to set it because the selection is already handled when reading // else // { // SelectedInteractable = _interactables[_selectedInteractable]; // } UpdatePosition(); } public void SelectNextDelayed() { if (!_canSelect) { _autoSelect = true; } else { SelectNext(); } //CallDeferred(MethodName.SelectNext); } public void AddInteractable(IInteractable interactable) { if (!_interactables.Contains(interactable)) { _interactables.Add(interactable); // if (_interactables.Count == 1) // { // SelectedInteractable = interactable; // //_selectedInteractable = 0; // } } // Always set the current one to the newest SelectedInteractable = interactable; UpdatePosition(); } public void RemoveInteractable(IInteractable interactable) { _interactables.Remove(interactable); UpdatePosition(); } public void Deselect() { SelectedInteractable = null; //SelectedInteractableIndex = -1; EmitSignalHideSelector(); } public void DeselectWithCooldown() { Deselect(); _canSelect = false; _cooldownTimer = 0d; } public void UpdatePosition() { var selected = GetSelectedInteractable(); if (selected != null) { EmitSignalChangePosition(selected.GetScreenPosition()); //EmitSignalChangePosition3D(); EmitSignalChangeParent3D(selected as Node3D); EmitSignalShowSelector(); } else { EmitSignalHideSelector(); } } private void NotifyChanged(IInteractable interactable) { //EmitSignal(nameof(SelectedItemInteractableChanged), interactable); } public void Hide() { EmitSignalHideSelector(); } public void PhysicsProcess(double delta) { if (_canSelect is true) return; _cooldownTimer += delta; if (!(_cooldownTimer >= 0.2d)) return; _canSelect = true; _cooldownTimer = 0; if (!_autoSelect) return; _autoSelect = false; SelectNext(); //if (SelectedInteractable is null) return; //EmitSignalChangePosition(SelectedInteractable.GetScreenPosition()); } }