206 lines
7.6 KiB
C#
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) { }
|
|
} |