using System.Collections.Generic; using System.Linq; using Cirno.Scripts.Components.Actors; using Cirno.Scripts.Interactables; using Godot; namespace Cirno.Scripts.Components.FSM._3DPlayer; public partial class IsoActivationProvider : Area3D, IModule { private bool _enabled = false; public bool Enabled { get => _enabled; set { if (_enabled == value) return; _enabled = value; } } [Export] private InputProvider _inputProvider; [Export] private SelectorController _selectorController; [Export] private AudioStreamPlayer _errorSound; [Export] public PackedScene SelectorScene { get; set; } private Node3D _selector; public IStateMachine StateMachine { get; private set; } private CollisionShape3D _collisionShape; public void EnterState(PlayerState state) { Enabled = true; AreaEntered += _on_interaction_controller_area_entered; AreaExited += _on_interaction_controller_area_exited; } public void ExitState(PlayerState state) { Enabled = false; AreaEntered -= _on_interaction_controller_area_entered; AreaExited -= _on_interaction_controller_area_exited; } public void Init(IStateMachine machine) { StateMachine = machine; _collisionShape = GetNode("CollisionShape"); _selectorController.Hide(); _selectorController.ShowSelector += ShowSelector; _selectorController.HideSelector += HideSelector; _selectorController.ChangeParent3D += OnChangeParent3D; // if (SelectorScene is not null && _selector is null) // { // _selector = actor.CreateSibling(SelectorScene, this.GlobalPosition); // _selector.Visible = false; // } } private void OnChangeParent3D(Node3D node) { if (IsInstanceValid(_selector) && _selector is not null) { if (node is null) { _selector.Hide(); } else { _selector.GlobalPosition = node.GlobalPosition; _selector.Show(); //_selector.Reparent(node); } } else { _selector = SelectorScene.Instantiate(); //node.AddChild(_selector); StateMachine.MainObject.GetParent().AddChild(_selector); //sel.GlobalPosition = StateMachine.MainObject.GlobalPosition; _selector.GlobalPosition = node.GlobalPosition; } //_selector.Position = Vector3.Zero; } private void ShowSelector() { if (IsInstanceValid(_selector)) { _selector?.Show(); } } private void HideSelector() { if (IsInstanceValid(_selector)) { _selector?.Hide(); } } private void SpawnSelector(Node3D parent) { var sel = SelectorScene.Instantiate(); StateMachine.MainObject.GetParent().AddChild(sel); sel.GlobalPosition = StateMachine.MainObject.GlobalPosition; _selectorController.ShowSelector += () => { sel.Show(); }; _selectorController.HideSelector += () => { sel.Reparent(this); sel.Hide(); }; _selectorController.ChangeParent3D += parent => { if (parent is not null) { sel.Reparent(parent); } else { sel.Reparent(this); sel.Hide(); } sel.Position = Vector3.Zero; }; // if (Hud.Instance is not null) // { // Hud.Instance.CreateSelector(_selectorController); // } } public void Process(double delta) { } public void PhysicsProcess(double delta) { _selectorController.PhysicsProcess(delta); HandleInteraction(); } public void HandleInteraction() { if (!_selectorController.CanSelect) return; if (_inputProvider.GetUseJustPressed()) { if (!TrySelect()) { _selectorController.SelectNext(); } return; } if (_inputProvider.GetScanJustPressed()) { var items = ScanTargets(); _selectorController.SelectNext(); } } private bool TrySelect() { var selected = _selectorController.GetSelectedInteractable(); if (selected is null) { _errorSound?.Play(); return false; } ; if (!selected.CanActivate()) { _errorSound?.Play(); return true; } ; bool success = selected.Activate(ActivationType.Use); if (success) { // Deselect and scan for next //_selectorController.RemoveInteractable(selected); //_selectorController.DeselectWithCooldown(); _selectorController.Deselect(); // Do this at end of frame instead //_selectorController.SelectNext(); _selectorController.SelectNext(); } else { _errorSound?.Play(); } return true; //var spaceState = GetWorld2D().DirectSpaceState; //var query = PhysicsRayQueryParameters2D.Create(Vector2.Zero, ) } private List ScanTargets() { var spaceState = GetWorld3D().DirectSpaceState; var query = new PhysicsShapeQueryParameters3D() { Shape = _collisionShape.Shape, CollideWithBodies = false, CollideWithAreas = true, CollisionMask = this.CollisionMask, Exclude = [GetRid()], }; var targets = spaceState.IntersectShape(query); if (targets.Count is 0) return null; var found = targets.Select(resDict => { var collider = resDict["collider"].As(); if (collider.IsInGroup("Interactable") && collider is IInteractable interactable && interactable.CanActivate()) { return interactable; } else { return null; } } ).Where(x => x is not null).ToList(); return found; } private void _on_interaction_controller_area_entered(Area3D area) { if (!Enabled) return; if (area.IsInGroup("Interactable") && area is IInteractable interactable && interactable.CanActivate()) { //if (_selector == null) return; _selectorController.AddInteractable(interactable); } } private void _on_interaction_controller_area_exited(Area3D area) { //if (!Enabled) return; if (area.IsInGroup("Interactable") && area is IInteractable interactable) { //if (_selector == null) return; _selectorController.RemoveInteractable(interactable); } } }