175 lines
5.8 KiB
C#
175 lines
5.8 KiB
C#
using TMPro;
|
||
using UnityEngine;
|
||
|
||
// Порядок важен: он совпадает с порядком секторов в ToolRadialMenu (индекс = номер сектора)
|
||
public enum ToolType
|
||
{
|
||
Hands, RustCleaner, Putty, Sander, SprayCan, Wrench
|
||
|
||
}
|
||
|
||
public class PlayerToolManager : MonoBehaviour
|
||
{
|
||
[Header("Инструмент")]
|
||
public ToolType currentTool = ToolType.Hands;
|
||
|
||
[Header("Луч инструмента")]
|
||
[SerializeField] private float toolRange = 2.5f;
|
||
[SerializeField] private LayerMask interactableLayer;
|
||
|
||
[Header("Время полной обработки детали, сек")]
|
||
[SerializeField] private float cleanTime = 5f;
|
||
[SerializeField] private float puttyTime = 3f;
|
||
[SerializeField] private float sandTime = 4f;
|
||
[SerializeField] private float paintTime = 3f;
|
||
|
||
[Header("Перекраска целой детали")]
|
||
[SerializeField] private Color sprayPaintColor = new Color(0.1f, 0.4f, 0.8f);
|
||
|
||
[Header("Подсказка о состоянии детали (необязательно)")]
|
||
[Tooltip("Если не задан - текст рисуется простым OnGUI по центру экрана")]
|
||
[SerializeField] private TextMeshProUGUI statusText;
|
||
|
||
private Camera playerCam;
|
||
private string status = "";
|
||
private GUIStyle guiStyle;
|
||
|
||
private void Awake()
|
||
{
|
||
playerCam = GetComponentInChildren<Camera>();
|
||
if (playerCam == null) playerCam = Camera.main;
|
||
}
|
||
|
||
private void Update()
|
||
{
|
||
if (currentTool == ToolType.Hands || currentTool == ToolType.Wrench || Input.GetKey(KeyCode.Tab))
|
||
{
|
||
SetStatus("");
|
||
return;
|
||
}
|
||
|
||
CarPartVisuals visuals = FindTarget();
|
||
if (visuals == null)
|
||
{
|
||
SetStatus("");
|
||
return;
|
||
}
|
||
|
||
string text = $"{StageText(visuals.Stage)}";
|
||
if (visuals.Stage != RepairStage.Healthy && visuals.Stage != RepairStage.Repaired)
|
||
text += $" {Mathf.RoundToInt(visuals.StageProgress * 100f)}%";
|
||
|
||
if (Input.GetMouseButton(0))
|
||
{
|
||
if (!UseTool(visuals)) text = HintFor(visuals.Stage);
|
||
}
|
||
|
||
SetStatus(text);
|
||
}
|
||
|
||
private CarPartVisuals FindTarget()
|
||
{
|
||
if (playerCam == null) return null;
|
||
|
||
Ray ray = new Ray(playerCam.transform.position, playerCam.transform.forward);
|
||
|
||
// Ignore: зоны монтажа - это триггеры на том же слое, луч не должен в них упираться
|
||
if (!Physics.Raycast(ray, out RaycastHit hit, toolRange, interactableLayer, QueryTriggerInteraction.Ignore))
|
||
return null;
|
||
|
||
return hit.collider.GetComponentInParent<CarPartVisuals>();
|
||
}
|
||
|
||
private bool UseTool(CarPartVisuals visuals)
|
||
{
|
||
float dt = Time.deltaTime;
|
||
|
||
switch (currentTool)
|
||
{
|
||
case ToolType.RustCleaner:
|
||
// TODO: частицы искр / щётки и звук
|
||
return visuals.CleanRust(dt / cleanTime);
|
||
|
||
case ToolType.Putty:
|
||
return visuals.ApplyPutty(dt / puttyTime);
|
||
|
||
case ToolType.Sander:
|
||
return visuals.Sand(dt / sandTime);
|
||
|
||
case ToolType.SprayCan:
|
||
// Ремонтная покраска идёт цветом детали, чтобы заплатка слилась с кузовом.
|
||
// Целую деталь баллончик перекрашивает в выбранный цвет.
|
||
if (visuals.Stage == RepairStage.Sanded) return visuals.PaintRepair(dt / paintTime);
|
||
return visuals.Recolor(sprayPaintColor);
|
||
|
||
default:
|
||
return false;
|
||
}
|
||
}
|
||
|
||
public void SelectTool(ToolType newTool)
|
||
{
|
||
currentTool = newTool;
|
||
}
|
||
|
||
public void SetSprayColor(Color color)
|
||
{
|
||
sprayPaintColor = color;
|
||
}
|
||
|
||
// ---------- Тексты ----------
|
||
|
||
private static string StageText(RepairStage stage)
|
||
{
|
||
switch (stage)
|
||
{
|
||
case RepairStage.Healthy: return "Деталь целая";
|
||
case RepairStage.Rusted: return "Ржавчина";
|
||
case RepairStage.Cleaned: return "Зачищено, нужна шпаклёвка";
|
||
case RepairStage.Puttied: return "Зашпаклёвано, нужна шлифовка";
|
||
case RepairStage.Sanded: return "Отшлифовано, нужна покраска";
|
||
default: return "Отремонтировано";
|
||
}
|
||
}
|
||
|
||
private static string HintFor(RepairStage stage)
|
||
{
|
||
switch (stage)
|
||
{
|
||
case RepairStage.Rusted: return "Сначала счистите ржавчину (зачистка)";
|
||
case RepairStage.Cleaned: return "Нужна шпаклёвка (шпатель)";
|
||
case RepairStage.Puttied: return "Нужна шлифовка";
|
||
case RepairStage.Sanded: return "Нужна покраска (баллончик)";
|
||
default: return "Этот инструмент здесь не нужен";
|
||
}
|
||
}
|
||
|
||
// ---------- Вывод ----------
|
||
|
||
private void SetStatus(string value)
|
||
{
|
||
status = value;
|
||
|
||
if (statusText != null)
|
||
{
|
||
statusText.text = value;
|
||
statusText.gameObject.SetActive(!string.IsNullOrEmpty(value));
|
||
}
|
||
}
|
||
|
||
private void OnGUI()
|
||
{
|
||
if (statusText != null || string.IsNullOrEmpty(status)) return;
|
||
|
||
if (guiStyle == null)
|
||
{
|
||
guiStyle = new GUIStyle(GUI.skin.label)
|
||
{
|
||
alignment = TextAnchor.MiddleCenter,
|
||
fontSize = 22
|
||
};
|
||
}
|
||
|
||
GUI.Label(new Rect(Screen.width * 0.5f - 300f, Screen.height * 0.62f, 600f, 40f), status, guiStyle);
|
||
}
|
||
} |