【问题标题】:How to freeze/stop bodies using pause button and resume bodies after in Matter.js?如何使用暂停按钮冻结/停止主体并在 Matter.js 之后恢复主体?
【发布时间】:2022-12-24 11:16:52
【问题描述】:

我为一款名为 Pirate Invasion 的游戏创建了一个暂停按钮。我试图在他们的位置暂停/冻结身体并从他们所在的位置恢复他们。

我使用setStaticisStatic使用function mousePressed()。但是,它们都显示错误Uncaught TypeError: Matter.Bodies.setStatic is not a function

我是不是错过了什么,或者这与保存职位或类似的东西有关?

船是必须“暂停/冻结”的物体。

function mousePressed(playButton) { // this is my play button which works perfectly
  gameState = "play"
  World.remove(world, playButton)
  World.remove(world, playImage)
}

function mousePressed(pauseButton) { // pause button which gives an error
  Matter.Bodies.setStatic(boats, true)
}

【问题讨论】:

  • 物理引擎通常在主循环中有一个步进函数调用,暂停它就像不调用该函数一样简单。请出示相关代码。
  • 谢谢,刚刚上传了代码...函数 mousePressed() 在 draw() 函数中。
  • Chris 的建议很好。感谢您提供代码,但这不完全是 minimal reproducible example(显示问题所需的最少代码)。当您遇到错误时,请在您的问题中提供该错误,以便我们都在同一页面上,而不必猜测您的问题。
  • 感谢更新。你必须遍历每个身体并在其上设置静态:boats.forEach(e => Matter.Body.setStatic(e, true));。但是可能有一个 better way 来暂停渲染循环。 This answer 展示了一种暂停不同场景的方法——您可以使用runner.enabled 在单个场景上执行此操作。看起来您在这里使用的是 p5.js 和 MJS?

标签: javascript p5.js matter.js


【解决方案1】:

首先,World 已弃用,因此您应该使用 Composite.remove 而不是 World.remove

至于报错,setStaticBody方法,不是Bodies方法。您可以遍历每个主体并对其调用setStaticboats.forEach(e => Matter.Body.setStatic(e, true));,但根据this issue,如果不对主体实施缓存或其他解决方法,您将无法安全地切换静态。有关更多潜在选项,请参阅How do I make a matter body isStatic false after pressing a key in matter.js?

您确定要通过将正文设置为静态来实现暂停吗?这并没有真正暂停模拟——时间一直在流逝,各种属性可能会继续以意想不到的方式发生变化。

由于您使用的是自己的渲染器 (p5.js),因此暂停整个模拟非常简单。您可以停止在渲染循环中调用 MJS 代码,模拟将暂停。在 p5.js 中,这可以通过 draw 开头的布尔检查来完成,或者通过将 draw 临时设置为不运行 MJS 更新的函数(并且可能显示菜单或“暂停”屏幕)来完成).有关该方法的详细信息,请参阅Transitioning from one scene to the next with p5.js

下面是一个基本示例,通过基于复选框的值在 draw() 循环中提前返回来切换暂停:

class Ball {
  constructor(x, y, r) {
    const options = {
      restitution: 0.1,
      density: 1.5,
      friction: 1,
    };
    this.body = Matter.Bodies.circle(x, y, r, options);
  }

  draw() {
    const {position: {x, y}, circleRadius: r} = this.body;
    fill("white");
    ellipse(x, y, r * 2);
  }
}

const engine = Matter.Engine.create();
const balls = [...Array(20)].map((_, i) =>
  new Ball(
    50 + ~~(Math.random() * 450),
    50 + ~~(Math.random() * 150),
    ~~(Math.random() * 5) + 10,
  )
);
const walls = [
  Matter.Bodies.rectangle(
    250, 200, 500, 50, {isStatic: true}
  ),
  Matter.Bodies.rectangle(
    250, 0, 500, 50, {isStatic: true}
  ),
  Matter.Bodies.rectangle(
    0, 100, 50, 200, {isStatic: true}
  ),
  Matter.Bodies.rectangle(
    500, 100, 50, 200, {isStatic: true}
  ),
];
const bodies = [...walls, ...balls.map(e => e.body)];
Matter.Composite.add(engine.world, bodies);
let checkbox;

function setup() {
  checkbox = createCheckbox("running?", true);
  checkbox.position(0, 0);
  createCanvas(500, 200);
  noStroke();
}

function draw() {
  if (!checkbox.checked()) { // check for pause
    return;
  }

  background(30, 30, 30, 60);
  balls.forEach(e => e.draw());
  fill(160);

  for (const e of walls) {
    beginShape();
    e.vertices.forEach(({x, y}) => vertex(x, y));
    endShape();
  }

  if (random(2)) {
    Matter.Body.applyForce(
      balls[~~random(balls.length)].body,
      {
        x: random(0, 500),
        y: random(0, 200),
      },
      {
        x: random(-3, 3),
        y: random(-3, 3),
      }
    );
  }

  Matter.Engine.update(engine);
}
body {
  margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.18.0/matter.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.5.0/p5.min.js"></script>

如果您想使用鼠标暂停/取消暂停,请将复选框替换为

let running = true;

function mousePressed() {
  running = !running;
}

并在draw函数中测试running

function draw() {
  if (!running) { // check for pause
    return;
  }

  // ... rerender ...
}

我不确定您的代码是否与项目中的代码完全相同,但如原始帖子所示,如果第二个函数在同一范围内,它们将覆盖第一个。

p5 中的另一个选项是调用 noLoop() 暂停 draw 循环和 loop() 恢复它。您可以使用isLooping() 来确定要呼叫哪个。


如果您使用的是内置渲染器,请创建一个 Runner 并使用 runner.enabled 切换暂停。根据Matter.runner.stop()的文档:

如果您只想暂时暂停引擎,请参阅engine.enabled

...虽然我相信 engine.enabled 是指 runner.enabled 的错字。我有一个 PR 可以修复这个错误。

有关暂停内部渲染器的示例,请参阅this answer

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多