我为一款名为 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)
}
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 ...
}
我不确定您的代码是否与项目中的代码完全相同,但如原始帖子所示,如果第二个函数在同一范围内,则第二个函数将覆盖第一个函数。
noLoop()
暂停 draw
循环和 loop()
恢复它。您可以使用 isLooping()
来确定调用哪个。
如果您使用的是内置渲染器,请创建一个
Runner
并使用runner.enabled
切换暂停。根据Matter.runner.stop()
的文档:
如果您只想暂时暂停引擎,请参阅
。engine.enabled
...虽然我相信
engine.enabled
是指 runner.enabled
的错字。我有一个 PR 可以修复这个错误。
有关暂停内部渲染器的示例,请参见这个答案。