Phaser Matter.js 实战:一块代码让布料真正飘起来,流体也不远了

发布时间:2026/10/27 18:44:07
Phaser Matter.js 实战:一块代码让布料真正飘起来,流体也不远了

Phaser Matter.js 实战:一块代码让布料真正飘起来,流体也不远了

【免费下载链接】phaserPhaser is a fun, free and fast 2D game framework for making HTML5 games for desktop and mobile web browsers, supporting Canvas and WebGL rendering.项目地址: https://gitcode.com/gh_mirrors/ph/phaser

你场景里的那面旗帜,现在还是死的。水也是一坨不会动的色块。这篇用 Phaser 内置的 Matter.js 物理引擎(不是 Arcade Physics 那种轴对齐碰撞),先给你一段能跑的布料 softBody 最小示例,再讲清楚它为什么能动,最后聊怎么用一堆粒子假装出流体。

一、先跑起来:Phaser 启用 Matter.js + softBody 布料

配置里把物理默认引擎指到 matter,其余保持最简:

const config = { type: Phaser.AUTO, width: 800, height: 600, physics: { default: 'matter', matter: { debug: true } }, scene: { create: create } };

然后 create 里放一个 softBody,再加个地面接着它:

function create() { // 12 列 x 8 行、间距 18px 的粒子网格 this.matter.add.softBody( 100, 100, 12, 8, 18, 18, true, 8, { friction: 0.05, restitution: 0.2 }, { stiffness: 0.15 } ); this.matter.add.rectangle(400, 580, 800, 40, { isStatic: true }); }

想让布料挂在绳子上而不是整片自由落体,把第一行粒子钉死就行:

cloth.bodies.forEach((body, i) => { if (i < 12) this.matter.body.setStatic(body, true); // 第一行 12 个粒子 });

跑起来了吗?下面说它为什么能动。

二、它到底怎么动的:粒子 + 约束就是布料

softBody 没有魔法。它本质是一张粒子网格:很多个圆形小粒子,用虚拟弹簧一根根连起来,排成 columns × rows 的行和列,crossBrace 为 true 时还会加斜撑让网格不容易变形。想象用图钉把一块网格布的最上边钉在墙上,松开手,剩下的部分就被重力拽垂下来了。

实现就在 src/physics/matter-js/Factory.js 的 softBody 方法里,它调 Matter.js 原生的 Composites.softBody 建好网格,再丢进世界。

真正决定"手感"的只有三个参数,按体感记就行:

  • stiffness:弹簧弹性系数。调大 → 布料变硬,像帆布;调小 → 软趴趴像纱巾,晃起来更夸张。
  • damping:能量衰减。调大 → 晃两下就停,像浸了水的布;调小 → 一直飘。
  • friction:粒子表面的涩度。它只影响布料碰到其他物体时的摩擦,不影响自身柔软度,调大布料贴墙时会"抓"一下。

另外两个容易忽略的点:particleRadius 是粒子本体半径,间距 gap 设得太小粒子会互相重叠打架,一般让 gap 明显大于半径;columns × rows 就是粒子总数,16×10 已经是 160 个刚体了,别贪多。

三、让粒子"流"起来:Phaser 粒子模拟流体的思路

先说破前提:Matter.js 没有原生流体模拟。

但"近似"够用。核心思路一句话:大量低摩擦小圆球互相推挤 + 力场推它们 ≈ 看着像流体。

for (let i = 0; i < 150; i++) { this.matter.add.circle( Phaser.Math.Between(150, 650), Phaser.Math.Between(80, 160), 7, { friction: 0.01, density: 0.001, restitution: 0 } ); }

几个体感:density 给小一点,粒子才"水",重了会像沙子;restitution 压到 0,粒子撞到容器壁不反弹,堆积更像液体;再给几个静态 rectangle 围出容器,水会自己找平。

那问题来了,怎么让它"流"?用 src/physics/matter-js/components/Force.js 的 applyForce 每帧往粒子上推一点力,比如按粒子所在 x 坐标加一个正弦波,水面就鼓包、下压、再鼓包。想要漩涡就把力改成切向的。数值一定要小(0.001 量级),Matter 的力不是加速度,给猛了粒子直接射穿屏幕。

想让粒子跟着鼠标走,一行搞定:this.matter.add.mouseSpring()。

四、Phaser 物理性能避坑:帧率保命清单

🧯 调完参数先对照这几条:

  1. 帧率掉到 30?大概率粒子总数超了,先砍到 200 个以内试试,softBody 的行列数减半是最直接的降法。
  2. 画面卡但物理没炸?debug: true 会把每个粒子和弹簧全画出来,发布前关掉,调试完再开。
  3. 布料突然"炸开"散架?多半是 gap 小于粒子直径,粒子初始就互相重叠,弹簧在硬拽它们分开,把间距拉开就正常了。
  4. 粒子飞出屏幕后一直卡?离屏刚体照样参与计算,每帧检查一次 position,出界的直接 remove 或挪回来。
  5. 两个软体放一起特别卡?碰撞检测按对数算,300 个粒子互相检测的量是翻着倍涨的,软体和软体尽量别正面硬刚。

五、下一步往哪走

  • 角色头发动画:一条 2 列的软体就是最朴素的头发,把第一行钉在角色头顶,给个微小风力的周期性扰动。
  • 环境液体:水、熔岩、漏油,第三节那套粒子 + 正弦力场,换个 tint 就能复用。
  • 软体碰撞:果冻、史莱姆,softBody 的行列数调小、stiffness 调低,让它有弹性形变。
  • 鼠标交互:PointerConstraint 和 mouseSpring 的完整写法可以看 src/physics/matter-js/PointerConstraint.js。

参数含义不确定时,直接翻 src/physics/matter-js/Factory.js 的 JSDoc,每个参数都写了行为说明;渲染层面想再叠点光效,docs/Phaser 4 Shader Guide/Phaser 4 Shader Guide.md 里有现成路子。

布料会动、粒子会流之后,剩下的就是挑个场景把这两样焊进去——你游戏里那个还站着一动不动的东西,就是它。

【免费下载链接】phaserPhaser is a fun, free and fast 2D game framework for making HTML5 games for desktop and mobile web browsers, supporting Canvas and WebGL rendering.项目地址: https://gitcode.com/gh_mirrors/ph/phaser

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考