189 lines
5.9 KiB
C#
189 lines
5.9 KiB
C#
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
public enum RepairStage
|
|
{
|
|
Healthy, Rusted, Cleaned, Puttied, Sanded, Repaired
|
|
}
|
|
|
|
[DisallowMultipleComponent]
|
|
public class CarPartVisuals : MonoBehaviour
|
|
{
|
|
private static readonly int BaseColorProp = Shader.PropertyToID("_BaseColor");
|
|
private static readonly int RustAmountProp = Shader.PropertyToID("_RustAmount");
|
|
private static readonly int RustInitialProp = Shader.PropertyToID("_RustInitial");
|
|
private static readonly int PuttyProp = Shader.PropertyToID("_PuttyProgress");
|
|
private static readonly int SandProp = Shader.PropertyToID("_SandProgress");
|
|
private static readonly int PaintProp = Shader.PropertyToID("_PaintProgress");
|
|
|
|
private const float DoneThreshold = 0.98f;
|
|
private const float RustCleanThreshold = 0.02f;
|
|
|
|
[Header("Состояние детали")]
|
|
[Range(0f, 1f)] [SerializeField] private float rustInitial;
|
|
[Range(0f, 1f)] [SerializeField] private float rustCurrent;
|
|
[Range(0f, 1f)] [SerializeField] private float putty;
|
|
[Range(0f, 1f)] [SerializeField] private float sanding;
|
|
[Range(0f, 1f)] [SerializeField] private float paint;
|
|
[SerializeField] private Color paintColor = Color.white;
|
|
|
|
private struct Slot
|
|
{
|
|
public Renderer renderer;
|
|
public int materialIndex;
|
|
}
|
|
|
|
private readonly List<Slot> slots = new List<Slot>();
|
|
private MaterialPropertyBlock block;
|
|
private bool initialized;
|
|
private bool colorInitialized;
|
|
|
|
public float CurrentRust => rustCurrent;
|
|
public float InitialRust => rustInitial;
|
|
public Color CurrentColor => paintColor;
|
|
|
|
public RepairStage Stage
|
|
{
|
|
get
|
|
{
|
|
if (rustInitial <= 0.001f) return RepairStage.Healthy;
|
|
if (rustCurrent > RustCleanThreshold) return RepairStage.Rusted;
|
|
if (putty < DoneThreshold) return RepairStage.Cleaned;
|
|
if (sanding < DoneThreshold) return RepairStage.Puttied;
|
|
if (paint < DoneThreshold) return RepairStage.Sanded;
|
|
return RepairStage.Repaired;
|
|
}
|
|
}
|
|
|
|
public float StageProgress
|
|
{
|
|
get
|
|
{
|
|
switch (Stage)
|
|
{
|
|
case RepairStage.Rusted: return 1f - rustCurrent / Mathf.Max(rustInitial, 0.001f);
|
|
case RepairStage.Cleaned: return putty;
|
|
case RepairStage.Puttied: return sanding;
|
|
case RepairStage.Sanded: return paint;
|
|
default: return 1f;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void EnsureInit()
|
|
{
|
|
if (initialized) return;
|
|
initialized = true;
|
|
block = new MaterialPropertyBlock();
|
|
|
|
CarPart owner = GetComponent<CarPart>();
|
|
|
|
foreach (Renderer r in GetComponentsInChildren<Renderer>(true))
|
|
{
|
|
if (owner != null && r.GetComponentInParent<CarPart>(true) != owner) continue;
|
|
|
|
Material[] mats = r.sharedMaterials;
|
|
for (int i = 0; i < mats.Length; i++)
|
|
{
|
|
if (mats[i] != null && mats[i].HasProperty(RustAmountProp))
|
|
{
|
|
// Автоматически запоминаем родной цвет машины из материала (например, синий!)
|
|
if (!colorInitialized && mats[i].HasProperty(BaseColorProp))
|
|
{
|
|
paintColor = mats[i].GetColor(BaseColorProp);
|
|
colorInitialized = true;
|
|
}
|
|
slots.Add(new Slot { renderer = r, materialIndex = i });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnValidate()
|
|
{
|
|
if (Application.isPlaying && initialized) Apply();
|
|
}
|
|
|
|
public void SetDamage(float amount)
|
|
{
|
|
EnsureInit();
|
|
amount = Mathf.Clamp01(amount);
|
|
if (amount <= 0.001f) amount = 0f;
|
|
|
|
rustInitial = amount;
|
|
rustCurrent = amount;
|
|
putty = 0f;
|
|
sanding = 0f;
|
|
paint = 0f;
|
|
Apply();
|
|
}
|
|
|
|
public void SetPaintColor(Color newColor)
|
|
{
|
|
EnsureInit();
|
|
paintColor = newColor;
|
|
colorInitialized = true;
|
|
Apply();
|
|
}
|
|
|
|
public bool CleanRust(float amount01)
|
|
{
|
|
if (Stage != RepairStage.Rusted) return false;
|
|
rustCurrent -= rustInitial * amount01;
|
|
if (rustCurrent <= RustCleanThreshold) rustCurrent = 0f;
|
|
Apply();
|
|
return true;
|
|
}
|
|
|
|
public bool ApplyPutty(float amount01)
|
|
{
|
|
if (Stage != RepairStage.Cleaned) return false;
|
|
putty = Mathf.Min(1f, putty + amount01);
|
|
if (putty >= DoneThreshold) putty = 1f;
|
|
Apply();
|
|
return true;
|
|
}
|
|
|
|
public bool Sand(float amount01)
|
|
{
|
|
if (Stage != RepairStage.Puttied) return false;
|
|
sanding = Mathf.Min(1f, sanding + amount01);
|
|
if (sanding >= DoneThreshold) sanding = 1f;
|
|
Apply();
|
|
return true;
|
|
}
|
|
|
|
public bool PaintRepair(float amount01)
|
|
{
|
|
if (Stage != RepairStage.Sanded) return false;
|
|
paint = Mathf.Min(1f, paint + amount01);
|
|
if (paint >= DoneThreshold) paint = 1f;
|
|
Apply();
|
|
return true;
|
|
}
|
|
|
|
public bool Recolor(Color newColor)
|
|
{
|
|
RepairStage s = Stage;
|
|
if (s != RepairStage.Healthy && s != RepairStage.Repaired) return false;
|
|
SetPaintColor(newColor);
|
|
return true;
|
|
}
|
|
|
|
private void Apply()
|
|
{
|
|
EnsureInit();
|
|
foreach (Slot s in slots)
|
|
{
|
|
if (s.renderer == null) continue;
|
|
s.renderer.GetPropertyBlock(block, s.materialIndex);
|
|
block.SetColor(BaseColorProp, paintColor);
|
|
block.SetFloat(RustInitialProp, rustInitial);
|
|
block.SetFloat(RustAmountProp, rustCurrent);
|
|
block.SetFloat(PuttyProp, putty);
|
|
block.SetFloat(SandProp, sanding);
|
|
block.SetFloat(PaintProp, paint);
|
|
s.renderer.SetPropertyBlock(block, s.materialIndex);
|
|
}
|
|
}
|
|
} |