最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to completely stopresetreinitialize Matter.js canvasworldengineinstance - Stack Overflow

programmeradmin0浏览0评论

I have an instance of Matter.js on the screen such as a game, and want to pletely start over from scratch when the user/player clicks a "new game" button:

const { Engine, Render, Runner, World, Bodies, Mouse, MouseConstraint, Body, Events } = Matter;

    //movement setup
    const engine = Engine.create();
    const { world } = engine;

    let render;
    let runner;

const startGame = document.querySelector('#start');
startGame.addEventListener('click', event => {

    event.preventDefault();

    //hide 'choose difficulty' 
    const chooseDifficulty = document.querySelector('.options');
    chooseDifficulty.classList.add('hidden');

    //get selected difficulty
    const difficulty = document.querySelector('input[name=difficulty]:checked').value;

    //set number of horizontal/vertical cells based on difficulty selected
    switch(difficulty) {
        case 'easy':
            cellsHorizontal = 6;
            cellsVertical = 4;
            break;
        case 'medium':
            cellsHorizontal = 14;
            cellsVertical = 10;
            break;
        case 'hard':
            cellsHorizontal = 25;
            cellsVertical = 15;
            break;
    }

    createMaze();
});

const createMaze = () => {
        //show controls
        // document.querySelector('.controls').classList.remove('hidden');
        console.log(document.querySelector('.controls').scrollHeight)
        //set size of movement.js canvas/world
        const worldWidth = document.querySelector('.canvas').scrollWidth;
        const worldHeight = document.querySelector('.canvas').scrollHeight;

        console.log(document.querySelector('.canvas').scrollHeight)
        console.log(worldHeight);

        //length of one side of one cell
        const unitLengthX = worldWidth/cellsHorizontal;
        const unitLengthY = worldHeight/cellsVertical;

        //disable gravity & render the world
        engine.world.gravity.y = 0;
        world.gravity.x = 0;
        render = Render.create({
            element: document.querySelector('.canvas'),
            engine: engine,
            options: {
                width:worldWidth,
                height:worldHeight,
                wireframes:false
            }
        });

        Render.run(render);
        runner = Runner.create();
        Runner.run(runner, engine);

        //Outer edges
        const edges = [
            /*top*/Bodies.rectangle((worldWidth/2),0,worldWidth,5, {isStatic:true}),
            /*bottom*/Bodies.rectangle((worldWidth/2),worldHeight,worldWidth,5, {isStatic:true}),
            /*left*/Bodies.rectangle(0,(worldHeight/2),5,worldHeight, {isStatic:true}),
            /*right*/Bodies.rectangle(worldWidth,(worldHeight/2),5,worldHeight, {isStatic:true})
        ];

        World.add(world, edges);
}

This creates a canvas inside a .canvas div on the page that takes up the whole screen, with solid edges on the outside so Bodies can't fall through any direction.

In this instance (not included here), I've create a random maze with a rectangle as the goal and a circle to move around using the WASD or arrow keys, and an event handler for a collision between those two which pops up a previously hidden div with a z-index of 1 to go on top of the map, which contains a "Start Over" button which, when clicked, will take the player back to a difficulty selection and then they can generate a brand new maze.

Here's code for that "Start Over" button where I want to clear the entire Matter instance/canvas/world/engine before giving the option to choose a difficulty and create a new maze:

button.addEventListener('click', event => {
            event.preventDefault();
            World.clear(world);
            Engine.clear(engine);
            console.log('reset clicked');
            document.querySelector('.winner').classList.add('hidden');
            document.querySelector('.options').classList.remove('hidden');
        });

Here is where I found the World.clear and Engine.clear method remendations, and that worked to remove all the elements from the current canvas.

However what I'm running into is that when the player chooses a new difficulty and clicks the "Go" button, a whole new canvas inside the existing world gets created, next to/below the old, now empty, canvas.

How do I get rid of that old canvas in order to pletely reinitialize?

I have an instance of Matter.js on the screen such as a game, and want to pletely start over from scratch when the user/player clicks a "new game" button:

const { Engine, Render, Runner, World, Bodies, Mouse, MouseConstraint, Body, Events } = Matter;

    //movement setup
    const engine = Engine.create();
    const { world } = engine;

    let render;
    let runner;

const startGame = document.querySelector('#start');
startGame.addEventListener('click', event => {

    event.preventDefault();

    //hide 'choose difficulty' 
    const chooseDifficulty = document.querySelector('.options');
    chooseDifficulty.classList.add('hidden');

    //get selected difficulty
    const difficulty = document.querySelector('input[name=difficulty]:checked').value;

    //set number of horizontal/vertical cells based on difficulty selected
    switch(difficulty) {
        case 'easy':
            cellsHorizontal = 6;
            cellsVertical = 4;
            break;
        case 'medium':
            cellsHorizontal = 14;
            cellsVertical = 10;
            break;
        case 'hard':
            cellsHorizontal = 25;
            cellsVertical = 15;
            break;
    }

    createMaze();
});

