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);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|