You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义渲染器的Matter.js运行速度翻倍问题求助

解决Matter.js点击文本后场景速度翻倍的问题

你的问题核心是每次点击文本时都新建了一个独立的渲染循环,还重复更新物理引擎——初始代码已经有一个全局循环在跑引擎更新,每点一次就多一个循环,每个循环都执行Matter.Engine.update,导致引擎被多次重复更新,速度自然越来越快。

修复方案:

  • 维护一个全局数组,存储所有需要渲染的下落文本对象
  • 只保留一个全局渲染循环,统一处理引擎更新和所有下落对象的渲染
  • 移除explodeMe里的局部循环和重复的引擎更新

修复后的完整代码

HTML(无改动)

<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.20.0/matter.min.js"></script>
<div>
  <div id="physicscanvas">
    <div id="ground"></div>
  </div>
  <p>When <span onclick="explodeMe(this)">this</span> text is clicked, it drops! Likewise, <span onclick="explodeMe(this)">text over here</span> drops too.</p>
</div>

CSS(无改动)

.fallingtext {
  position: absolute;
  z-index: 50;
  color: blue;
  background-color: #0f011f;
  text-align: center;
}

#physicscanvas {
  position: fixed;
  bottom: 0;
  margin: auto;
  width: 800px;
  height: 2500px;
  z-index: -5;
  opacity: 1;
}

html,
body {
  position: relative;
  height: 100%;
  margin: 0;
}

JavaScript(关键修改)

const engine = Matter.Engine.create();
const physicscanvas = document.getElementById("physicscanvas");
// 新增全局数组,管理所有下落文本对象
const fallingObjects = [];

const ground = Matter.Bodies.rectangle(
  200, 2560, 2000, 120, {
    isStatic: true
  }
);
Matter.Composite.add(engine.world, [ground]);

// 全局唯一渲染循环:统一更新引擎 + 渲染所有下落对象
(function rerender() {
  Matter.Engine.update(engine);
  // 遍历数组,调用每个下落对象的渲染方法
  fallingObjects.forEach(obj => obj.render());
  requestAnimationFrame(rerender);
})();

function explodeMe(textid) {
  const explodedName = textid.innerHTML;

  var x_of_physicscanvas = physicscanvas.getBoundingClientRect().left;
  var x_of_text = textid.getBoundingClientRect().left;
  var x_pos_bugged = x_of_text - x_of_physicscanvas;

  var y_of_physicscanvas = physicscanvas.getBoundingClientRect().top;
  var y_of_text = textid.getBoundingClientRect().top;
  var y_pos = y_of_text - y_of_physicscanvas;

  textid.style.visibility = "hidden";

  const fallingContainer = document.createElement("div");
  fallingContainer.innerHTML = explodedName;
  fallingContainer.classList.add("fallingtext");
  physicscanvas.appendChild(fallingContainer);

  var container_width = fallingContainer.offsetWidth;
  var container_height = fallingContainer.offsetHeight;

  x_pos = x_pos_bugged + (container_width / 2);

  var box = {
    w: container_width,
    h: container_height,
    body: Matter.Bodies.rectangle(x_pos, y_pos, container_width, container_height, {
      restitution: 0.7
    }),
    elem: fallingContainer,
    render() {
      const { x, y } = this.body.position;
      this.elem.style.top = `${y - this.h / 2}px`;
      this.elem.style.left = `${x - this.w / 2}px`;
      this.elem.style.transform = `rotate(${this.body.angle}rad)`;
    },
  };

  Matter.Composite.add(engine.world, [box.body]);
  // 将新创建的下落对象加入全局数组
  fallingObjects.push(box);

  // 移除原局部渲染循环和重复的引擎更新
  return;
}

关键改动说明:

  1. 新增fallingObjects数组,统一管理所有需要渲染的文本对象
  2. 全局rerender循环中,除了更新物理引擎,还遍历数组调用每个对象的render方法
  3. 删除explodeMe函数内的局部渲染循环和重复的Matter.Engine.update调用,避免循环叠加和引擎重复更新

这样不管点击多少次,始终只有一个渲染循环在工作,引擎每秒只更新一次(和屏幕帧率同步),就不会出现速度翻倍的问题了。

内容的提问来源于stack exchange,提问作者itsolie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 10:17:02