166 lines
6.0 KiB
C#
166 lines
6.0 KiB
C#
using UnityEngine;
|
||
|
||
public class PlayerInteractor : MonoBehaviour
|
||
{
|
||
[Header("Настройки луча")]
|
||
[SerializeField] private float interactRange = 3f;
|
||
[SerializeField] private LayerMask interactableLayer;
|
||
|
||
[Header("Клавиши управления")]
|
||
[SerializeField] private KeyCode primaryKey = KeyCode.E;
|
||
[SerializeField] private KeyCode secondaryKey = KeyCode.R;
|
||
[SerializeField] private KeyCode enterVehicleKey = KeyCode.F;
|
||
|
||
[Header("Ссылки")]
|
||
[SerializeField] private UIManager uiManager;
|
||
|
||
private CarPart lastHoveredPart;
|
||
|
||
private void Awake()
|
||
{
|
||
if (uiManager == null)
|
||
uiManager = FindAnyObjectByType<UIManager>();
|
||
}
|
||
|
||
private void OnDisable()
|
||
{
|
||
ResetProgressTargets();
|
||
if (uiManager != null) uiManager.HidePrompt();
|
||
}
|
||
|
||
private void Update()
|
||
{
|
||
if (CarJack.ActiveJackInHand != null)
|
||
{
|
||
uiManager?.ShowPrompt(CarJack.ActiveJackInHand.GetPlacementPrompt());
|
||
return;
|
||
}
|
||
|
||
Ray ray = new Ray(transform.position, transform.forward);
|
||
|
||
if (Physics.Raycast(ray, out RaycastHit hit, interactRange, interactableLayer, QueryTriggerInteraction.Collide))
|
||
{
|
||
GameObject playerRoot = transform.root.gameObject;
|
||
|
||
// 1. ПРИОРИТЕТ БОЛТАМ: проверяем, не целимся ли мы в колесный болт (даже сквозь коллайдер шины)
|
||
WheelBolt bolt = hit.collider.GetComponent<WheelBolt>();
|
||
if (bolt == null)
|
||
{
|
||
Collider[] nearCols = Physics.OverlapSphere(hit.point, 0.06f, interactableLayer, QueryTriggerInteraction.Collide);
|
||
foreach (var c in nearCols)
|
||
{
|
||
bolt = c.GetComponent<WheelBolt>();
|
||
if (bolt != null) break;
|
||
}
|
||
}
|
||
|
||
if (bolt != null)
|
||
{
|
||
ResetProgressTargets();
|
||
string boltPrompt = bolt.GetPrompt();
|
||
if (!string.IsNullOrEmpty(boltPrompt))
|
||
uiManager?.ShowPrompt(boltPrompt);
|
||
else
|
||
uiManager?.HidePrompt();
|
||
return;
|
||
}
|
||
|
||
// 2. Обычные объекты, детали и авто
|
||
IInteractable interactable = hit.collider.GetComponentInParent<IInteractable>();
|
||
VehicleInteraction vehicle = hit.collider.GetComponentInParent<VehicleInteraction>();
|
||
CarPart part = hit.collider.GetComponentInParent<CarPart>();
|
||
CarPartMountZone mountZone = hit.collider.GetComponentInParent<CarPartMountZone>();
|
||
|
||
if (part != lastHoveredPart)
|
||
{
|
||
ResetProgressTargets();
|
||
lastHoveredPart = part;
|
||
}
|
||
|
||
if (interactable != null || vehicle != null)
|
||
{
|
||
// Посадка в авто (F)
|
||
if (Input.GetKeyDown(enterVehicleKey) && vehicle != null)
|
||
{
|
||
vehicle.Interact(playerRoot);
|
||
return;
|
||
}
|
||
|
||
// Зона обратной установки детали (обрабатывается внутри CarPartMountZone)
|
||
if (mountZone != null)
|
||
{
|
||
if (Input.GetKeyDown(primaryKey))
|
||
mountZone.Interact(playerRoot);
|
||
}
|
||
// Работа с деталью (снятие / открытие / подбор с земли)
|
||
else if (part != null)
|
||
{
|
||
if (part.State == PartState.Dropped)
|
||
{
|
||
if (Input.GetKeyDown(primaryKey))
|
||
part.Interact(playerRoot);
|
||
}
|
||
else if (part.State == PartState.Installed)
|
||
{
|
||
bool hasAnimator = part.GetComponent<CarPartAnimator>() != null;
|
||
|
||
if (hasAnimator)
|
||
{
|
||
if (Input.GetKeyDown(primaryKey))
|
||
part.Interact(playerRoot);
|
||
|
||
if (Input.GetKey(secondaryKey))
|
||
part.ProcessUnbolting(playerRoot, Time.deltaTime);
|
||
else
|
||
part.ResetUnbolt();
|
||
}
|
||
else
|
||
{
|
||
if (Input.GetKey(primaryKey))
|
||
part.ProcessUnbolting(playerRoot, Time.deltaTime);
|
||
else
|
||
part.ResetUnbolt();
|
||
}
|
||
}
|
||
}
|
||
else if (interactable != null && Input.GetKeyDown(primaryKey))
|
||
{
|
||
interactable.Interact(playerRoot);
|
||
}
|
||
|
||
string finalPrompt = BuildPrompt(vehicle, interactable);
|
||
if (!string.IsNullOrEmpty(finalPrompt))
|
||
uiManager?.ShowPrompt(finalPrompt);
|
||
else
|
||
uiManager?.HidePrompt();
|
||
|
||
return;
|
||
}
|
||
}
|
||
|
||
ResetProgressTargets();
|
||
uiManager?.HidePrompt();
|
||
}
|
||
|
||
private string BuildPrompt(VehicleInteraction vehicle, IInteractable interactable)
|
||
{
|
||
string partPrompt = (interactable != null && !(interactable is VehicleInteraction))
|
||
? interactable.GetPrompt()
|
||
: string.Empty;
|
||
|
||
bool canEnter = vehicle != null && !vehicle.isPlayerInside;
|
||
|
||
if (canEnter && !string.IsNullOrEmpty(partPrompt))
|
||
return $"[F] Сесть | {partPrompt}";
|
||
if (canEnter)
|
||
return "[F] Сесть в машину";
|
||
|
||
return partPrompt;
|
||
}
|
||
|
||
private void ResetProgressTargets()
|
||
{
|
||
if (lastHoveredPart != null) lastHoveredPart.ResetUnbolt();
|
||
lastHoveredPart = null;
|
||
}
|
||
} |