做Niagara粒子最有成就感的一刻,是看着自己做出来的导弹划出一道弧线,死死咬住目标,然后在命中的瞬间炸开。前两期我们聊了Niagara的发射器搭建、Sprite渲染和基础拖尾,这期直接上实战:十分钟做一个导弹追踪效果。默认你已经知道怎么创建Niagara System和Emitter、怎么把模块拖进堆栈,如果这些还不熟,建议先回头过一遍前两期的基础内容。
所谓“导弹追踪”,往大里说可以做成导弹、魔法飞弹、跟踪榴弹,往小里说其实就是一件事:粒子每帧都根据目标位置修正自己的飞行方向。这期我会直接从思路开始,把场景参数、发射初始化、逐帧转向、拖尾渲染、命中爆炸完整走一遍,最后把最常见的绕圈、抖动、多目标串线这些坑也一并说清。
1. 追踪效果的本质:让粒子自己决定下一步往哪飞
1.1 直线飞行和追踪飞行的区别
直线飞行太简单了:粒子出生时给一个初速度,后面什么都不用管,它就会沿着直线一直飞。比如默认的Initialize Particle里设置一个Velocity (1000, 0, 0),粒子就会朝X轴方向匀速运动。
追踪效果跟直线飞行的本质区别在于:粒子的速度方向需要每一帧都根据“目标位置”重新计算。也就是说,粒子不能闷着头往前冲,必须持续感知目标在哪,然后调整自己的朝向。听起来像是有“思想”了,但实际上就是一套非常朴素的反馈循环:
每一帧做三件事:
- 拿到粒子的当前位置
- 拿到目标位置(外部传入)
- 计算这两点之间的方向向量,把粒子的速度往这个方向修正
这个循环只要每帧都在跑,粒子就会呈现出“追”的感觉。关键在于“修正”的幅度——修正太快,轨迹会很僵硬;修正太慢,导弹会飞过目标,在目标周围画圈。
1.2 三种常见追踪思路怎么选
我在项目里实际试过几种实现思路,各有取舍,先拉一张表对比:
| 方案 | 实现方式 | 优点 | 缺点 | 适合场景 |
|---|---|---|---|---|
| User参数+自定义更新 | 蓝图每帧把目标坐标写入Niagara用户参数,粒子更新时读取并修正速度 | 简单直接,跨网络同步也方便 | 需要外部持续传入目标坐标 | 单目标、多目标的导弹追踪 |
| Object Reader | Niagara直接读取场景中Actor的Transform | 不需要每帧手动传参,目标自己“可见” | 性能开销相对大,只适合CPU模拟,且需要设置好读取通道 | 目标类型固定且数量较少的场景 |
| 碰撞/场景查询 | 通过射线、碰撞事件检测最近目标 | 命中检测天然精准 | 做追踪循环比较复杂,不太适合做平滑转向 | 导弹爆炸检测、命中反馈 |
这期我推荐第一种方案,也就是用User参数传目标坐标。原因是它最直观,也最容易排查问题:你打开Niagara的Debug面板,能看到User.TargetLocation到底变了没有。一旦导弹不追目标,判断起来很快。
1.3 为什么不在Niagara内部直接找目标
有人可能会问:Niagara不是有Object Reader吗?把场景里的目标Actor拖进去,不就能直接在粒子系统里读位置了吗?
理论上可以,但实际用起来有几个麻烦:
- Object Reader依赖目标Actor的可见性和可读通道,万一目标被隐藏、销毁或者不在视口范围内,数据可能读不到
- 它只能配合CPU模拟使用,GPU模拟下很多Data Interface的读取限制很大
- 你把目标“焊死”在粒子系统里,后期想换成多目标轮流追踪,反而不好改
所以除非你的目标就是固定一两个并且永不销毁,否则老老实实用User参数更稳妥。这个在多人联机或者网络同步场景下尤其重要——服务器给客户端传目标坐标,比客户端自己去场景里找Actor更可控。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 场景准备:目标坐标怎么传进Niagara,是我踩过的第一个坑
2.1 先把场景里的目标和发射点摆好
我建议场景里放两个Actor:
- 目标:一个TargetPoint或者一个真正的角色/移动靶子,命名比如
MissileTarget - 发射点:一个明确的空Actor或者场景里的武器挂点,命名比如
MissileSpawn
发射点建议单独用一个Actor,不要偷懒把发射位置直接写死成(0,0,0)。因为后面你可能需要把发射点挂到角色手上、载具机翼下、炮塔口上,单独一个Actor方便随时调整和挂接。
目标则建议用移动的靶子来测试。如果目标站着不动,追踪效果是能跑通,但你看不出追踪逻辑的实时性;目标一旦动起来,才能验证你的转弯算法是不是真的在“追”。
2.2 在Niagara里声明User.TargetLocation
打开你的Niagara System,在System参数面板里新增一个Vector3参数,命名:
text复制User.TargetLocation
命名空间User很关键。Niagara里的参数命名空间不是随便写的,它决定了参数的可见范围。User.命名空间的参数,可
