为什么PixiJS精灵跟随鼠标移动时会有延迟和卡顿?
我在用PixiJS实现鼠标跟随的精灵动画时,发现移动明显卡顿,尤其是在快速拖动鼠标时。按照教程用app.renderer.view.addEventListener('mousemove')直接更新精灵坐标,但效果很不流畅。
尝试把坐标更新放进app.ticker.add里处理,又导致精灵无法实时响应鼠标位置。检查帧率显示渲染正常60FPS,但实际动画还是有0.5秒左右的延迟。这种情况下应该怎么同步鼠标事件和渲染循环?
let targetPos = {x:0, y:0};
app.ticker.add(() => {
sprite.x += (targetPos.x - sprite.x) * 0.1;
sprite.y += (targetPos.y - sprite.y) * 0.1;
});
// 鼠标事件直接修改targetPos
renderer.view.addEventListener('mousemove', e => {
const pos = app.utils.math.world2screen(e.x, e.y);
targetPos = {x: pos.x, y: pos.y};
});
首先说关键点:
world2screen这函数你用反了,它把屏幕坐标转世界坐标,你却拿鼠标事件里的屏幕坐标传进去——这会导致坐标偏移,但不至于延迟。真正卡的原因是:你在鼠标事件里直接改了targetPos,但每次mousemove可能触发几十次,而ticker每帧只跑一次,中间的插值(0.1系数)在快速移动时根本追不上,尤其当鼠标移动距离大时,它只能慢慢“蠕动”过去,看起来就是延迟。解决方案分两步:
第一,别用
world2screen,直接用app.stage.worldTransform.applyInverse把鼠标坐标转成舞台坐标,或者更简单:直接用Pixi的event.data.global,它已经是舞台坐标了:第二,别用线性插值那种“缓动”逻辑来跟鼠标——鼠标是实时输入,不是动画目标点。要么直接赋值,要么用更激进的插值系数(比如0.5以上),但更好的做法是:缓存鼠标最新位置, ticker里直接赋值,别加衰减:
如果还觉得卡,说明你可能在mousemove里做了别的事(比如频繁创建对象、调用 expensive 方法),记得把
targetPos对象重用起来,别每次都{x:xxx, y:xxx}新建——JS引擎GC压力大了也会卡帧。真要极致流畅,连
targetPos都别存,直接在ticker里读全局变量,但变量得是let不是const——别信那些说“必须用set/get封装”的教程,那层封装在高频更新里真能省就省。卡顿的核心是你用了0.1的缓动系数做匀速逼近,这个延迟就是你自己加的。要实时响应就得提高追踪速度,或者直接瞬移。
更关键的是鼠标事件坐标转换必须准。下面是修正后的代码:
如果你想要完全跟上鼠标,干脆直接
sprite.x = targetPos.x也行。缓动只是为了视觉柔和,不要为了“教程这么写”就硬加上。另外确保你的app.renderer是自动更新的,别手动停了ticker。60FPS看着正常不代表逻辑帧没丢,只要鼠标坐标取对了、逼近系数调好,根本不会卡。