166 lines
5.7 KiB
C#
166 lines
5.7 KiB
C#
using UnityEngine;
|
||
|
||
public class CarPartMountZone : MonoBehaviour, IInteractable
|
||
{
|
||
private CarPart targetPart;
|
||
private Collider zoneCollider;
|
||
private MeshRenderer ghostRenderer;
|
||
private PlayerHands cachedHands;
|
||
|
||
private float mountDuration = 1.2f;
|
||
private float currentMountProgress = 0f;
|
||
private bool hasSeparateBolts = false;
|
||
|
||
public void Initialize(CarPart part)
|
||
{
|
||
targetPart = part;
|
||
gameObject.layer = part.gameObject.layer;
|
||
|
||
cachedHands = FindAnyObjectByType<PlayerHands>();
|
||
hasSeparateBolts = part.GetComponentsInChildren<WheelBolt>(true).Length > 0;
|
||
|
||
if (part.Data != null && part.Data.boltDuration > 0f)
|
||
mountDuration = part.Data.boltDuration;
|
||
|
||
MeshFilter sourceFilter = part.GetComponentInChildren<MeshFilter>();
|
||
|
||
// Для колеса создаем удобную широкую сферу вокруг ступицы, чтобы луч всегда попадал с первого раза
|
||
if (hasSeparateBolts)
|
||
{
|
||
SphereCollider sphere = gameObject.AddComponent<SphereCollider>();
|
||
if (sourceFilter != null && sourceFilter.sharedMesh != null)
|
||
sphere.center = sourceFilter.sharedMesh.bounds.center;
|
||
sphere.radius = 0.48f;
|
||
sphere.isTrigger = true;
|
||
zoneCollider = sphere;
|
||
}
|
||
else
|
||
{
|
||
Collider sourceCollider = part.GetComponent<Collider>();
|
||
if (sourceCollider is BoxCollider sourceBox)
|
||
{
|
||
BoxCollider box = gameObject.AddComponent<BoxCollider>();
|
||
box.center = sourceBox.center;
|
||
box.size = sourceBox.size;
|
||
box.isTrigger = true;
|
||
zoneCollider = box;
|
||
}
|
||
else if (sourceCollider is MeshCollider sourceMesh)
|
||
{
|
||
MeshCollider meshCol = gameObject.AddComponent<MeshCollider>();
|
||
meshCol.sharedMesh = sourceMesh.sharedMesh;
|
||
meshCol.convex = true;
|
||
meshCol.isTrigger = true;
|
||
zoneCollider = meshCol;
|
||
}
|
||
else
|
||
{
|
||
SphereCollider sphere = gameObject.AddComponent<SphereCollider>();
|
||
sphere.radius = 0.6f;
|
||
sphere.isTrigger = true;
|
||
zoneCollider = sphere;
|
||
}
|
||
}
|
||
|
||
if (sourceFilter != null && sourceFilter.sharedMesh != null)
|
||
{
|
||
MeshFilter mf = gameObject.AddComponent<MeshFilter>();
|
||
mf.sharedMesh = sourceFilter.sharedMesh;
|
||
|
||
ghostRenderer = gameObject.AddComponent<MeshRenderer>();
|
||
ghostRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
|
||
|
||
Material sharedGhostMat = part.Data != null ? part.Data.ghostMaterial : null;
|
||
if (sharedGhostMat != null)
|
||
{
|
||
ghostRenderer.sharedMaterial = sharedGhostMat;
|
||
}
|
||
else
|
||
{
|
||
Material fallbackMat = new Material(Shader.Find("Universal Render Pipeline/Unlit"));
|
||
fallbackMat.color = new Color(0.2f, 0.9f, 0.3f, 0.4f);
|
||
ghostRenderer.material = fallbackMat;
|
||
}
|
||
}
|
||
|
||
UpdateZoneVisibility();
|
||
}
|
||
|
||
private void Update()
|
||
{
|
||
UpdateZoneVisibility();
|
||
}
|
||
|
||
private void UpdateZoneVisibility()
|
||
{
|
||
if (cachedHands == null)
|
||
cachedHands = FindAnyObjectByType<PlayerHands>();
|
||
|
||
bool isHoldingTarget = cachedHands != null && cachedHands.IsHolding && cachedHands.CurrentPart == targetPart;
|
||
|
||
if (zoneCollider != null && zoneCollider.enabled != isHoldingTarget)
|
||
zoneCollider.enabled = isHoldingTarget;
|
||
|
||
if (ghostRenderer != null && ghostRenderer.enabled != isHoldingTarget)
|
||
ghostRenderer.enabled = isHoldingTarget;
|
||
|
||
if (!isHoldingTarget)
|
||
currentMountProgress = 0f;
|
||
}
|
||
|
||
public string GetPrompt()
|
||
{
|
||
if (targetPart == null) return string.Empty;
|
||
if (cachedHands == null || !cachedHands.IsHolding || cachedHands.CurrentPart != targetPart)
|
||
return string.Empty;
|
||
|
||
string partTitle = targetPart.Data != null ? targetPart.Data.partName : "Деталь";
|
||
|
||
// Колесо надевается на ступицу сразу при нажатии E или ЛКМ
|
||
if (hasSeparateBolts)
|
||
{
|
||
if (Input.GetKeyDown(KeyCode.E) || Input.GetMouseButtonDown(0))
|
||
{
|
||
CompleteInstall();
|
||
return string.Empty;
|
||
}
|
||
return $"[E / ЛКМ] Надеть {partTitle} на ступицу";
|
||
}
|
||
|
||
if (Input.GetKey(KeyCode.E))
|
||
{
|
||
currentMountProgress += Time.deltaTime;
|
||
if (currentMountProgress >= mountDuration)
|
||
{
|
||
CompleteInstall();
|
||
return string.Empty;
|
||
}
|
||
|
||
int percent = Mathf.RoundToInt(Mathf.Clamp01(currentMountProgress / mountDuration) * 100f);
|
||
return $"Закручиваем болты: {partTitle}... {percent}%";
|
||
}
|
||
else
|
||
{
|
||
currentMountProgress = 0f;
|
||
}
|
||
|
||
return $"[Удерживать E] Установить {partTitle}";
|
||
}
|
||
|
||
public void Interact(GameObject interactor)
|
||
{
|
||
if (hasSeparateBolts && cachedHands != null && cachedHands.IsHolding && cachedHands.CurrentPart == targetPart)
|
||
{
|
||
CompleteInstall();
|
||
}
|
||
}
|
||
|
||
private void CompleteInstall()
|
||
{
|
||
if (cachedHands == null || targetPart == null) return;
|
||
|
||
cachedHands.ClearHandAfterInstall();
|
||
targetPart.Install();
|
||
Destroy(gameObject);
|
||
}
|
||
} |