Perekyp/Assets/Scripts/Car/Repair/WheelBolt.cs

206 lines
7.6 KiB
C#

using UnityEngine;
[RequireComponent(typeof(SphereCollider))]
public class WheelBolt : MonoBehaviour, IInteractable
{
[Header("Настройки вылета и скорости")]
[SerializeField] private float pullOutDistance = 0.06f;
[SerializeField] private float workDuration = 0.5f;
private CarPart parentWheel;
private MeshRenderer meshRenderer;
private SphereCollider boltCollider;
private Material originalMaterial;
private Material ghostMaterial;
private PlayerToolManager toolManager;
private Vector3 tightenedLocalPos;
private Quaternion tightenedLocalRot;
private Vector3 baseLocalScale;
private Vector3 localMeshCenter;
private Vector3 boltCenterInParent;
private Vector3 parentOutwardDir;
private float tightness = 1f;
private bool isTightened = true;
private bool isHoveredThisFrame = false;
private bool waitForRelease = false;
public bool IsTightened => isTightened;
public bool IsAvailableForAim => parentWheel == null || parentWheel.State == PartState.Installed;
public Vector3 WorldBoltCenter => transform.TransformPoint(localMeshCenter);
private void Awake()
{
parentWheel = GetComponentInParent<CarPart>();
meshRenderer = GetComponent<MeshRenderer>();
boltCollider = GetComponent<SphereCollider>();
toolManager = FindAnyObjectByType<PlayerToolManager>();
tightenedLocalPos = transform.localPosition;
tightenedLocalRot = transform.localRotation;
baseLocalScale = transform.localScale;
MeshFilter mf = GetComponent<MeshFilter>();
if (mf != null && mf.sharedMesh != null)
localMeshCenter = mf.sharedMesh.bounds.center;
boltCollider.isTrigger = true;
boltCollider.center = localMeshCenter;
boltCollider.radius = 0.045f;
boltCenterInParent = tightenedLocalPos + tightenedLocalRot * Vector3.Scale(localMeshCenter, baseLocalScale);
CalculateOutwardDirection();
if (meshRenderer != null)
originalMaterial = meshRenderer.sharedMaterial;
if (parentWheel != null && parentWheel.Data != null)
ghostMaterial = parentWheel.Data.ghostMaterial;
}
private void CalculateOutwardDirection()
{
Vector3 worldBoltPos = transform.TransformPoint(localMeshCenter);
VehicleInteraction car = GetComponentInParent<VehicleInteraction>();
Transform carRoot = car != null ? car.transform : transform.root;
Vector3 fromCarToBolt = worldBoltPos - carRoot.position;
float sideSign = Mathf.Sign(Vector3.Dot(fromCarToBolt, carRoot.right));
if (sideSign == 0f) sideSign = 1f;
Vector3 worldOutDir = carRoot.right * sideSign;
parentOutwardDir = transform.parent != null
? transform.parent.InverseTransformDirection(worldOutDir).normalized
: Vector3.right * sideSign;
}
private void LateUpdate()
{
if (parentWheel != null && parentWheel.State != PartState.Installed)
{
if (meshRenderer != null && meshRenderer.enabled) meshRenderer.enabled = false;
if (boltCollider != null && boltCollider.enabled) boltCollider.enabled = false;
isHoveredThisFrame = false;
return;
}
if (boltCollider != null && !boltCollider.enabled)
boltCollider.enabled = true;
if (toolManager == null)
toolManager = FindAnyObjectByType<PlayerToolManager>();
bool hasWrench = toolManager != null && toolManager.currentTool == ToolType.Wrench;
bool isAnimating = tightness > 0.01f && tightness < 0.99f;
// Визуально увеличиваем КОНКРЕТНЫЙ выбранный болт под прицелом, чтобы игрок видел, куда навелся
float scaleMult = (isHoveredThisFrame && hasWrench) ? 1.25f : 1.0f;
UpdateBoltTransform(scaleMult);
if (meshRenderer != null)
{
if (isTightened || isAnimating)
{
meshRenderer.enabled = true;
// Подсвечиваем только тот болт, на который сейчас наведен прицел!
if (isHoveredThisFrame && hasWrench && ghostMaterial != null)
meshRenderer.sharedMaterial = ghostMaterial;
else if (originalMaterial != null)
meshRenderer.sharedMaterial = originalMaterial;
}
else
{
// Выкрученный болт: показываем силуэт отверстия при взятом ключе
meshRenderer.enabled = hasWrench && isHoveredThisFrame;
if (meshRenderer.enabled && ghostMaterial != null)
meshRenderer.sharedMaterial = ghostMaterial;
}
}
isHoveredThisFrame = false;
}
public string GetPrompt()
{
isHoveredThisFrame = true;
if (isTightened && parentWheel != null && !CarJack.IsWheelLifted(parentWheel.transform))
{
return "Колесо под нагрузкой! Сначала поднимите эту сторону домкратом";
}
bool hasWrench = toolManager != null && toolManager.currentTool == ToolType.Wrench;
if (!hasWrench)
{
waitForRelease = false;
return isTightened
? "Колесный болт (Возьмите баллонный ключ [Tab])"
: "Отверстие под болт (Возьмите ключ [Tab])";
}
bool isHoldingKey = Input.GetMouseButton(0) || Input.GetKey(KeyCode.E);
if (!isHoldingKey)
{
waitForRelease = false;
tightness = isTightened ? 1f : 0f;
}
else if (!waitForRelease)
{
ProcessWrench(Time.deltaTime);
}
int percent = Mathf.RoundToInt((isTightened ? (1f - tightness) : tightness) * 100f);
if (isTightened)
return (percent > 0 && !waitForRelease) ? $"Откручиваем болт... {percent}%" : "[Удерж. ЛКМ / E] Открутить болт";
else
return (percent > 0 && !waitForRelease) ? $"Закручиваем болт... {percent}%" : "[Удерж. ЛКМ / E] Закрутить болт";
}
private void ProcessWrench(float dt)
{
float step = dt / workDuration;
if (isTightened)
{
tightness -= step;
if (tightness <= 0f)
{
tightness = 0f;
isTightened = false;
waitForRelease = true;
}
}
else
{
tightness += step;
if (tightness >= 1f)
{
tightness = 1f;
isTightened = true;
waitForRelease = true;
}
}
}
private void UpdateBoltTransform(float scaleMultiplier = 1f)
{
float outFactor = 1f - Mathf.Clamp01(tightness);
Vector3 currentScale = baseLocalScale * scaleMultiplier;
Quaternion spinRotation = Quaternion.AngleAxis(outFactor * 720f, parentOutwardDir);
Quaternion newLocalRot = spinRotation * tightenedLocalRot;
Vector3 rotatedCenterOffset = newLocalRot * Vector3.Scale(localMeshCenter, currentScale);
Vector3 pullOutOffset = parentOutwardDir * (pullOutDistance * outFactor);
transform.localScale = currentScale;
transform.localRotation = newLocalRot;
transform.localPosition = boltCenterInParent - rotatedCenterOffset + pullOutOffset;
}
public void Interact(GameObject interactor) { }
}