Perekyp/Assets/Scripts/Car/PartData/CarPart.cs

161 lines
5.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using UnityEngine;
public enum PartState { Installed, InHand, Dropped }
[RequireComponent(typeof(Collider))]
public class CarPart : MonoBehaviour, IInteractable
{
[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 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>();
originalParent = transform.parent;
originalLocalPos = transform.localPosition;
originalLocalRot = transform.localRotation;
originalLocalScale = transform.localScale;
}
public string GetPrompt()
{
if (partData == null) return "Деталь (E)";
return currentState switch
{
PartState.Installed => $"Снять {partData.partName} (E)",
PartState.Dropped => $"Взять {partData.partName} (E)",
_ => string.Empty
};
}
public void Interact(GameObject interactor)
{
PlayerHands hands = interactor.GetComponent<PlayerHands>();
if (hands == null) hands = interactor.GetComponentInParent<PlayerHands>();
if (hands == null) return;
if (currentState == PartState.Installed)
{
// 1. Создаем зону для обратной установки на машине
CreateMountZone();
// 2. Берем сразу в руки
hands.PickUp(this);
}
else if (currentState == PartState.Dropped)
{
// Подбираем деталь с земли
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);
}
}