Matter.js调用World.add()时出现events未定义错误排查求助
问题:Matter.js调用
World.add()触发"Cannot read properties of undefined (reading 'events')"错误 我用Matter.js结合p5.js开发斯诺克游戏,调用World.add()时触发错误:
Matter.js: Cannot read properties of undefined (reading 'events') in Events.trigger()
以下是原代码:
// matter.js modules let Engine = Matter.Engine, Render = Matter.Render, World = Matter.World, Bodies = Matter.Bodies, Mouse = Matter.Mouse, MouseConstraint = Matter.MouseConstraint; // Game variables let engine; let world; let renderer; // Table variables let table; let pocketSize = 50; let tableWidth = 500; let tableHeight = 250; // Ball arrays let reds = []; let colours = []; let pockets = []; // Cue variables let cueBall; let cue; let cueLength = 100; let aiming = false; // Game state let consecutiveColours = 0; function setup() { // Canvas createCanvas(800, 600); // Engine engine = Engine.create(); // Renderer renderer = Render.create({ element: document.body, engine: engine, options: { width: 800, height: 600, wireframes: false } }); // Table body table = Bodies.rectangle(width / 2, height / 2, tableWidth, tableHeight, { isStatic: true }); World.add(world, table); // Table walls World.add(world, [ Bodies.rectangle(width / 2, 50, width, 100, {isStatic: true}), Bodies.rectangle(width / 2, height - 50, width, 100, {isStatic: true}), Bodies.rectangle(50, height / 2, 100, height, {isStatic: true}), Bodies.rectangle(width - 50, height / 2, 100, height, {isStatic: true}) ]); // Pockets let pocketOpts = { isStatic: true, isSensor: true }; pockets.push(Bodies.rectangle(width / 2, 50, pocketSize, pocketSize, pocketOpts)); // Add other 5 pockets // Red balls for(let i = 0; i < 15; i++) { let ball = Bodies.circle(random(tableWidth / 4, tableWidth * 3 / 4), random(100, tableHeight - 50), 15, { friction: 0.05, restitution: 0.5 }); World.add(world, ball); reds.push(ball); } // Coloured balls let colourOptions = { friction: 0.05, restitution: 0.5 }; colours.push(Bodies.circle(tableWidth / 4, tableHeight / 2, 15, colourOptions)); colours.push(Bodies.circle(tableWidth * 3/4, tableHeight / 2, 15, colourOptions)); // Cue ball cueBall = Bodies.circle(tableWidth / 2, tableHeight - 30, 15, { friction: 0.05, restitution: 0.8}); World.add(world, cueBall); // Mouse control let mouse = Mouse.create(renderer.canvas); let mConstraint = MouseConstraint.create(engine, { mouse: mouse }); World.add(world, mConstraint); // Run renderer Render.run(renderer); } function draw() { // Background background(0, 128, 0); // Table stroke(128); strokeWeight(2); fill(100, 50, 0); rect(table.position.x - tableWidth / 2, table.position.y - tableHeight / 2, tableWidth, tableHeight); // Balls for(let i = 0; i < reds.length; i++) { drawBall(reds[i]); } for(let i = 0; i < colours.length; i++) { drawBall(colours[i], 10); } // Cue ball drawBall(cueBall); // Cue if (aiming) { drawCue(); } // Collision messages checkCueCollisions(); // Update physics Engine.update(engine); // Remove pocketed reds reds = reds.filter(red => !red.isSensor); } // Ball function function drawBall(ball, r = 15) { push(); noStroke(); fill(255); circle(ball.position.x, ball.position.y, r * 2); pop(); } // Cue rendering function drawCue() { let x = mouseX; let y = mouseY; if (!onTable(x, y)) { x = cue.position.x; y = cue.position.y; } push(); stroke(128); strokeWeight(10); line(x, y, x - cueLength * cos(cue.angle), y - cueLength * sin(cue.angle)); pop(); } // Cue ball shot function keyPressed() { if (keyCode === ENTER) { aiming = true; cue = Bodies.rectangle(cueBall.position.x, cueBall.position.y, 100, 10); World.add(world, cue); } } // Collision messages function checkCueCollisions() { // Implement collisions with balls and cushions } // Helper functions function onTable(x, y) { return x >= 0 && x <= width && y >= 100 && y <= height - 100; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.19.0/matter.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.js"></script>
错误原因
代码中声明了let world;但未初始化,调用World.add(world, ...)时传入的是undefined,导致Matter.js内部事件系统尝试访问undefined的events属性,触发报错。
修复方案
- 初始化
world变量:在创建引擎后,添加一行绑定世界实例:
engine = Engine.create(); world = engine.world; // 新增此行
- 修复其他潜在问题:
drawCue()中判断cue是否存在,避免未创建时访问属性报错- 将彩色球添加到世界中
- 将口袋添加到世界中
- 优化击球逻辑,不需要将cue添加到物理世界,直接绘制瞄准线即可
完整修正代码
// matter.js modules let Engine = Matter.Engine, Render = Matter.Render, World = Matter.World, Bodies = Matter.Bodies, Mouse = Matter.Mouse, MouseConstraint = Matter.MouseConstraint; // Game variables let engine; let world; let renderer; // Table variables let table; let pocketSize = 50; let tableWidth = 500; let tableHeight = 250; // Ball arrays let reds = []; let colours = []; let pockets = []; // Cue variables let cueBall; let cueLength = 100; let aiming = false; // Game state let consecutiveColours = 0; function setup() { // Canvas createCanvas(800, 600); // Engine engine = Engine.create(); world = engine.world; // 初始化world变量 // Renderer renderer = Render.create({ element: document.body, engine: engine, options: { width: 800, height: 600, wireframes: false } }); // Table body table = Bodies.rectangle(width / 2, height / 2, tableWidth, tableHeight, { isStatic: true }); World.add(world, table); // Table walls World.add(world, [ Bodies.rectangle(width / 2, 50, width, 100, {isStatic: true}), Bodies.rectangle(width / 2, height - 50, width, 100, {isStatic: true}), Bodies.rectangle(50, height / 2, 100, height, {isStatic: true}), Bodies.rectangle(width - 50, height / 2, 100, height, {isStatic: true}) ]); // Pockets let pocketOpts = { isStatic: true, isSensor: true }; pockets.push(Bodies.rectangle(width / 2, 50, pocketSize, pocketSize, pocketOpts)); pockets.push(Bodies.rectangle(50, 50, pocketSize, pocketSize, pocketOpts)); pockets.push(Bodies.rectangle(width - 50, 50, pocketSize, pocketSize, pocketOpts)); pockets.push(Bodies.rectangle(width / 2, height - 50, pocketSize, pocketSize, pocketOpts)); pockets.push(Bodies.rectangle(50, height - 50, pocketSize, pocketSize, pocketOpts)); pockets.push(Bodies.rectangle(width - 50, height - 50, pocketSize, pocketSize, pocketOpts)); World.add(world, pockets); // 将口袋添加到世界 // Red balls for(let i = 0; i < 15; i++) { let ball = Bodies.circle(random(tableWidth / 4, tableWidth * 3 / 4), random(100, tableHeight - 50), 15, { friction: 0.05, restitution: 0.5 }); World.add(world, ball); reds.push(ball); } // Coloured balls let colourOptions = { friction: 0.05, restitution: 0.5 }; colours.push(Bodies.circle(tableWidth / 4, tableHeight / 2, 15, colourOptions)); colours.push(Bodies.circle(tableWidth * 3/4, tableHeight / 2, 15, colourOptions)); // 将彩色球添加到世界 colours.forEach(ball => World.add(world, ball)); // Cue ball cueBall = Bodies.circle(tableWidth / 2, tableHeight - 30, 15, { friction: 0.05, restitution: 0.8}); World.add(world, cueBall); // Mouse control let mouse = Mouse.create(renderer.canvas); let mConstraint = MouseConstraint.create(engine, { mouse: mouse }); World.add(world, mConstraint); // Run renderer Render.run(renderer); } function draw() { // Background background(0, 128, 0); // Table stroke(128); strokeWeight(2); fill(100, 50, 0); rect(table.position.x - tableWidth / 2, table.position.y - tableHeight / 2, tableWidth, tableHeight); // Balls for(let i = 0; i < reds.length; i++) { drawBall(reds[i]); } for(let i = 0; i < colours.length; i++) { drawBall(colours[i], 10); } // Cue ball drawBall(cueBall); // Cue if (aiming) { drawCue(); } // Collision messages checkCueCollisions(); // Update physics Engine.update(engine); // Remove pocketed reds reds = reds.filter(red => !red.isSensor); } // Ball function function drawBall(ball, r = 15) { push(); noStroke(); fill(255); circle(ball.position.x, ball.position.y, r * 2); pop(); } // Cue rendering function drawCue() { let x = mouseX; let y = mouseY; if (!onTable(x, y)) { x = cueBall.position.x; y = cueBall.position.y; } // 计算瞄准角度 let angle = atan2(y - cueBall.position.y, x - cueBall.position.x); push(); stroke(128); strokeWeight(10); line(cueBall.position.x, cueBall.position.y, cueBall.position.x + cueLength * cos(angle), cueBall.position.y + cueLength * sin(angle)); pop(); } // Cue ball shot function keyPressed() { if (keyCode === ENTER) { aiming = !aiming; // 切换瞄准状态 if (!aiming) { // 计算击球力度 let angle = atan2(mouseY - cueBall.position.y, mouseX - cueBall.position.x); let force = 0.05; Matter.Body.applyForce(cueBall, cueBall.position, { x: force * cos(angle), y: force * sin(angle) }); } } } // Collision messages function checkCueCollisions() { // Implement collisions with balls and cushions } // Helper functions function onTable(x, y) { return x >= 0 && x <= width && y >= 100 && y <= height - 100; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.19.0/matter.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.js"></script>
内容的提问来源于stack exchange,提问作者RemRDS
相关产品推荐
相关产品推荐

