| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442 |
- using UnityEngine;
- using UnityEngine.InputSystem;
- using System.Collections.Generic;
- public class SelectionManager : MonoBehaviour
- {
- [Header("Selection Settings")]
- public LayerMask selectableLayerMask = -1;
- public Material ghostMaterial;
- private Villager selectedVillager;
- private GameObject selectedObject;
- private Camera playerCamera;
- // Drag and Drop
- private bool isDragging = false;
- private GameObject dragGhost;
- private Vector3 dragStartPosition;
- // Box Selection
- private bool isBoxSelecting = false;
- private Vector2 boxSelectionStart;
- public Villager SelectedVillager => selectedVillager;
- public GameObject SelectedObject => selectedObject;
- // Event for selection changes
- public delegate void SelectionChangedHandler();
- public static event SelectionChangedHandler OnSelectionChanged;
- void Start()
- {
- playerCamera = Camera.main;
- if (playerCamera == null)
- playerCamera = FindObjectOfType<Camera>();
- }
- void Update()
- {
- HandleInput();
- HandleDragAndDrop();
- }
- void HandleInput()
- {
- // Left click - selection or box selection start
- var mouse = Mouse.current;
- if (mouse.leftButton.wasPressedThisFrame)
- {
- // Start potential box selection
- boxSelectionStart = mouse.position.ReadValue();
- isBoxSelecting = false; // Not yet, wait for drag
- }
- // Check if dragging for box selection (only when no villager is selected)
- if (mouse.leftButton.isPressed && !isDragging && selectedVillager == null)
- {
- Vector2 currentMousePos = mouse.position.ReadValue();
- float dragDistance = Vector2.Distance(boxSelectionStart, currentMousePos);
- // Start box selection if dragged more than 10 pixels
- if (dragDistance > 10f && !isBoxSelecting)
- {
- isBoxSelecting = true;
- Debug.Log("Started box selection");
- }
- } // Complete box selection on release
- if (mouse.leftButton.wasReleasedThisFrame)
- {
- if (isBoxSelecting)
- {
- CompleteBoxSelection();
- isBoxSelecting = false;
- }
- else if (!isDragging)
- {
- // Single click selection (only if not dragging)
- HandleSelection();
- }
- }
- // Right click - cancel/deselect
- if (mouse.rightButton.wasPressedThisFrame)
- {
- CancelCurrentAction();
- }
- }
- void HandleSelection()
- {
- if (Mouse.current == null || playerCamera == null) return;
- Ray ray = playerCamera.ScreenPointToRay(Mouse.current.position.ReadValue());
- RaycastHit hit;
- if (Physics.Raycast(ray, out hit, Mathf.Infinity, selectableLayerMask))
- {
- GameObject hitObject = hit.collider.gameObject;
- // Check if we hit a villager
- Villager villager = hitObject.GetComponent<Villager>();
- if (villager != null)
- {
- SelectVillager(villager);
- return;
- }
- // Check for other selectable objects
- ISelectable selectable = hitObject.GetComponent<ISelectable>();
- if (selectable != null)
- {
- SelectObject(hitObject);
- return;
- }
- // If we hit something else, check parent objects
- Transform parent = hitObject.transform.parent;
- while (parent != null)
- {
- villager = parent.GetComponent<Villager>();
- if (villager != null)
- {
- SelectVillager(villager);
- return;
- }
- selectable = parent.GetComponent<ISelectable>();
- if (selectable != null)
- {
- SelectObject(parent.gameObject);
- return;
- }
- parent = parent.parent;
- }
- }
- // If we didn't hit anything selectable, deselect
- DeselectAll();
- }
- void HandleDragAndDrop()
- {
- if (Mouse.current == null) return;
- var mouse = Mouse.current;
- // Don't start dragging if box selecting
- if (isBoxSelecting) return;
- // Start dragging
- if (selectedVillager != null && mouse.leftButton.wasPressedThisFrame && !isDragging)
- {
- StartDrag();
- }
- // Update drag
- if (isDragging)
- {
- UpdateDrag();
- }
- // End dragging
- if (isDragging && mouse.leftButton.wasReleasedThisFrame)
- {
- EndDrag();
- }
- }
- void StartDrag()
- {
- isDragging = true;
- dragStartPosition = selectedVillager.transform.position;
- // Create ghost object
- CreateDragGhost();
- }
- void UpdateDrag()
- {
- if (dragGhost != null)
- {
- // Move ghost to mouse position
- Ray ray = playerCamera.ScreenPointToRay(Mouse.current.position.ReadValue());
- if (Physics.Raycast(ray, out RaycastHit hit))
- {
- dragGhost.transform.position = hit.point + Vector3.up * 0.1f;
- }
- }
- }
- void EndDrag()
- {
- isDragging = false;
- if (dragGhost != null)
- {
- Vector3 dropPosition = dragGhost.transform.position;
- // Check what we're dropping on
- Ray ray = playerCamera.ScreenPointToRay(Mouse.current.position.ReadValue());
- if (Physics.Raycast(ray, out RaycastHit hit))
- {
- HandleDrop(hit.collider.gameObject, dropPosition);
- }
- DestroyDragGhost();
- }
- }
- void CreateDragGhost()
- {
- if (selectedVillager != null)
- {
- dragGhost = Instantiate(selectedVillager.gameObject);
- // Make it a ghost (semi-transparent, no collisions)
- Collider ghostCollider = dragGhost.GetComponent<Collider>();
- if (ghostCollider != null)
- ghostCollider.enabled = false;
- // Remove any scripts that might interfere
- Villager ghostVillager = dragGhost.GetComponent<Villager>();
- if (ghostVillager != null)
- Destroy(ghostVillager);
- // Apply ghost material
- Renderer ghostRenderer = dragGhost.GetComponent<Renderer>();
- if (ghostRenderer != null && ghostMaterial != null)
- {
- ghostRenderer.material = ghostMaterial;
- }
- else if (ghostRenderer != null)
- {
- Color ghostColor = ghostRenderer.material.color;
- ghostColor.a = 0.5f;
- ghostRenderer.material.color = ghostColor;
- }
- }
- }
- void DestroyDragGhost()
- {
- if (dragGhost != null)
- {
- Destroy(dragGhost);
- dragGhost = null;
- }
- }
- void HandleDrop(GameObject dropTarget, Vector3 dropPosition)
- {
- if (selectedVillager == null) return;
- VillagerManager villagerManager = GameManager.Instance.villagerManager;
- // Determine what to do based on drop target
- string targetTag = dropTarget.tag;
- JobType newJob = targetTag switch
- {
- "Tree" => JobType.Woodcutter,
- "Stone" => JobType.Stonecutter,
- "Farm" => JobType.Farmer,
- "TownHall" => JobType.None, // Unemployed - return to town hall
- _ => selectedVillager.currentJob // Keep current job if dropped on something else
- };
- // Special check for Builder job - requires workshop
- if (newJob == JobType.Builder)
- {
- GameObject[] workshops = GameObject.FindGameObjectsWithTag("BuildingWorkshop");
- if (workshops == null || workshops.Length == 0)
- {
- Debug.LogWarning("⚠️ Cannot assign Builder job - No Builder's Workshop found! Build one first.");
- return;
- }
- }
- if (newJob != selectedVillager.currentJob || (newJob != JobType.None && selectedVillager.targetWorkplace != dropTarget))
- {
- // Assign job and specific workplace
- villagerManager.AssignVillagerToSpecificWorkplace(selectedVillager, newJob, dropTarget);
- Debug.Log($"Assigned {selectedVillager.villagerName} to {newJob} at specific {dropTarget.name}");
- }
- }
- public void SelectVillager(Villager villager)
- {
- // Deselect previous
- DeselectAll();
- selectedVillager = villager;
- selectedObject = villager.gameObject;
- villager.SetSelected(true);
- Debug.Log($"SelectionManager: Selected villager: {villager.villagerName}");
- Debug.Log($"SelectionManager: OnVillagerSelected event triggered");
- // Notify UI of selection change
- OnSelectionChanged?.Invoke();
- }
- public void SelectObject(GameObject obj)
- {
- // Deselect previous
- DeselectAll();
- selectedObject = obj;
- ISelectable selectable = obj.GetComponent<ISelectable>();
- selectable?.OnSelected();
- Debug.Log($"Selected object: {obj.name}");
- // Notify UI of selection change
- OnSelectionChanged?.Invoke();
- }
- public void DeselectAll()
- {
- if (selectedVillager != null)
- {
- selectedVillager.SetSelected(false);
- selectedVillager = null;
- }
- if (selectedObject != null)
- {
- ISelectable selectable = selectedObject.GetComponent<ISelectable>();
- selectable?.OnDeselected();
- selectedObject = null;
- }
- // Cancel any ongoing drag
- if (isDragging)
- {
- isDragging = false;
- DestroyDragGhost();
- }
- Debug.Log("SelectionManager: Deselected all");
- // Notify UI of selection change
- OnSelectionChanged?.Invoke();
- }
- void OnGUI()
- {
- if (isBoxSelecting && Mouse.current != null)
- {
- Vector2 mouseStart = boxSelectionStart;
- Vector2 mouseEnd = Mouse.current.position.ReadValue();
- // Convert to GUI coordinates (Y is flipped)
- mouseStart.y = Screen.height - mouseStart.y;
- mouseEnd.y = Screen.height - mouseEnd.y;
- Rect selectionRect = new Rect(
- Mathf.Min(mouseStart.x, mouseEnd.x),
- Mathf.Min(mouseStart.y, mouseEnd.y),
- Mathf.Abs(mouseStart.x - mouseEnd.x),
- Mathf.Abs(mouseStart.y - mouseEnd.y)
- );
- // Draw selection box
- GUI.color = new Color(0.8f, 0.8f, 0.95f, 0.25f);
- GUI.DrawTexture(selectionRect, Texture2D.whiteTexture);
- GUI.color = new Color(0.8f, 0.8f, 0.95f, 1f);
- GUI.Box(selectionRect, "");
- }
- }
- void CompleteBoxSelection()
- {
- Vector2 mouseStart = boxSelectionStart;
- Vector2 mouseEnd = Mouse.current.position.ReadValue();
- // Create screen space rectangle
- Rect selectionRect = new Rect(
- Mathf.Min(mouseStart.x, mouseEnd.x),
- Mathf.Min(mouseStart.y, mouseEnd.y),
- Mathf.Abs(mouseStart.x - mouseEnd.x),
- Mathf.Abs(mouseStart.y - mouseEnd.y)
- );
- // Find all villagers
- Villager[] allVillagers = FindObjectsOfType<Villager>();
- Villager firstVillager = null;
- foreach (Villager villager in allVillagers)
- {
- Vector3 screenPos = playerCamera.WorldToScreenPoint(villager.transform.position);
- // Check if villager is in selection box and in front of camera
- if (screenPos.z > 0 && selectionRect.Contains(new Vector2(screenPos.x, screenPos.y)))
- {
- if (firstVillager == null)
- {
- firstVillager = villager;
- }
- }
- }
- // Select the first villager found
- if (firstVillager != null)
- {
- SelectVillager(firstVillager);
- Debug.Log($"Box selection completed: selected {firstVillager.villagerName}");
- }
- else
- {
- Debug.Log("Box selection completed: no villagers found");
- }
- }
- void CancelCurrentAction()
- {
- if (isDragging)
- {
- isDragging = false;
- DestroyDragGhost();
- }
- else if (isBoxSelecting)
- {
- isBoxSelecting = false;
- }
- else
- {
- DeselectAll();
- }
- Debug.Log("Cancelled current action");
- }
- }
- // Interface for selectable objects
- public interface ISelectable
- {
- void OnSelected();
- void OnDeselected();
- }
|