const createMaze = () => {
        //show controls
        // document.querySelector('.controls').classList.remove('hidden');
        console.log(document.querySelector('.controls').scrollHeight)
        //set size of movement.js canvas/world
        const worldWidth = document.querySelector('.canvas').scrollWidth;
        const worldHeight = document.querySelector('.canvas').scrollHeight;

        console.log(document.querySelector('.canvas').scrollHeight)
        console.log(worldHeight);

        //length of one side of one cell
        const unitLengthX = worldWidth/cellsHorizontal;
        const unitLengthY = worldHeight/cellsVertical;

        //disable gravity & render the world
        engine.world.gravity.y = 0;
        world.gravity.x = 0;
        render = Render.create({
            element: document.querySelector('.canvas'),
            engine: engine,
            options: {
                width:worldWidth,
                height:worldHeight,
                wireframes:false
            }
        });

        Render.run(render);
        runner = Runner.create();
        Runner.run(runner, engine);

        //Outer edges
        const edges = [
            /*top*/Bodies.rectangle((worldWidth/2),0,worldWidth,5, {isStatic:true}),
            /*bottom*/Bodies.rectangle((worldWidth/2),worldHeight,worldWidth,5, {isStatic:true}),
            /*left*/Bodies.rectangle(0,(worldHeight/2),5,worldHeight, {isStatic:true}),
            /*right*/Bodies.rectangle(worldWidth,(worldHeight/2),5,worldHeight, {isStatic:true})
        ];

        World.add(world, edges);
}

This creates a canvas inside a .canvas div on the page that takes up the whole screen, with solid edges on the outside so Bodies can't fall through any direction.

In this instance (not included here), I've create a random maze with a rectangle as the goal and a circle to move around using the WASD or arrow keys, and an event handler for a collision between those two which pops up a previously hidden div with a z-index of 1 to go on top of the map, which contains a "Start Over" button which, when clicked, will take the player back to a difficulty selection and then they can generate a brand new maze.

Here's code for that "Start Over" button where I want to clear the entire Matter instance/canvas/world/engine before giving the option to choose a difficulty and create a new maze:

button.addEventListener('click', event => {
            event.preventDefault();
            World.clear(world);
            Engine.clear(engine);
            console.log('reset clicked');
            document.querySelector('.winner').classList.add('hidden');
            document.querySelector('.options').classList.remove('hidden');
        });

Here is where I found the World.clear and Engine.clear method remendations, and that worked to remove all the elements from the current canvas.

However what I'm running into is that when the player chooses a new difficulty and clicks the "Go" button, a whole new canvas inside the existing world gets created, next to/below the old, now empty, canvas.

How do I get rid of that old canvas in order to pletely reinitialize?

Share Improve this question asked Feb 12, 2020 at 19:42 R GreenstreetR Greenstreet 7407 silver badges25 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 9

I guess the Docs assume that devs can put two and two together from the documentation in order to figure this out, but it took me several hours to find/figure out that I needed to bine this other post with the one originally referenced to get this for the "Start Over" button event:

button.addEventListener('click', event => {
            event.preventDefault();
            World.clear(world);
            Engine.clear(engine);
            Render.stop(render);
            Runner.stop(runner);
            render.canvas.remove();
            render.canvas = null;
            render.context = null;
            render.textures = {};
            console.log('reset clicked');
            document.querySelector('.winner').classList.add('hidden');
            document.querySelector('.options').classList.remove('hidden');
        });

Specifically the Render and Runner class methods/property clear-outs. You have to stop both of them, then remove the render itself and clear the other properties for both render and runner.

One VERY important thing to note is that I had to declare engine, world, render, and runner globally, and then assign them in the createMaze function.

Also important, as I found in another post (can't find where it was now) that if you don't stop the Runner, the runner/animation will get faster each time the canvas is re-created.

The function is run initially at load, and then again after clearing out the World/canvas with the "Start Over" button, so those variables need to be global.


I have to be honest and admit that 1) I'm new, and not super knowledgeable/practiced in initializing/reinitializing, and 2) I'm not the best/most thorough at reading through docs, so this may have been obvious somewhere and I just didn't take the time to find it.

To be more honest, I've been led to believe that no one pletely reads docs on everything they use, right? Maybe I've just seen too many "being a developer means pasting from stackoverflow all day" memes.

发布评论

评论列表(0)

  1. 暂无评论