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

283 lines
9.6 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 }
public class CarPart : MonoBehaviour, IInteractable, ISecondaryInteractable
{
[Header("Данные")]
[SerializeField] private CarPartData partData;
[SerializeField] private float mass = 12f;
[Header("Позиционирование в руках")]
[SerializeField] private Vector3 inHandPositionOffset = Vector3.zero;
[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 WheelBolt[] wheelBolts;
private WheelCollider linkedWheelCollider;
private Transform currentHoldPoint;
private Vector3 targetInHandLocalPos;
private Quaternion targetInHandLocalRot;
private Rigidbody rb;
private Collider partCollider;
private GameObject currentMountZone;
private float unboltDuration => (partData != null && partData.boltDuration > 0f) ? partData.boltDuration : 1.2f;
private float unboltProgress = 0f;
public float UnboltProgress01 => Mathf.Clamp01(unboltProgress / unboltDuration);
public void ResetUnbolt() => unboltProgress = 0f;
public CarPartData Data => partData;
public PartState State => currentState;
public bool HasAnimator => partAnimator != null;
public int TotalBoltsCount => wheelBolts != null ? wheelBolts.Length : 0;
public int TightenedBoltsCount
{
get
{
if (wheelBolts == null || wheelBolts.Length == 0) return 0;
int count = 0;
foreach (var b in wheelBolts)
if (b != null && b.IsTightened) count++;
return count;
}
}
private void Awake()
{
partCollider = GetComponent<Collider>();
partAnimator = GetComponent<CarPartAnimator>();
wheelBolts = GetComponentsInChildren<WheelBolt>(true);
originalParent = transform.parent;
originalLocalPos = transform.localPosition;
originalLocalRot = transform.localRotation;
originalLocalScale = transform.localScale;
VehicleInteraction car = GetComponentInParent<VehicleInteraction>();
if (car != null)
{
foreach (WheelCollider wc in car.GetComponentsInChildren<WheelCollider>(true))
{
if (wc.name == gameObject.name)
{
linkedWheelCollider = wc;
break;
}
}
}
// ВАЖНО: Если это колесо, на машине его MeshCollider ДОЛЖЕН быть триггером!
// Иначе он трется об асфальт и крылья машины, мешая WheelCollider'у ехать!
if (linkedWheelCollider != null && partCollider != null)
{
if (partCollider is MeshCollider mc) mc.convex = true;
partCollider.isTrigger = true;
}
}
private void LateUpdate()
{
if (currentState == PartState.InHand && currentHoldPoint != null)
{
transform.localPosition = targetInHandLocalPos;
transform.localRotation = targetInHandLocalRot;
}
}
public string GetPrompt()
{
if (partData == null) return "Деталь (E)";
if (currentState == PartState.Installed)
{
if (wheelBolts != null && wheelBolts.Length > 0)
{
if (!CarJack.IsWheelLifted(transform))
return "Колесо под нагрузкой! Поднимите авто домкратом";
if (TightenedBoltsCount > 0)
return $"Сначала открутите болты ({TightenedBoltsCount}/{wheelBolts.Length})";
return $"[E] Снять {partData.partName}";
}
if (unboltProgress > 0f)
return $"Откручивание болтов ({partData.partName})... {Mathf.RoundToInt(UnboltProgress01 * 100f)}%";
if (partAnimator != null)
{
string action = partAnimator.IsOpen ? "Закрыть" : "Открыть";
return $"[E] {action} {partData.partName} | [Удерж. R] Снять";
}
return $"[Удерж. E] Снять {partData.partName}";
}
if (currentState == PartState.Dropped)
return $"[E] Взять {partData.partName}";
return string.Empty;
}
public void Interact(GameObject interactor)
{
if (currentState == PartState.Installed)
{
if (partAnimator != null)
partAnimator.TogglePart();
else if (wheelBolts != null && wheelBolts.Length > 0 && TightenedBoltsCount == 0 && CarJack.IsWheelLifted(transform))
TakeToHands(interactor);
}
else if (currentState == PartState.Dropped)
{
TakeToHands(interactor);
}
}
public void SecondaryInteract(GameObject interactor) { }
public void ProcessUnbolting(GameObject interactor, float deltaTime)
{
if (currentState != PartState.Installed) return;
if (wheelBolts != null && wheelBolts.Length > 0)
{
if (!CarJack.IsWheelLifted(transform) || TightenedBoltsCount > 0) return;
TakeToHands(interactor);
return;
}
PlayerToolManager toolMgr = interactor.GetComponentInChildren<PlayerToolManager>();
if (toolMgr != null && toolMgr.currentTool != ToolType.Hands) return;
unboltProgress += deltaTime;
if (unboltProgress >= unboltDuration)
{
unboltProgress = 0f;
TakeToHands(interactor);
}
}
private void TakeToHands(GameObject interactor)
{
PlayerHands hands = interactor.GetComponentInChildren<PlayerHands>() ?? interactor.GetComponentInParent<PlayerHands>();
if (hands == null || hands.IsHolding) return;
if (currentState == PartState.Installed)
{
if (partAnimator != null) partAnimator.ResetToClosed();
CreateMountZone();
}
hands.PickUp(this);
}
public void OnPickedUp(Transform holdPoint)
{
currentState = PartState.InHand;
currentHoldPoint = holdPoint;
unboltProgress = 0f;
if (rb != null) Destroy(rb);
if (partCollider != null) partCollider.enabled = false;
if (linkedWheelCollider != null)
linkedWheelCollider.enabled = false;
transform.SetParent(holdPoint);
transform.localScale = originalLocalScale;
transform.localRotation = Quaternion.Euler(inHandRotationOffset);
transform.localPosition = Vector3.zero;
Renderer meshRenderer = GetComponentInChildren<Renderer>();
if (meshRenderer != null)
{
Vector3 visualCenterWorld = meshRenderer.bounds.center;
Vector3 offsetToCenter = holdPoint.position - visualCenterWorld;
transform.position += offsetToCenter;
transform.localPosition += inHandPositionOffset;
}
targetInHandLocalPos = transform.localPosition;
targetInHandLocalRot = transform.localRotation;
}
public void OnDropped(Vector3 throwForce)
{
currentState = PartState.Dropped;
unboltProgress = 0f;
if (currentHoldPoint != null)
transform.position = currentHoldPoint.position + currentHoldPoint.forward * 0.45f;
currentHoldPoint = null;
transform.SetParent(null);
transform.localScale = originalLocalScale;
if (partCollider != null)
{
if (partCollider is MeshCollider meshCol) meshCol.convex = true;
partCollider.isTrigger = false; // На земле деталь твердая
partCollider.enabled = 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;
currentHoldPoint = null;
unboltProgress = 0f;
if (rb != null) Destroy(rb);
transform.SetParent(originalParent);
transform.localPosition = originalLocalPos;
transform.localRotation = originalLocalRot;
transform.localScale = originalLocalScale;
if (partCollider != null)
{
partCollider.enabled = true;
// Установленное колесо делаем триггером, чтобы оно не мешало физике езды!
if (linkedWheelCollider != null)
partCollider.isTrigger = true;
}
if (linkedWheelCollider != null)
{
linkedWheelCollider.enabled = true;
linkedWheelCollider.motorTorque = 0f;
linkedWheelCollider.brakeTorque = 0f;
}
}
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);
}
}