94 lines
3.6 KiB
C#
94 lines
3.6 KiB
C#
using UnityEngine;
|
|
|
|
namespace Ashwild.Harvesting
|
|
{
|
|
[CreateAssetMenu(fileName = "NewScatterProfile", menuName = "Harvesting/Scatter Profile")]
|
|
public class ScatterProfile : ScriptableObject
|
|
{
|
|
[System.Serializable]
|
|
public struct Entry
|
|
{
|
|
public GameObject prefab;
|
|
[Min(0f)] public float weight;
|
|
public Vector2 scaleRange;
|
|
public bool alignToNormal;
|
|
}
|
|
|
|
[Header("Prefabs (sélection pondérée)")]
|
|
[SerializeField] private Entry[] entries;
|
|
|
|
[Header("Densité")]
|
|
[Tooltip("Nombre d'instances visées pour 100 m² lors d'un Scatter auto.")]
|
|
[SerializeField] private float density = 5f;
|
|
[Tooltip("Distance minimale entre deux instances, en mètres.")]
|
|
[SerializeField] private float minSpacing = 3f;
|
|
|
|
[Header("Contraintes de pente (degrés)")]
|
|
[SerializeField] private Vector2 slopeRange = new Vector2(0f, 35f);
|
|
|
|
[Header("Enfoncement (sink)")]
|
|
[Tooltip("Enfoncement aléatoire vers le bas, en mètres (min..max). Ex. arbres qui mordent le sol.")]
|
|
[SerializeField] private Vector2 sinkRange = Vector2.zero;
|
|
|
|
[Header("Filtre par texture du terrain")]
|
|
[Tooltip("Terrain layers autorisés (glisse les assets TerrainLayer). Vide = aucune contrainte de texture.")]
|
|
[SerializeField] private TerrainLayer[] allowedTerrainLayers;
|
|
[Tooltip("Poids minimal de la texture autorisée sous le point (0-1).")]
|
|
[SerializeField, Range(0f, 1f)] private float minTextureWeight = 0.5f;
|
|
|
|
[Header("Placement")]
|
|
[Tooltip("Couche(s) du terrain pour le raycast vers le bas.")]
|
|
[SerializeField] private LayerMask groundMask = ~0;
|
|
[Tooltip("Layer forcé sur chaque instance posée (doit être inclus dans le harvestMask du PlayerTools).")]
|
|
[Layer]
|
|
[SerializeField] private int placedLayer = 6;
|
|
|
|
public Entry[] Entries => entries;
|
|
public float Density => density;
|
|
public float MinSpacing => Mathf.Max(0.01f, minSpacing);
|
|
public Vector2 SlopeRange => slopeRange;
|
|
public Vector2 SinkRange => sinkRange;
|
|
public TerrainLayer[] AllowedTerrainLayers => allowedTerrainLayers;
|
|
public float MinTextureWeight => minTextureWeight;
|
|
public LayerMask GroundMask => groundMask;
|
|
public int PlacedLayer => placedLayer;
|
|
|
|
/// <summary>Tire une Entry au hasard selon les poids. Renvoie false si aucune entry valide.</summary>
|
|
public bool TryPickEntry(System.Random rng, out Entry result)
|
|
{
|
|
result = default;
|
|
if (entries == null || entries.Length == 0) return false;
|
|
|
|
float total = 0f;
|
|
for (int i = 0; i < entries.Length; i++)
|
|
if (entries[i].prefab != null)
|
|
total += Mathf.Max(0f, entries[i].weight);
|
|
|
|
if (total <= 0f) return false;
|
|
|
|
float pick = (float)rng.NextDouble() * total;
|
|
for (int i = 0; i < entries.Length; i++)
|
|
{
|
|
if (entries[i].prefab == null) continue;
|
|
pick -= Mathf.Max(0f, entries[i].weight);
|
|
if (pick <= 0f)
|
|
{
|
|
result = entries[i];
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Sécurité (erreurs d'arrondi) : renvoie la dernière entry valide.
|
|
for (int i = entries.Length - 1; i >= 0; i--)
|
|
{
|
|
if (entries[i].prefab != null)
|
|
{
|
|
result = entries[i];
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
}
|