Files
tools/Unity C++脚本/ParticleAttractionPoint.cs
2025-08-01 10:50:57 +08:00

96 lines
4.1 KiB
C#

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