241 lines
7.8 KiB
C#
241 lines
7.8 KiB
C#
using UnityEngine;
|
|
|
|
/// <summary>
|
|
/// Handles proximity-based interactions for the player.
|
|
/// Automatically triggers interactions when the player gets within range.
|
|
/// Scalable for buildings, gates, bridges, ledges, and other interactive objects.
|
|
/// </summary>
|
|
public class PlayerInteractionController : MonoBehaviour
|
|
{
|
|
[Header("Interaction Settings")]
|
|
[SerializeField]
|
|
private float interactionRange = 1.5f; // "Arm's reach" distance
|
|
[SerializeField]
|
|
private float stoppingDistance = 0.5f; // How close to the entry point before triggering the interaction
|
|
|
|
[Header("Debug")]
|
|
[SerializeField]
|
|
private bool enableDebugLogs = false;
|
|
|
|
private NavMeshMovementController movementController;
|
|
private Building pendingBuildingInteraction;
|
|
private IInteractiveObject pendingInteraction;
|
|
private NPC pendingNPCInteraction;
|
|
|
|
void Awake()
|
|
{
|
|
movementController = GetComponent<NavMeshMovementController>();
|
|
if (movementController == null)
|
|
Debug.LogWarning("PlayerInteractionController requires NavMeshMovementController on the same GameObject.", gameObject);
|
|
}
|
|
|
|
void Update()
|
|
{
|
|
// Check if we should trigger pending building interaction
|
|
if (pendingBuildingInteraction != null)
|
|
{
|
|
CheckBuildingInteractionProximity();
|
|
}
|
|
|
|
// Check for generic interactive objects in range
|
|
if (pendingInteraction != null)
|
|
{
|
|
CheckGenericInteractionProximity();
|
|
}
|
|
|
|
// Check for NPC interactions in range
|
|
if (pendingNPCInteraction != null)
|
|
{
|
|
CheckNPCInteractionProximity();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set a building as the pending interaction target.
|
|
/// The player will move to the building's entry point and enter when close enough.
|
|
/// </summary>
|
|
public void SetPendingBuildingInteraction(Building building)
|
|
{
|
|
if (building == null) return;
|
|
|
|
// Clear any previous interaction
|
|
ClearPendingInteraction();
|
|
|
|
pendingBuildingInteraction = building;
|
|
|
|
// Move to the building's entry point and look at the building
|
|
if (movementController != null && building.entryPoint != null)
|
|
{
|
|
movementController.MoveToAndLookAt(building.entryPoint.position, building.transform.position);
|
|
Log($"PlayerInteractionController: Moving to {building.buildingName}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set a generic interactive object as the pending interaction target.
|
|
/// Scalable for gates, bridges, ledges, etc.
|
|
/// </summary>
|
|
public void SetPendingInteraction(IInteractiveObject interactiveObject, Vector3 targetPosition)
|
|
{
|
|
if (interactiveObject == null) return;
|
|
|
|
ClearPendingInteraction();
|
|
|
|
pendingInteraction = interactiveObject;
|
|
|
|
if (movementController != null)
|
|
{
|
|
movementController.MoveToAndLookAt(targetPosition, targetPosition);
|
|
Log("PlayerInteractionController: Moving to interactive object");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set an NPC as the pending interaction target.
|
|
/// The player will move to the NPC and trigger interaction when close enough.
|
|
/// </summary>
|
|
public void SetPendingNPCInteraction(NPC npc)
|
|
{
|
|
if (npc == null) return;
|
|
|
|
ClearPendingInteraction();
|
|
|
|
pendingNPCInteraction = npc;
|
|
|
|
if (movementController != null)
|
|
{
|
|
movementController.MoveToAndLookAt(npc.transform.position, npc.transform.position);
|
|
Log($"PlayerInteractionController: Moving to interact with {npc.npcName}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clear any pending interactions
|
|
/// </summary>
|
|
public void ClearPendingInteraction()
|
|
{
|
|
pendingBuildingInteraction = null;
|
|
pendingInteraction = null;
|
|
pendingNPCInteraction = null;
|
|
}
|
|
|
|
private void CheckBuildingInteractionProximity()
|
|
{
|
|
if (pendingBuildingInteraction == null || pendingBuildingInteraction.entryPoint == null)
|
|
{
|
|
pendingBuildingInteraction = null;
|
|
return;
|
|
}
|
|
|
|
float distanceToEntry = Vector3.Distance(transform.position, pendingBuildingInteraction.entryPoint.position);
|
|
|
|
// Check if player is close enough to interact
|
|
if (distanceToEntry <= stoppingDistance)
|
|
{
|
|
// Check if building can be entered
|
|
if (pendingBuildingInteraction.canEnter)
|
|
{
|
|
// Check gate status
|
|
if (pendingBuildingInteraction.gate != null && pendingBuildingInteraction.gate.isLocked)
|
|
{
|
|
Log($"Cannot enter {pendingBuildingInteraction.buildingName}: Gate is locked");
|
|
pendingBuildingInteraction = null;
|
|
return;
|
|
}
|
|
|
|
// Check if we need to open the gate
|
|
if (pendingBuildingInteraction.gate != null && !pendingBuildingInteraction.gate.IsOpen())
|
|
{
|
|
pendingBuildingInteraction.gate.Open();
|
|
Log($"Opening gate for {pendingBuildingInteraction.buildingName}");
|
|
// Wait a moment for the gate to open before entering
|
|
return;
|
|
}
|
|
|
|
// Enter the building
|
|
pendingBuildingInteraction.Enter();
|
|
Log($"Entering {pendingBuildingInteraction.buildingName}");
|
|
pendingBuildingInteraction = null;
|
|
|
|
// Stop movement
|
|
if (movementController != null)
|
|
movementController.Stop();
|
|
}
|
|
else
|
|
{
|
|
Log($"Cannot enter {pendingBuildingInteraction.buildingName}: Building is not enterable");
|
|
pendingBuildingInteraction = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CheckGenericInteractionProximity()
|
|
{
|
|
if (pendingInteraction == null) return;
|
|
|
|
Vector3 interactionPoint = pendingInteraction.GetInteractionPoint();
|
|
float distanceToInteraction = Vector3.Distance(transform.position, interactionPoint);
|
|
|
|
if (distanceToInteraction <= interactionRange)
|
|
{
|
|
if (pendingInteraction.CanInteract())
|
|
{
|
|
pendingInteraction.Interact(gameObject);
|
|
Log("Triggered interaction");
|
|
pendingInteraction = null;
|
|
|
|
if (movementController != null)
|
|
movementController.Stop();
|
|
}
|
|
else
|
|
{
|
|
Log("Cannot interact: conditions not met");
|
|
pendingInteraction = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CheckNPCInteractionProximity()
|
|
{
|
|
if (pendingNPCInteraction == null) return;
|
|
|
|
float distanceToNPC = Vector3.Distance(transform.position, pendingNPCInteraction.transform.position);
|
|
|
|
// Check if player is close enough to the NPC
|
|
if (distanceToNPC <= interactionRange)
|
|
{
|
|
// Trigger the NPC interaction
|
|
pendingNPCInteraction.OnInteract(gameObject);
|
|
Log($"Triggered NPC interaction: {pendingNPCInteraction.npcName}");
|
|
|
|
// Clear the pending interaction
|
|
pendingNPCInteraction = null;
|
|
|
|
// Stop player movement
|
|
if (movementController != null)
|
|
movementController.Stop();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the current interaction range setting
|
|
/// </summary>
|
|
public float GetInteractionRange() => interactionRange;
|
|
|
|
/// <summary>
|
|
/// Set the interaction range (useful for difficulty settings or equipment modifiers)
|
|
/// </summary>
|
|
public void SetInteractionRange(float range)
|
|
{
|
|
interactionRange = Mathf.Max(0.1f, range);
|
|
}
|
|
|
|
private void Log(string message)
|
|
{
|
|
if (enableDebugLogs)
|
|
{
|
|
Debug.Log(message);
|
|
}
|
|
}
|
|
}
|