using UnityEngine; using UnityEngine.AI; using UnityEngine.InputSystem; public class ClickToMoveInputSystem : MonoBehaviour { [Header("References")] public Camera cam; public LayerMask movementLayers; // ground public LayerMask selectionLayers; // enemies, NPCs, interactables [Header("Options")] [SerializeField] private bool useLegacyMouseFallback = false; [SerializeField] private bool enableDebugLogs = false; Camera cachedCam; Vector2 pointerScreenPos; PlayerInteractionController cachedInteraction; NavMeshMovementController cachedMovement; PlayerCombatController cachedCombat; void Awake() { CacheCameraReference(); CachePlayerReferences(); } void CacheCameraReference() { if (cam != null) { cachedCam = cam; } else { cachedCam = Camera.main; if (cachedCam == null) Debug.LogError("ClickToMoveInputSystem: No camera found! Assign one in the inspector or ensure Camera.main exists.", gameObject); } } void CachePlayerReferences() { if (Player.current == null) { cachedInteraction = null; cachedMovement = null; cachedCombat = null; return; } cachedInteraction = Player.current.GetComponent(); cachedMovement = Player.current.MovementController; cachedCombat = Player.current.GetComponent(); if (cachedMovement == null) { cachedMovement = Player.current.GetComponent(); } } PlayerInteractionController GetInteraction() { if (Player.current == null) return null; if (cachedInteraction == null || cachedInteraction.gameObject != Player.current.gameObject) { CachePlayerReferences(); } return cachedInteraction; } NavMeshMovementController GetMovement() { if (Player.current == null) return null; if (cachedMovement == null || cachedMovement.gameObject != Player.current.gameObject) { CachePlayerReferences(); } return cachedMovement; } PlayerCombatController GetCombat() { if (Player.current == null) return null; if (cachedCombat == null || cachedCombat.gameObject != Player.current.gameObject) { CachePlayerReferences(); } return cachedCombat; } void Log(string message) { if (enableDebugLogs) { Debug.Log(message, gameObject); } } // Hook this to PointerPos action (Value Vector2) public void OnPointerPos(InputAction.CallbackContext ctx) { pointerScreenPos = ctx.ReadValue(); } // Hook this to LeftClick action (Button) public void OnLeftClick(InputAction.CallbackContext ctx) { if (!ctx.performed) return; HandleLeftClick(); } private void HandleLeftClick() { if (cachedCam == null) return; Ray ray = cachedCam.ScreenPointToRay(pointerScreenPos); if (Physics.Raycast(ray, out RaycastHit hit, 500f, selectionLayers)) { // Try NPC first var npc = hit.collider.GetComponentInParent(); if (npc != null) { // Check if NPC has a Selectable component var selectable = npc.GetComponent(); if (selectable != null && SelectionManager.Instance != null) { SelectionManager.Instance.Select(selectable); } Debug.Log($"Selected NPC: {npc.npcName} ({npc.npcType})"); return; } // Try building first var building = hit.collider.GetComponentInParent(); if (building != null) { if (SelectionManager.Instance != null) SelectionManager.Instance.Select(building); Log($"Selected building: {building.buildingName}"); return; } // Try to find a Selectable (Character, NPC, etc.) var selectable2 = hit.collider.GetComponentInParent(); if (selectable2 != null) { if (SelectionManager.Instance != null) SelectionManager.Instance.Select(selectable2); // Set player target if it's a character var character = selectable2.GetComponent(); if (character != null && Player.current != null) { Player.current.SetTarget(character); } Log($"Selected: {selectable2.displayName}"); return; } // Check for interactive objects (gates, bridges, ledges without Selection Manager) var interactiveObject = hit.collider.GetComponentInParent(); if (interactiveObject != null) { Log($"Selected interactive object: {interactiveObject.GetDisplayName()}"); return; } // Generic interactable (if needed) var interactable = hit.collider.GetComponentInParent(); if (interactable != null) { interactable.OnSelect(); Log($"Interacted with: {interactable.name}"); return; } } // Nothing selected, clear selection and target if (SelectionManager.Instance != null) SelectionManager.Instance.ClearSelection(); if (Player.current != null) Player.current.SetTarget(null); } // Hook this to RightClick action (Button) public void OnRightClick(InputAction.CallbackContext ctx) { if (!ctx.performed) return; HandleRightClick(); } private void HandleRightClick() { if (cachedCam == null || Player.current == null) return; Ray ray = cachedCam.ScreenPointToRay(pointerScreenPos); // First check if right-clicking on a building to interact with it if (Physics.Raycast(ray, out RaycastHit hit, 500f, selectionLayers)) { // Check for enemy combat target first var enemy = hit.collider.GetComponentInParent(); if (enemy != null) { var combat = GetCombat(); if (combat != null) { combat.SetTargetEnemy(enemy); Log($"Set combat target: {enemy.enemyName}"); } else { // Fallback: move to enemy and look at them var movement = GetMovement(); if (movement != null) { movement.MoveToAndLookAt(enemy.transform.position, enemy.transform.position); } } return; } // Check for NPC interaction first var npc = hit.collider.GetComponentInParent(); if (npc != null) { var combat = GetCombat(); if (combat != null) combat.ClearCombatTarget(); var interaction = GetInteraction(); if (interaction != null) { interaction.SetPendingNPCInteraction(npc); Log($"Set interaction target: {npc.npcName}"); } else { // Fallback: move to NPC and look at them var movement = GetMovement(); if (movement != null) { movement.MoveToAndLookAt(npc.transform.position, npc.transform.position); Log($"Moving to NPC: {npc.npcName}"); } } return; } var building = hit.collider.GetComponentInParent(); if (building != null) { var combat = GetCombat(); if (combat != null) combat.ClearCombatTarget(); // If building can be entered and has an entry point, move to the door if (building.canEnter && building.entryPoint != null) { var interaction = GetInteraction(); if (interaction != null) { interaction.SetPendingBuildingInteraction(building); Log($"Set interaction target: {building.buildingName}"); } else { // Fallback: move to entry point and look at it var movement = GetMovement(); if (movement != null) { movement.MoveToAndLookAt(building.entryPoint.position, building.transform.position); } } } else { // Cannot enter building - move as close as possible via NavMesh and look at building var movement = GetMovement(); if (movement != null) { // Move toward the hit point and set look target to building center movement.MoveToAndLookAt(hit.point, building.transform.position); Log($"Moving toward building: {building.buildingName}"); } } return; } // Check for other interactive objects (gates, bridges, ledges, etc.) var interactiveObject = hit.collider.GetComponentInParent(); if (interactiveObject != null) { var combat = GetCombat(); if (combat != null) combat.ClearCombatTarget(); var interaction = GetInteraction(); if (interaction != null) { Vector3 interactionPoint = interactiveObject.GetInteractionPoint(); interaction.SetPendingInteraction(interactiveObject, interactionPoint); Log($"Set interaction target: {interactiveObject.GetDisplayName()}"); } else { // Fallback if no PlayerInteractionController - move to interaction point directly and look at it var movement = GetMovement(); if (movement != null) { Vector3 interactionPoint = interactiveObject.GetInteractionPoint(); movement.MoveToAndLookAt(interactionPoint, interactionPoint); Log($"Moving to interactive object: {interactiveObject.GetDisplayName()}"); } } return; } } // If not an interactive object, check for movement destination if (Physics.Raycast(ray, out RaycastHit groundHit, 500f, movementLayers)) { var combat = GetCombat(); if (combat != null) combat.ClearCombatTarget(); var movement = GetMovement(); if (movement != null) { movement.MoveTo(groundHit.point); Log($"Moving to point: {groundHit.point}"); } else { // fallback: try to find NavMeshAgent on player root var agent = Player.current.GetComponent(); if (agent != null) agent.SetDestination(groundHit.point); } } } // Optional fallback if PointerPos not wired void Update() { if (!useLegacyMouseFallback) return; if (cachedCam == null) return; if (Mouse.current == null) return; pointerScreenPos = Mouse.current.position.ReadValue(); if (Mouse.current.leftButton.wasPressedThisFrame) { HandleLeftClick(); } if (Mouse.current.rightButton.wasPressedThisFrame) { HandleRightClick(); } } }