200 lines
7.1 KiB
C#
200 lines
7.1 KiB
C#
using UnityEngine;
|
||
|
||
public enum PartState { Installed, InHand, Dropped }
|
||
|
||
public class CarPart : MonoBehaviour, IInteractable, ISecondaryInteractable
|
||
{
|
||
[Header("Данные")]
|
||
[SerializeField] private CarPartData partData;
|
||
[SerializeField] private float mass = 12f;
|
||
[Header("Позиционирование в руках")]
|
||
[Tooltip("Дополнительное смещение детали в руках, если она перекрывает весь обзор")]
|
||
[SerializeField] private Vector3 inHandPositionOffset = Vector3.zero;
|
||
[Tooltip("Поворот детали в руках (например, если бампер берется боком)")]
|
||
[SerializeField] private Vector3 inHandRotationOffset = Vector3.zero;
|
||
|
||
private CarPartAnimator partAnimator;
|
||
private PartState currentState = PartState.Installed;
|
||
private Transform originalParent;
|
||
private Vector3 originalLocalPos;
|
||
private Quaternion originalLocalRot;
|
||
private Vector3 originalLocalScale;
|
||
|
||
private Rigidbody rb;
|
||
private Collider partCollider;
|
||
private GameObject currentMountZone;
|
||
|
||
|
||
public CarPartData Data => partData;
|
||
public PartState State => currentState;
|
||
|
||
private void Awake()
|
||
{
|
||
partCollider = GetComponent<Collider>();
|
||
partAnimator = GetComponent<CarPartAnimator>();
|
||
|
||
originalParent = transform.parent;
|
||
originalLocalPos = transform.localPosition;
|
||
originalLocalRot = transform.localRotation;
|
||
originalLocalScale = transform.localScale;
|
||
|
||
|
||
}
|
||
|
||
public string GetPrompt()
|
||
{
|
||
if (partData == null) return "Деталь (E)";
|
||
|
||
if (currentState == PartState.Installed)
|
||
{
|
||
// Если на детали есть аниматор — выводим подсказку с открытием
|
||
if (partAnimator != null)
|
||
{
|
||
string action = partAnimator.IsOpen ? "Закрыть" : "Открыть";
|
||
return $"[E] {action} {partData.partName} | [R] Снять";
|
||
}
|
||
|
||
return $"Снять {partData.partName} (E)";
|
||
}
|
||
|
||
if (currentState == PartState.Dropped)
|
||
{
|
||
return $"Взять {partData.partName} (E)";
|
||
}
|
||
|
||
return string.Empty;
|
||
}
|
||
|
||
public void Interact(GameObject interactor)
|
||
{
|
||
if (currentState == PartState.Installed)
|
||
{
|
||
if (partAnimator != null)
|
||
{
|
||
// Нажали E — открываем или закрываем
|
||
partAnimator.TogglePart();
|
||
}
|
||
else
|
||
{
|
||
// Обычная деталь (бампер) сразу снимается
|
||
TakeToHands(interactor);
|
||
}
|
||
}
|
||
else if (currentState == PartState.Dropped)
|
||
{
|
||
TakeToHands(interactor);
|
||
}
|
||
}
|
||
|
||
// Вызывается при нажатии R (вторичное действие)
|
||
public void SecondaryInteract(GameObject interactor)
|
||
{
|
||
if (currentState == PartState.Installed)
|
||
{
|
||
TakeToHands(interactor);
|
||
}
|
||
}
|
||
|
||
// Вынесенный общий метод взятия в руки
|
||
private void TakeToHands(GameObject interactor)
|
||
{
|
||
PlayerHands hands = interactor.GetComponent<PlayerHands>();
|
||
if (hands == null) hands = interactor.GetComponentInParent<PlayerHands>();
|
||
|
||
if (hands == null) return;
|
||
|
||
if (currentState == PartState.Installed)
|
||
{
|
||
if (partAnimator != null) partAnimator.ResetToClosed();
|
||
CreateMountZone();
|
||
}
|
||
|
||
hands.PickUp(this);
|
||
}
|
||
|
||
public void OnPickedUp(Transform holdPoint)
|
||
{
|
||
currentState = PartState.InHand;
|
||
|
||
// Отключаем физику и коллайдер
|
||
if (rb != null) Destroy(rb);
|
||
partCollider.enabled = false;
|
||
|
||
// 1. Привязываем к рукам и сохраняем оригинальный размер (чтобы не сплющило)
|
||
transform.SetParent(holdPoint);
|
||
transform.localScale = originalLocalScale;
|
||
|
||
// 2. Задаем поворот вперед с учетом возможной ручной поправки
|
||
transform.localRotation = Quaternion.Euler(inHandRotationOffset);
|
||
transform.localPosition = Vector3.zero;
|
||
|
||
// 3. АВТО-ЦЕНТРИРОВАНИЕ: компенсируем сбитый пивот геометрии
|
||
Renderer meshRenderer = GetComponentInChildren<Renderer>();
|
||
if (meshRenderer != null)
|
||
{
|
||
// Находим, где сейчас находится визуальный центр геометрии в мире
|
||
Vector3 visualCenterWorld = meshRenderer.bounds.center;
|
||
|
||
// Вычисляем вектор сдвига, чтобы центр меша совпал с точкой HoldPoint
|
||
Vector3 offsetToCenter = holdPoint.position - visualCenterWorld;
|
||
|
||
// Смещаем деталь так, чтобы её реальный центр оказался в руках
|
||
transform.position += offsetToCenter;
|
||
|
||
// Применяем ручной оффсет, если захотите опустить деталь чуть ниже
|
||
transform.localPosition += inHandPositionOffset;
|
||
}
|
||
}
|
||
|
||
public void OnDropped(Vector3 throwForce)
|
||
{
|
||
currentState = PartState.Dropped;
|
||
|
||
// Отвязываем от игрока
|
||
transform.SetParent(null);
|
||
transform.localScale = originalLocalScale;
|
||
|
||
// Включаем коллайдер обратно
|
||
partCollider.enabled = true;
|
||
if (partCollider is MeshCollider meshCol) meshCol.convex = true;
|
||
|
||
// Включаем физику
|
||
rb = gameObject.AddComponent<Rigidbody>();
|
||
rb.mass = mass;
|
||
rb.interpolation = RigidbodyInterpolation.Interpolate;
|
||
|
||
if (throwForce != Vector3.zero)
|
||
{
|
||
rb.AddForce(throwForce, ForceMode.Impulse);
|
||
}
|
||
}
|
||
|
||
public void Install()
|
||
{
|
||
currentState = PartState.Installed;
|
||
|
||
if (rb != null) Destroy(rb);
|
||
|
||
// Возвращаем на исходное место на машине
|
||
transform.SetParent(originalParent);
|
||
transform.localPosition = originalLocalPos;
|
||
transform.localRotation = originalLocalRot;
|
||
transform.localScale = originalLocalScale;
|
||
|
||
partCollider.enabled = true;
|
||
}
|
||
|
||
private void CreateMountZone()
|
||
{
|
||
if (currentMountZone != null) return;
|
||
|
||
currentMountZone = new GameObject($"MountZone_{gameObject.name}");
|
||
currentMountZone.transform.SetParent(originalParent);
|
||
currentMountZone.transform.localPosition = originalLocalPos;
|
||
currentMountZone.transform.localRotation = originalLocalRot;
|
||
currentMountZone.transform.localScale = originalLocalScale; // Передаем оригинальный масштаб
|
||
|
||
CarPartMountZone zone = currentMountZone.AddComponent<CarPartMountZone>();
|
||
zone.Initialize(this);
|
||
}
|
||
} |