Unity LaserControl脚本激光粒子系统不生效仅LineRenderer显示问题
Unity LaserControl脚本粒子系统失效问题排查
核心故障点
- 播放状态标记逻辑错误:现有代码用
startParticlePlaying/endParticlePlaying两个自定义布尔值控制粒子播放触发,但该标记仅在松开射击键时重置。粒子系统按自身配置播放完一轮自动停止后,标记仍为true,后续帧不会再触发Play()调用,粒子直接停播。 - 射线命中长度计算错误:当前计算LineRenderer终点的公式逻辑混乱,本地坐标系下向上发射的射线命中距离可直接通过
RaycastHit2D.distance获取,原有公式算出的长度偏差极大,可能导致终点粒子被卡在碰撞体内部、或移出相机视域范围无法看见。 - 坐标同步逻辑缺陷:直接修改粒子物体的世界坐标时,若粒子为当前激光物体的子物体、且粒子
Simulation Space设为Local,坐标会叠加父物体偏移,最终粒子位置和预期的射击起点/命中点完全错位。 - 缺失空引用校验:代码未在初始化阶段校验两个粒子系统的引用是否在Inspector面板正确赋值,一旦漏拖引用,调用
Play()/Stop()时会抛出空引用异常,粒子逻辑直接中断,异常仅在控制台打印日志,极易被忽略。
修复后完整代码
using System.Collections; using System.Collections.Generic; using UnityEngine; public class LaserControl : MonoBehaviour { public ParticleSystem LaserStartParticle; public ParticleSystem LaserEndParticle; public float lineLength = 36f; public int damage; public LayerMask layerMask; private LineRenderer Laser; private RaycastHit2D hit; void Start() { Laser = GetComponent<LineRenderer>(); // 初始化校验引用,避免空引用 if (LaserStartParticle == null || LaserEndParticle == null) { Debug.LogError("请在Inspector面板赋值激光粒子引用!"); enabled = false; return; } // 强制粒子使用世界空间模拟,避免坐标偏移 var startMain = LaserStartParticle.main; startMain.simulationSpace = ParticleSystemSimulationSpace.World; var endMain = LaserEndParticle.main; endMain.simulationSpace = ParticleSystemSimulationSpace.World; } void Update() { if (Input.GetButton("Fire1")) { ShootLaser(); } else { Laser.enabled = false; Laser.SetPosition(1, new Vector3(0, lineLength, 0)); // 直接调用停止,不需要额外标记 LaserEndParticle.Stop(true); LaserStartParticle.Stop(true); } } void ShootLaser() { Laser.enabled = true; // 直接通过粒子系统自带的isPlaying判断状态,避免自定义标记不同步 if (!LaserStartParticle.isPlaying) { LaserStartParticle.Play(true); } LaserStartParticle.transform.position = transform.position; hit = Physics2D.Raycast(transform.position, Vector2.up, lineLength, layerMask); if (hit) { Enemy enemy = hit.transform.GetComponent<Enemy>(); if (enemy != null) { enemy.GetDamage(damage); } if (!LaserEndParticle.isPlaying) { LaserEndParticle.Play(true); } LaserEndParticle.transform.position = hit.point; // 直接用hit.distance设置LineRenderer本地终点坐标 Laser.SetPosition(1, new Vector3(0, hit.distance, 0)); } else { Laser.SetPosition(1, new Vector3(0, lineLength, 0)); LaserEndParticle.Stop(true); } } }
部署前额外检查项
- 确认两个粒子系统的
Play On Awake选项为关闭状态,避免场景加载时自动播放 - 确认粒子材质挂载在相机可渲染的层级,未被其他碰撞体遮挡
- 若需要持续射击时粒子持续显示,将两个粒子的
Looping选项勾选,Duration设为大于等于0.5s即可 - 确认
LayerMask参数在Inspector中正确勾选了需要检测的碰撞层,避免射线检测失效导致终点粒子无法触发
内容的提问来源于stack exchange,提问作者Rogan Charlie
相关产品推荐
相关产品推荐

