Perekyp/Assets/Scripts/Car/Visuals/CarConditionGenerator.cs

181 lines
7.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Collections.Generic;
using UnityEngine;
public struct CarDefectsSummary
{
public int rustedPartsCount;
public int missingBodyPartsCount;
public int flatTiresCount;
public int missingWheelsCount;
public List<string> missingPartNames;
public float totalPricePenalty;
}
public class CarConditionGenerator : MonoBehaviour
{
[Header("Настройки ржавчины")]
[Range(0f, 1f)] [SerializeField] private float rustProbability = 0.65f;
[SerializeField] private float minRustAmount = 0.25f;
[SerializeField] private float maxRustAmount = 0.80f;
[Header("Шанс отсутствия навесных деталей (бамперы, фары, крылья)")]
[Range(0f, 0.5f)] [SerializeField] private float missingBodyPartChance = 0.15f;
[SerializeField] private int maxMissingBodyParts = 3;
[Header("Проблемы с колесами")]
[Range(0f, 1f)] [SerializeField] private float flatTireChance = 0.25f;
[Range(0f, 1f)] [SerializeField] private float missingWheelChance = 0.12f;
[Header("Цвет кузова")]
[SerializeField] private bool overrideMaterialColor = false;
[SerializeField] private Color baseCarColor = Color.blue;
private bool configuredExternally = false;
private void Start()
{
// Если машина уже настроена через CarMarketManager (по Seed) — не перезаписываем её!
if (!configuredExternally)
{
GenerateCondition();
}
}
[ContextMenu("Сгенерировать случайное состояние")]
public void GenerateCondition()
{
int randomSeed = Random.Range(1, 999999);
Color col = overrideMaterialColor ? baseCarColor : GetCurrentBodyColor();
ApplyConditionBySeed(randomSeed, col, false, out _);
}
public Color GetCurrentBodyColor()
{
int rustProp = Shader.PropertyToID("_RustAmount");
int colorProp = Shader.PropertyToID("_BaseColor");
foreach (Renderer r in GetComponentsInChildren<Renderer>(true))
{
foreach (Material m in r.sharedMaterials)
{
if (m != null && m.HasProperty(rustProp) && m.HasProperty(colorProp))
return m.GetColor(colorProp);
}
}
return baseCarColor;
}
/// <summary>
/// Генерирует 100% одинаковое состояние машины для одного и того же seed (и в фотобоксе, и на карте).
/// </summary>
public void ApplyConditionBySeed(int seed, Color carColor, bool isPhotoStudio, out CarDefectsSummary summary)
{
configuredExternally = true;
Random.State oldState = Random.state;
Random.InitState(seed);
summary = new CarDefectsSummary
{
missingPartNames = new List<string>()
};
CarPart[] allParts = GetComponentsInChildren<CarPart>(true);
// 1. Обрабатываем кузовные и навесные детали (кроме колес)
foreach (CarPart part in allParts)
{
// Пропускаем колеса (у них свой цикл ниже)
if (part.GetComponent<CarWheelCondition>() != null || part.TotalBoltsCount > 0)
continue;
CarPartVisuals visuals = part.GetComponent<CarPartVisuals>();
if (visuals == null) visuals = part.gameObject.AddComponent<CarPartVisuals>();
visuals.SetPaintColor(carColor);
float partPrice = part.Data != null ? part.Data.basePrice : 150f;
string partTitle = part.Data != null ? part.Data.partName : part.name;
// Проверяем, отсутствует ли эта навесная деталь (бампер, фара, крыло, дверь, зеркало)
if (summary.missingBodyPartsCount < maxMissingBodyParts && Random.value < missingBodyPartChance)
{
summary.missingBodyPartsCount++;
summary.missingPartNames.Add(partTitle.ToLower());
summary.totalPricePenalty += partPrice * 1.4f;
part.MakeMissingAtStart(null, false);
continue;
}
// Пластик не ржавеет
if (part.Data != null && !part.Data.canRust)
{
visuals.SetDamage(0f);
continue;
}
if (Random.value < rustProbability)
{
float dmg = Random.Range(minRustAmount, maxRustAmount);
visuals.SetDamage(dmg);
summary.rustedPartsCount++;
summary.totalPricePenalty += partPrice * dmg;
}
else
{
visuals.SetDamage(0f);
}
}
// 2. Обрабатываем основной несъемный кузов (body)
int rustProp = Shader.PropertyToID("_RustAmount");
foreach (Renderer r in GetComponentsInChildren<Renderer>(true))
{
if (r.GetComponentInParent<CarPart>(true) != null) continue;
foreach (Material m in r.sharedMaterials)
{
if (m != null && m.HasProperty(rustProp))
{
CarPartVisuals bodyVis = r.GetComponent<CarPartVisuals>();
if (bodyVis == null) bodyVis = r.gameObject.AddComponent<CarPartVisuals>();
bodyVis.SetPaintColor(carColor);
float bodyDmg = Random.value < rustProbability ? Random.Range(minRustAmount, maxRustAmount) : 0f;
bodyVis.SetDamage(bodyDmg);
if (bodyDmg > 0.05f)
{
summary.rustedPartsCount++;
summary.totalPricePenalty += 250f * bodyDmg;
}
break;
}
}
}
// 3. Обрабатываем колеса (Нормальное / Спущенное / Отсутствует)
CarWheelCondition[] wheels = GetComponentsInChildren<CarWheelCondition>(true);
foreach (CarWheelCondition wheel in wheels)
{
float roll = Random.value;
// В одном объявлении убираем максимум 1 колесо, чтобы машина не висела вся на кирпичах
if (roll < missingWheelChance && summary.missingWheelsCount < 1)
{
summary.missingWheelsCount++;
summary.totalPricePenalty += 220f;
CarPart wp = wheel.GetComponent<CarPart>();
if (wp != null) wp.MakeMissingAtStart(null, !isPhotoStudio);
}
else if (roll < missingWheelChance + flatTireChance)
{
summary.flatTiresCount++;
summary.totalPricePenalty += 100f;
wheel.ApplyState(CarWheelCondition.TireState.Flat);
}
else
{
wheel.ApplyState(CarWheelCondition.TireState.Normal);
}
}
Random.state = oldState;
}
}