178 lines
7.5 KiB
C#
178 lines
7.5 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using InfinityPBR.ModularCharacterHelper;
|
|
using Sirenix.OdinInspector;
|
|
using Sirenix.Utilities;
|
|
using UnityEngine;
|
|
using VOID.Generic.Dict;
|
|
using VOID.Generic.Objects.Unit;
|
|
using VOID.Generic.Util;
|
|
using Random = UnityEngine.Random;
|
|
|
|
namespace VOID.ScriptableObjects
|
|
{
|
|
[CreateAssetMenu(menuName = "GAME DATA/Generator/Generator Jednostki")]
|
|
public class UnitGenerator : ScriptableObject
|
|
{
|
|
[Title("Unit References")]
|
|
[SerializeField] private UnitObject[] _unitPrefabs;
|
|
[SerializeField] private Material[] _skinMaterials;
|
|
[SerializeField] private Material[] _hairMaterials;
|
|
|
|
[Space(100)]
|
|
[Title("Model")]
|
|
[InfoBox("If prefab part can't be attached to unit prefab then it'll be skipped!")]
|
|
[SerializeField] private bool _generateHair;
|
|
[SerializeField, ShowIf(nameof(_generateHair)), Required] private ModularPart[] _hairPrefabs;
|
|
|
|
[Title("Colors")]
|
|
[InfoBox("If colors list is empty then randomize new one!")]
|
|
[SerializeField] private bool _generateSkinColor;
|
|
[SerializeField, ShowIf(nameof(_generateSkinColor))] private Color[] _skinColors;
|
|
[SerializeField] private bool _generateHairColor;
|
|
[SerializeField, ShowIf(nameof(_generateHairColor))] private Color[] _hairColors;
|
|
|
|
[Title("Main Attributes")]
|
|
[SerializeField] private bool _generateMainAttributes;
|
|
[SerializeField, ShowIf(nameof(_generateMainAttributes)), MinMaxSlider(1, 50, true)] private Vector2Int _strength = new(4, 7);
|
|
[SerializeField, ShowIf(nameof(_generateMainAttributes)), MinMaxSlider(1, 50, true)] private Vector2Int _dexterity = new(4, 7);
|
|
[SerializeField, ShowIf(nameof(_generateMainAttributes)), MinMaxSlider(1, 50, true)] private Vector2Int _intelligence = new(4, 7);
|
|
[SerializeField, ShowIf(nameof(_generateMainAttributes)), MinMaxSlider(1, 50, true)] private Vector2Int _constitution = new(4, 7);
|
|
[SerializeField, ShowIf(nameof(_generateMainAttributes)), MinMaxSlider(1, 50, true)] private Vector2Int _speed = new(4, 7);
|
|
[SerializeField, ShowIf(nameof(_generateMainAttributes)), MinMaxSlider(1, 50, true)] private Vector2Int _perception = new(4, 7);
|
|
|
|
private void OnValidate()
|
|
{
|
|
if (!_generateHair)
|
|
{
|
|
_hairPrefabs = null;
|
|
}
|
|
|
|
if (!_generateSkinColor)
|
|
{
|
|
_skinColors = null;
|
|
}
|
|
|
|
if (!_generateHairColor)
|
|
{
|
|
_hairColors = null;
|
|
}
|
|
|
|
if (!_generateMainAttributes)
|
|
{
|
|
_strength = new Vector2Int(4, 7);
|
|
_dexterity = new Vector2Int(4, 7);
|
|
_intelligence = new Vector2Int(4, 7);
|
|
_constitution = new Vector2Int(4, 7);
|
|
_speed = new Vector2Int(4, 7);
|
|
_perception = new Vector2Int(4, 7);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Generate new <see cref="UnitObject"/>:<br/>
|
|
/// 1. Selects random <see cref="UnitObject"/> prefab<br/>
|
|
/// 2. Wait for full initialization of <see cref="UnitObject"/><br/>
|
|
/// 3. Updates <see cref="UnitObject"/> with random things defined via inspector
|
|
/// </summary>
|
|
/// <returns>Instantiated random <see cref="UnitObject"/></returns>
|
|
public UnitObject Generate(int? seed = null)
|
|
{
|
|
if (seed.HasValue) RandomUtil.InitState(seed.Value);
|
|
var unit = Instantiate(RandomUtil.RandomElement(_unitPrefabs));
|
|
Randomize(unit);
|
|
return unit;
|
|
}
|
|
|
|
private void Randomize(UnitObject unit)
|
|
{
|
|
RandomizeHair(unit);
|
|
RandomizeSkinColor(unit);
|
|
RandomizeHairColor(unit);
|
|
RandomizeMainAttributes(unit);
|
|
}
|
|
|
|
private void RandomizeHair(UnitObject unit)
|
|
{
|
|
if (!_generateHair) return;
|
|
|
|
var modularCharacter = unit.unitState.modularCharacter;
|
|
var validHairPrefabs = _hairPrefabs.Where(hair => hair.avatar == modularCharacter.avatar).ToList();
|
|
|
|
if (validHairPrefabs.IsNullOrEmpty()) return;
|
|
|
|
modularCharacter.AttachPart(Instantiate(RandomUtil.RandomElement(validHairPrefabs), unit.transform));
|
|
}
|
|
|
|
private void RandomizeSkinColor(UnitObject unit)
|
|
{
|
|
if (!_generateSkinColor) return;
|
|
if (_skinMaterials.IsNullOrEmpty()) return;
|
|
|
|
ApplyTintToMaterials(unit, _skinColors, _skinMaterials);
|
|
}
|
|
|
|
private void RandomizeHairColor(UnitObject unit)
|
|
{
|
|
if (!_generateHairColor) return;
|
|
if (_hairMaterials.IsNullOrEmpty()) return;
|
|
|
|
ApplyTintToMaterials(unit, _hairColors, _hairMaterials);
|
|
}
|
|
|
|
private void ApplyTintToMaterials(UnitObject unit, Color[] colors, Material[] forMaterials)
|
|
{
|
|
// Find renderers with this material to add tint color
|
|
var foundRenderers = unit.GetComponentsInChildren<Renderer>()
|
|
.Where(renderer => forMaterials.Any(material => renderer.sharedMaterials.Contains(material)))
|
|
.ToList();
|
|
|
|
if (foundRenderers.IsNullOrEmpty()) return;
|
|
|
|
// Get random defined color if present OR randomize new one
|
|
var color = colors.IsNullOrEmpty()
|
|
? Random.ColorHSV(0, 1, 0, 1, 0, 1, 0, 1)
|
|
: RandomUtil.RandomElement(colors);
|
|
|
|
// Normally renderers here will use shared materials, but we want to create colored "variants" thats why
|
|
// we need to instantiate material and add tint color if this is matching material. Other materials will
|
|
// instantiate too anyway even without our help so lets do all of them by ourselfs!
|
|
foreach (var foundRenderer in foundRenderers)
|
|
{
|
|
var materials = new List<Material>();
|
|
foreach (var sharedMaterial in foundRenderer.sharedMaterials)
|
|
{
|
|
if (forMaterials.Contains(sharedMaterial))
|
|
{
|
|
var material = Instantiate(sharedMaterial);
|
|
material.color = color;
|
|
materials.Add(material);
|
|
}
|
|
else
|
|
{
|
|
materials.Add(sharedMaterial);
|
|
}
|
|
}
|
|
foundRenderer.sharedMaterials = materials.ToArray();
|
|
}
|
|
}
|
|
|
|
private void RandomizeMainAttributes(UnitObject unit)
|
|
{
|
|
if (!_generateMainAttributes) return;
|
|
|
|
unit.unitData.baseMainAttributes.Set(MainAttributeType.Strength,
|
|
RandomUtil.RandomInteger(_strength.x, _strength.y));
|
|
unit.unitData.baseMainAttributes.Set(MainAttributeType.Dexterity,
|
|
RandomUtil.RandomInteger(_dexterity.x, _dexterity.y));
|
|
unit.unitData.baseMainAttributes.Set(MainAttributeType.Intelligence,
|
|
RandomUtil.RandomInteger(_intelligence.x, _intelligence.y));
|
|
unit.unitData.baseMainAttributes.Set(MainAttributeType.Constitution,
|
|
RandomUtil.RandomInteger(_constitution.x, _constitution.y));
|
|
unit.unitData.baseMainAttributes.Set(MainAttributeType.Speed,
|
|
RandomUtil.RandomInteger(_speed.x, _speed.y));
|
|
unit.unitData.baseMainAttributes.Set(MainAttributeType.Perception,
|
|
RandomUtil.RandomInteger(_perception.x, _perception.y));
|
|
}
|
|
}
|
|
} |