using System; using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; using VOID.Generic.Objects.Item; using VOID.Generic.Player.DraggingOperation; using VOID.Generic.Player.Input; using VOID.Generic.Player.Util; using VOID.UserInterface; using VOID.UserInterface.Game; using VOID.Generic.Util; using VOID.ScriptableObjects.Abilities; namespace VOID.Generic.Player { [DefaultExecutionOrder(-1)] public class DraggingManager : MonoBehaviour { public static DraggingManager current {get; private set;} // References private PlayerController _playerController; private PlayerInputManager _playerInputManager; private GameUI _gameUI; private DraggingUI _draggingUI; // Configuration [SerializeField] private float startDraggingAfter = 0.2f; // Private properties private List _draggingOperations; private SelectUtilResult _sourceSelect; private SelectUtilResult _targetSelect; private bool _isDragging; private bool _isPreparing; // Submodule that visualize player's dragging private DraggingVisualizer _draggingVisualizer; // Transform from those GameObjects used as start and end for trajectory private GameObject _draggingFrom; private GameObject _draggingTo; private void Awake() { current = this; var thisTransform = transform; _draggingFrom = new GameObject("Dragging From"); _draggingFrom.transform.parent = thisTransform; _draggingTo = new GameObject("Dragging To"); _draggingTo.transform.parent = thisTransform; _draggingOperations = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(assembly => assembly.GetTypes()) .Where(type => type.IsSubclassOf(typeof(AbstractDraggingOperation)) && type.IsClass) .Select(Activator.CreateInstance) .Cast() .ToList(); } private void Start() { _playerInputManager = PlayerInputManager.current; _playerInputManager.OnDraggingPrepare += PrepareDragging; _playerInputManager.OnDraggingStart += StartDragging; _playerInputManager.OnDraggingEnd += EndDragging; _playerController = PlayerController.current; _gameUI = GameUI.current; _draggingUI = DraggingUI.current; } private void FixedUpdate() { Dragging(); } /// /// Checks that the operation can be performed and prepares the data for use /// private void PrepareDragging() { if (_isPreparing || _isDragging) Clean(); var sourceSelect = SelectUtil.Select(); // Dragging only when ability or item selected (and can be dragged) if (!sourceSelect.selectObject && !sourceSelect.selectAbility) return; if (sourceSelect.selectObject is not null and not ItemObject) return; var selectItem = (ItemObject)sourceSelect.selectObject; if (selectItem && !selectItem.itemData.canBeMoved) return; _draggingFrom.transform.position = sourceSelect.position; _draggingTo.transform.position = sourceSelect.position; _sourceSelect = sourceSelect; _isPreparing = true; } /// /// Initiate draging visualisation /// Requied: PrepapreDragging to be done before /// private void StartDragging() { if(!_isPreparing) return; _isDragging = true; if(_sourceSelect.selectObject is ItemObject) StartDraggingItem((ItemObject)_sourceSelect.selectObject); else if(_sourceSelect.selectAbility) StartDraggingAbility(_sourceSelect.selectAbility); } private void StartDraggingItem(ItemObject item) { // Prepare for Scene dragging _draggingVisualizer = DraggingVisualizer.Create(_draggingFrom.transform, _draggingTo.transform, item); // Prepare for UI dragging _draggingUI.Set(item); } private void StartDraggingAbility(BasicAbility ability) { _draggingUI.Set(ability); _draggingUI.Show(); } private void Dragging() { if (!_isDragging) return; if (_sourceSelect.selectObject && !_gameUI.isCursorOverUI) DraggingItemOnScene(); else if (_sourceSelect.selectObject && _gameUI.isCursorOverUI) DraggingItemOnUI(); else if (_sourceSelect.selectAbility) DraggingAbility(); } private void DraggingItemOnScene() { _draggingUI.Hide(); var hit = SelectUtil.SelectHit(); _draggingTo.transform.position = hit.point; // Dragging only onto STATIC objects (like floor) if (hit.collider.gameObject.layer is not LayerManager.StaticIndex) { _draggingVisualizer.Hide(); return; } var isInRange = RangeUtil.IsInRange( _draggingFrom.transform.position, _draggingTo.transform.position, _playerController.activeUnit.unitData.takeRange*2, false ); // Dragging only when in player's unit range (2 * take range) if (!isInRange) { _draggingVisualizer.Hide(); return; } _draggingVisualizer.Show(); } private void DraggingItemOnUI() { _draggingUI.Show(); _draggingVisualizer.Hide(); } private void DraggingAbility() { } /// /// This function completes the transfer process. It contains the main logic responsible for moving an object from one place to another /// Required: StartDragging to be done before /// private void EndDragging() { if (!_isDragging) { Clean(); return; } _targetSelect = SelectUtil.Select(); if (_gameUI.isCursorOverUI && _targetSelect.slotUI?.slotType == null) { Debug.LogWarning("Dragged into invalid place over UI"); Clean(); return; } var operation = _draggingOperations.FirstOrDefault(op => op.Check(_sourceSelect, _targetSelect)); if (operation != null) { operation.Perform(_playerController.activeUnit, _sourceSelect, _targetSelect); Clean(); return; } Debug.LogWarning("Dragging between unsupported places: " + $"'{_sourceSelect.slotUI?.slotType}' -> '{_targetSelect.slotUI?.slotType}'"); Clean(); } private void Clean() { if (_draggingVisualizer) { Destroy(_draggingVisualizer.gameObject); _draggingVisualizer = null; } _isDragging = false; _isPreparing = false; _sourceSelect = null; _targetSelect = null; _draggingUI.Hide(); } } }