240 lines
8.7 KiB
C#
240 lines
8.7 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using Cielonos.MainGame.Characters;
|
||
using Sirenix.OdinInspector;
|
||
using SLSUtilities.LeanPoolAssistance;
|
||
using UnityEngine;
|
||
|
||
namespace Cielonos.MainGame
|
||
{
|
||
[Serializable]
|
||
[InlineProperty]
|
||
public class MeshEffectRendererInfo
|
||
{
|
||
public Renderer renderer;
|
||
public float referenceScale = 1f;
|
||
}
|
||
|
||
public class MeshEffect : PooledObject
|
||
{
|
||
[System.Serializable]
|
||
[InlineProperty]
|
||
public class AdaptiveParameter
|
||
{
|
||
// Renamed for compactness as requested: C = Constant, R2C = RandomTwoConstants
|
||
public enum ParamMode { Constant, RandomRanged }
|
||
|
||
[HorizontalGroup("Line", Width = 120)]
|
||
[HideLabel]
|
||
public ParamMode mode = ParamMode.Constant;
|
||
|
||
[HorizontalGroup("Line", Width = 100)]
|
||
[ShowIf("mode", ParamMode.Constant)]
|
||
[LabelText("Constant")]
|
||
[LabelWidth(60)]
|
||
public float constantValue = 1f;
|
||
|
||
[HorizontalGroup("Line", Width = 100)]
|
||
[ShowIf("mode", ParamMode.RandomRanged)]
|
||
[LabelText("Min")]
|
||
[LabelWidth(30)]
|
||
public float constantMin = 1f;
|
||
|
||
[HorizontalGroup("Line", Width = 100)]
|
||
[ShowIf("mode", ParamMode.RandomRanged)]
|
||
[LabelText("Max")]
|
||
[LabelWidth(30)]
|
||
public float constantMax = 2f;
|
||
|
||
[HideInInspector]
|
||
public bool isCurveDetected = false;
|
||
|
||
[ShowIf("isCurveDetected")]
|
||
[InfoBox("Original source used Curves. Converted to Constant (Lossy).", InfoMessageType.Warning)]
|
||
private bool ShowCurveWarning => isCurveDetected;
|
||
|
||
public AdaptiveParameter(float defaultVal)
|
||
{
|
||
mode = ParamMode.Constant;
|
||
constantValue = defaultVal;
|
||
}
|
||
|
||
public ParticleSystem.MinMaxCurve GetScaledCurve(float scale)
|
||
{
|
||
if (mode == ParamMode.Constant)
|
||
{
|
||
return new ParticleSystem.MinMaxCurve(constantValue * scale);
|
||
}
|
||
else
|
||
{
|
||
return new ParticleSystem.MinMaxCurve(constantMin * scale, constantMax * scale);
|
||
}
|
||
}
|
||
|
||
public void PullFrom(ParticleSystem.MinMaxCurve source)
|
||
{
|
||
isCurveDetected = false;
|
||
switch (source.mode)
|
||
{
|
||
case ParticleSystemCurveMode.Constant:
|
||
mode = ParamMode.Constant;
|
||
constantValue = source.constant;
|
||
break;
|
||
case ParticleSystemCurveMode.TwoConstants:
|
||
mode = ParamMode.RandomRanged;
|
||
constantMin = source.constantMin;
|
||
constantMax = source.constantMax;
|
||
break;
|
||
case ParticleSystemCurveMode.Curve:
|
||
case ParticleSystemCurveMode.TwoCurves:
|
||
isCurveDetected = true;
|
||
mode = ParamMode.Constant;
|
||
constantValue = source.curveMultiplier;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
[System.Serializable]
|
||
public class ParticleSetting
|
||
{
|
||
[Required]
|
||
[OnValueChanged("PullFromParticleSystem")]
|
||
public ParticleSystem particleSystem;
|
||
|
||
[LabelText("Start Size"), LabelWidth(80)]
|
||
public AdaptiveParameter baseStartSize = new AdaptiveParameter(0.5f);
|
||
|
||
[LabelText("Emission"), LabelWidth(80)]
|
||
public AdaptiveParameter baseEmissionRate = new AdaptiveParameter(10f);
|
||
|
||
[HorizontalGroup("Sensitivity")]
|
||
[LabelText("Size Sens."), LabelWidth(70)]
|
||
[Range(0f, 1f)]
|
||
public float sizeScaleSensitivity = 0f;
|
||
|
||
[HorizontalGroup("Sensitivity")]
|
||
[LabelText("Emission Sens."), LabelWidth(90)]
|
||
[Range(0f, 1f)]
|
||
public float emissionScaleSensitivity = 1f;
|
||
|
||
/// <summary>
|
||
/// Automatically pull values from the assigned ParticleSystem.
|
||
/// 自动读取粒子系统参数
|
||
/// </summary>
|
||
public void PullFromParticleSystem()
|
||
{
|
||
if (particleSystem != null)
|
||
{
|
||
baseStartSize.PullFrom(particleSystem.main.startSize);
|
||
baseEmissionRate.PullFrom(particleSystem.emission.rateOverTime);
|
||
}
|
||
}
|
||
}
|
||
|
||
[Title("Mesh Effect Configuration")]
|
||
[Button("Add All Child Particles", ButtonSizes.Medium), PropertyOrder(-1)]
|
||
[Tooltip("Automatically find all ParticleSystems in children and add them to the list.")]
|
||
public void AutoPopulateChildren()
|
||
{
|
||
var systems = GetComponentsInChildren<ParticleSystem>(true);
|
||
foreach (var ps in systems)
|
||
{
|
||
if (particleSettings.Any(p => p.particleSystem == ps)) continue;
|
||
|
||
var newSetting = new ParticleSetting();
|
||
newSetting.particleSystem = ps;
|
||
newSetting.PullFromParticleSystem();
|
||
particleSettings.Add(newSetting);
|
||
}
|
||
}
|
||
|
||
[ListDrawerSettings(ShowFoldout = true)]
|
||
public List<ParticleSetting> particleSettings = new List<ParticleSetting>();
|
||
|
||
[Title("Global Adjustments")]
|
||
[Tooltip("Global scale multiplier for the entire effect. \n全局系数,用于整体调整效果强弱")]
|
||
public float globalMultiplier = 1f;
|
||
|
||
[Tooltip("Reference scale for calculating 'One Unit'. Usually set to 1 or the average size of a character. \n参考尺寸,用于定义“单位大小”。通常设为1或者标准角色的大小")]
|
||
public float referenceScale = 1f;
|
||
|
||
public Renderer targetRenderer;
|
||
|
||
private void Reset()
|
||
{
|
||
isAutoDespawn = false;
|
||
}
|
||
|
||
public void AttachTo(MeshEffectRendererInfo target)
|
||
{
|
||
if (target == null) return;
|
||
|
||
targetRenderer = target.renderer;
|
||
transform.SetParent(targetRenderer.transform, true);
|
||
transform.localPosition = Vector3.zero;
|
||
transform.localRotation = Quaternion.identity;
|
||
transform.localScale = Vector3.one;
|
||
referenceScale = target.referenceScale;
|
||
ApplyEffectSettings();
|
||
}
|
||
|
||
public void StopAllParticles()
|
||
{
|
||
foreach (var setting in particleSettings.Where(setting => setting.particleSystem != null))
|
||
{
|
||
setting.particleSystem.Stop();
|
||
}
|
||
}
|
||
|
||
private void ApplyEffectSettings()
|
||
{
|
||
if (targetRenderer == null) return;
|
||
|
||
// Calculate Scale Factor based on Bounds
|
||
Vector3 size = targetRenderer.bounds.size;
|
||
float averageSize = (size.x + size.y + size.z) / 3f;
|
||
float scaleRatio = (averageSize / referenceScale);
|
||
|
||
if (scaleRatio <= 0.001f) scaleRatio = 1f;
|
||
|
||
foreach (var setting in particleSettings)
|
||
{
|
||
if (setting.particleSystem == null) continue;
|
||
|
||
var main = setting.particleSystem.main;
|
||
var emission = setting.particleSystem.emission;
|
||
var shape = setting.particleSystem.shape;
|
||
|
||
// 1. Adaptive Shape Setup
|
||
shape.enabled = true;
|
||
if (targetRenderer is SkinnedMeshRenderer smr)
|
||
{
|
||
shape.shapeType = ParticleSystemShapeType.SkinnedMeshRenderer;
|
||
shape.skinnedMeshRenderer = smr;
|
||
}
|
||
else if (targetRenderer is MeshRenderer mr)
|
||
{
|
||
shape.shapeType = ParticleSystemShapeType.MeshRenderer;
|
||
shape.meshRenderer = mr;
|
||
}
|
||
|
||
// 2. Calculate Adaptive Parameters
|
||
|
||
// Size Logic
|
||
float sizeFactor = Mathf.Lerp(1f, scaleRatio, setting.sizeScaleSensitivity);
|
||
float finalSizeScale = sizeFactor * globalMultiplier;
|
||
|
||
main.startSize = setting.baseStartSize.GetScaledCurve(finalSizeScale);
|
||
|
||
// Emission Logic
|
||
float areaRatio = Mathf.Pow(scaleRatio, 2);
|
||
float emissionFactor = Mathf.Lerp(1f, areaRatio, setting.emissionScaleSensitivity);
|
||
float finalEmissionScale = emissionFactor * globalMultiplier;
|
||
|
||
emission.rateOverTime = setting.baseEmissionRate.GetScaledCurve(finalEmissionScale);
|
||
}
|
||
}
|
||
}
|
||
} |