如何使用暂停按钮冻结/停止实体并在 Matter.js 之后恢复实体?

问题描述 投票:0回答:1

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

我已经使用

setStatic
isStatic
使用
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)
}
javascript p5.js matter.js
1个回答
2
投票

首先,

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

至于错误,

setStatic
Body
方法,不是
Bodies
方法。您可以遍历每个主体并对其调用
setStatic
boats.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 更新的函数(并且可能显示菜单或“暂停”屏幕) ).有关该方法的详细信息,请参阅使用 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.19.0/matter.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.min.js"></script>

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

let running = true;

function mousePressed() {
  running = !running;
}

并在

running
函数中测试
draw

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 可以修复这个错误。

有关暂停内部渲染器的示例,请参见这个答案

© www.soinside.com 2019 - 2024. All rights reserved.