using System.Collections; using System.Collections.Generic; using UnityEngine; [ExecuteInEditMode] // 让脚本在编辑器模式下也能执行 public class ParticleAttractionPoint : MonoBehaviour { [Header("吸附参数")] [Tooltip("粒子吸附目标点")] public Transform attractionPoint; // 吸附目标点 [Tooltip("粒子生成多久后开始进行吸附")] [Range(0.0f, 100.0f)] public float delayTime = 0.0f; // 延迟时间 [Tooltip("粒子开始进行吸附计算后的大小变化曲线")] public AnimationCurve SizeCurve = new AnimationCurve(); // 控制移动的曲线 [Tooltip("是否使用距离比例计算")] public bool UseDistance = false; [Header("逐帧计算")] public float attractionSpeed=50.0f; [Header("距离比例计算")] [Range(0.001f, 2.0f)] // 限制时间缩放的最大值和最小值 public float timeScale = 1.0f; // 时间缩放 private ParticleSystem particleSystemComponent; private ParticleSystem.Particle[] particles; void OnEnable() // 改用OnEnable替代Start,这样在编辑器中也能初始化 { particleSystemComponent = GetComponent(); particles = new ParticleSystem.Particle[particleSystemComponent.main.maxParticles]; } void LateUpdate() { if(!particleSystemComponent) return; // 添加空检查 int particleCount = particleSystemComponent.GetParticles(particles); if(attractionPoint == null) return; // 添加目标点空检查 for (int i = 0; i < particleCount; i++) { float lifePercent = 1.0f - (particles[i].remainingLifetime / particles[i].startLifetime); // 只有当粒子存在时间超过延迟时间才开始移动 if(particles[i].startLifetime - particles[i].remainingLifetime >= delayTime) { //暂存粒子位置 Vector3 startPos=particles[i].position; if (UseDistance) { // 位置计算方法1 重新计算剩余的距离比例 float adjustedLifePercent = (particles[i].startLifetime - particles[i].remainingLifetime - delayTime) / (particles[i].startLifetime - delayTime); // 根据距离比例计算位置 particles[i].position = Vector3.Lerp(particles[i].position, attractionPoint.position, adjustedLifePercent*timeScale); } else { // 位置计算方法2 朝向吸附点移动 Vector3 direction = (attractionPoint.position - particles[i].position).normalized; particles[i].position += direction * attractionSpeed * Time.deltaTime; } // 修正粒子size float distancePercent=Vector3.Distance(startPos, particles[i].position) / Vector3.Distance(startPos, attractionPoint.position); particles[i].startSize = particles[i].startSize * SizeCurve.Evaluate(distancePercent); // 当粒子到达目标点时立即消失,可能会有大量粒子,引起优化问题 // if(Vector3.Distance(particles[i].position, attractionPoint.position) <= 0.9f) // { // particles[i].remainingLifetime = 0.0f; // } // // 优化方法1 通过使用SqrMagnitude,可以避免开方运算 // if (Vector3.SqrMagnitude(particles[i].position - attractionPoint.position) <= 0.9f * 0.9f) // { // particles[i].remainingLifetime = 0.0f; // } // 优化方法2 使用Mathf.Approximately进行比较 if (Mathf.Approximately(Vector3.Distance(particles[i].position, attractionPoint.position), 0.0f) || Vector3.Distance(particles[i].position, attractionPoint.position) <= 0.9f) { particles[i].remainingLifetime = 0.0f; } } } particleSystemComponent.SetParticles(particles, particleCount); } }