LoginSignup
0
0

More than 5 years have passed since last update.

jsdoでmatter その2

Posted at

概要

jsdoでmatterやってみた。
ピンボール見つけた。

写真

image.png

サンプルコード

(() => {
    Matter.use(MatterAttractors);
    const PATHS = {
        DOME: '0 0 0 250 19 250 20 231.9 25.7 196.1 36.9 161.7 53.3 129.5 74.6 100.2 100.2 74.6 129.5 53.3 161.7 36.9 196.1 25.7 231.9 20 268.1 20 303.9 25.7 338.3 36.9 370.5 53.3 399.8 74.6 425.4 100.2 446.7 129.5 463.1 161.7 474.3 196.1 480 231.9 480 250 500 250 500 0 0 0',
        DROP_LEFT: '0 0 20 0 70 100 20 150 0 150 0 0',
        DROP_RIGHT: '50 0 68 0 68 150 50 150 0 100 50 0',
        APRON_LEFT: '0 0 180 120 0 120 0 0',
        APRON_RIGHT: '180 0 180 120 0 120 180 0'
    };
    const COLOR = {
        BACKGROUND: '#212529',
        OUTER: '#495057',
        INNER: '#15aabf',
        BUMPER: '#fab005',
        BUMPER_LIT: '#fff3bf',
        PADDLE: '#e64980',
        PINBALL: '#dee2e6'
    };
    const GRAVITY = 0.75;
    const WIREFRAMES = false;
    const BUMPER_BOUNCE = 1.5;
    const PADDLE_PULL = 0.002;
    const MAX_VELOCITY = 40;
    let $currentScore = $('.current-score span');
    let $highScore = $('.high-score span');
    let currentScore, 
        highScore;
    let engine, 
        world,
        render,
        pinball, 
        stopperGroup;
    let leftPaddle,
        leftUpStopper,
        leftDownStopper,
        isLeftPaddleUp;
    let rightPaddle, 
        rightUpStopper,
        rightDownStopper,
        isRightPaddleUp;

    function load() {
        init();
        createStaticBodies();
        createPaddles();
        createPinball();
        createEvents();
    }
    function init() {
        engine = Matter.Engine.create();
        world = engine.world;
        world.bounds = {
            min: {
                x: 0,
                y: 0
            },
            max: {
                x: 500,
                y: 800
            }
        };
        world.gravity.y = GRAVITY;
        render = Matter.Render.create({
            element: $('.container')[0],
            engine: engine,
            options: {
                width: world.bounds.max.x,
                height: world.bounds.max.y,
                wireframes: WIREFRAMES,
                background: COLOR.BACKGROUND
            }
        });
        Matter.Render.run(render);
        let runner = Matter.Runner.create();
        Matter.Runner.run(runner, engine);
        stopperGroup = Matter.Body.nextGroup(true);
        currentScore = 0;
        highScore = 0;
        isLeftPaddleUp = false;
        isRightPaddleUp = false;
    }
    function createStaticBodies() {
        Matter.World.add(world, [
            boundary(250, -30, 500, 100),
            boundary(250, 830, 500, 100),
            boundary(-30, 400, 100, 800),
            boundary(530, 400, 100, 800),
            path(239, 86, PATHS.DOME),
            wall(140, 140, 20, 40, COLOR.INNER),
            wall(225, 140, 20, 40, COLOR.INNER),
            wall(310, 140, 20, 40, COLOR.INNER),
            bumper(105, 250),
            bumper(225, 250),
            bumper(345, 250),
            bumper(165, 340),
            bumper(285, 340),
            wall(440, 520, 20, 560, COLOR.OUTER),
            path(25, 360, PATHS.DROP_LEFT),
            path(425, 360, PATHS.DROP_RIGHT),
            wall(120, 510, 20, 120, COLOR.INNER),
            wall(330, 510, 20, 120, COLOR.INNER),
            wall(60, 529, 20, 160, COLOR.INNER),
            wall(390, 529, 20, 160, COLOR.INNER),
            wall(93, 624, 20, 98, COLOR.INNER, -0.96),
            wall(357, 624, 20, 98, COLOR.INNER, 0.96),
            path(79, 740, PATHS.APRON_LEFT),
            path(371, 740, PATHS.APRON_RIGHT),
            reset(225, 50),
            reset(465, 30)
        ]);
    }
    function createPaddles() {
        leftUpStopper = stopper(160, 591, 'left', 'up');
        leftDownStopper = stopper(140, 743, 'left', 'down');
        rightUpStopper = stopper(290, 591, 'right', 'up');
        rightDownStopper = stopper(310, 743, 'right', 'down');
        Matter.World.add(world, [leftUpStopper, leftDownStopper, rightUpStopper, rightDownStopper]);
        let paddleGroup = Matter.Body.nextGroup(true);
        let paddleLeft = {};
        paddleLeft.paddle = Matter.Bodies.trapezoid(170, 660, 20, 80, 0.33, {
            label: 'paddleLeft',
            angle: 1.57,
            chamfer: {},
            render: {
                fillStyle: COLOR.PADDLE
            }
        });
        paddleLeft.brick = Matter.Bodies.rectangle(172, 672, 40, 80, {
            angle: 1.62,
            chamfer: {},
            render: {
                visible: false
            }
        });
        paddleLeft.comp = Matter.Body.create({
            label: 'paddleLeftComp',
            parts: [paddleLeft.paddle, paddleLeft.brick]
        });
        paddleLeft.hinge = Matter.Bodies.circle(142, 660, 5, {
            isStatic: true,
            render: {
                visible: false
            }
        });
        Object.values(paddleLeft).forEach((piece) => {
            piece.collisionFilter.group = paddleGroup
        });
        paddleLeft.con = Matter.Constraint.create({
            bodyA: paddleLeft.comp,
            pointA: { 
                x: -29.5,
                y: -8.5
            },
            bodyB: paddleLeft.hinge,
            length: 0,
            stiffness: 0
        });
        Matter.World.add(world, [paddleLeft.comp, paddleLeft.hinge, paddleLeft.con]);
        Matter.Body.rotate(paddleLeft.comp, 0.57, { 
            x: 142,
            y: 660
        });
        let paddleRight = {};
        paddleRight.paddle = Matter.Bodies.trapezoid(280, 660, 20, 80, 0.33, {
            label: 'paddleRight',
            angle: -1.57,
            chamfer: {},
            render: {
                fillStyle: COLOR.PADDLE
            }
        });
        paddleRight.brick = Matter.Bodies.rectangle(278, 672, 40, 80, {
            angle: -1.62,
            chamfer: {},
            render: {
                visible: false
            }
        });
        paddleRight.comp = Matter.Body.create({
            label: 'paddleRightComp',
            parts: [paddleRight.paddle, paddleRight.brick]
        });
        paddleRight.hinge = Matter.Bodies.circle(308, 660, 5, {
            isStatic: true,
            render: {
                visible: false
            }
        });
        Object.values(paddleRight).forEach((piece) => {
            piece.collisionFilter.group = paddleGroup
        });
        paddleRight.con = Matter.Constraint.create({
            bodyA: paddleRight.comp,
            pointA: { 
                x: 29.5,
                y: -8.5
            },
            bodyB: paddleRight.hinge,
            length: 0,
            stiffness: 0
        });
        Matter.World.add(world, [paddleRight.comp, paddleRight.hinge, paddleRight.con]);
        Matter.Body.rotate(paddleRight.comp, -0.57, { 
            x: 308, 
            y: 660
        });
    }
    function createPinball() {
        pinball = Matter.Bodies.circle(0, 0, 14, {
            label: 'pinball',
            collisionFilter: {
                group: stopperGroup
            },
            render: {
                fillStyle: COLOR.PINBALL
            }
        });
        Matter.World.add(world, pinball);
        launchPinball();
    }
    function createEvents() {
        Matter.Events.on(engine, 'collisionStart', function(event) {
            let pairs = event.pairs;
            pairs.forEach(function(pair) {
                if (pair.bodyB.label === 'pinball')
                {
                    switch (pair.bodyA.label) 
                    {
                    case 'reset':
                        launchPinball();
                    break;
                    case 'bumper':
                        pingBumper(pair.bodyA);
                    break;
                    }
                }
            });
        });
        Matter.Events.on(engine, 'beforeUpdate', function(event) {
            Matter.Body.setVelocity(pinball, {
                x: Math.max(Math.min(pinball.velocity.x, MAX_VELOCITY), -MAX_VELOCITY),
                y: Math.max(Math.min(pinball.velocity.y, MAX_VELOCITY), -MAX_VELOCITY),
            });
            if (pinball.position.x > 450 && pinball.velocity.y > 0) 
            {
                Matter.Body.setVelocity(pinball, {
                    x: 0, 
                    y: -5
                });
            }
        });
        Matter.World.add(world, Matter.MouseConstraint.create(engine, {
            mouse: Matter.Mouse.create(render.canvas),
            constraint: {
                stiffness: 0.2,
                render: {
                    visible: false
                }
            }
        }));
        $('body').on('keydown', function(e) {
            if (e.which === 37) 
            {
                isLeftPaddleUp = true;
            } 
            else if (e.which === 39)
            {
                isRightPaddleUp = true;
            }
        });
        $('body').on('keyup', function(e) {
            if (e.which === 37)
            {
                isLeftPaddleUp = false;
            } 
            else if (e.which === 39)
            {
                isRightPaddleUp = false;
            }
        });
        $('.left-trigger').on('mousedown touchstart', function(e) {
            isLeftPaddleUp = true;
        }).on('mouseup touchend', function(e) {
            isLeftPaddleUp = false;
        });
        $('.right-trigger').on('mousedown touchstart', function(e) {
            isRightPaddleUp = true;
        }).on('mouseup touchend', function(e) {
            isRightPaddleUp = false;
        });
    }
    function launchPinball() {
        updateScore(0);
        Matter.Body.setPosition(pinball, { 
            x: 465,
            y: 765
        });
        Matter.Body.setVelocity(pinball, {
            x: 0,
            y: -25 + rand(-2, 2) 
        });
        Matter.Body.setAngularVelocity(pinball, 0);
    }
    function pingBumper(bumper) {
        updateScore(currentScore + 10);
        bumper.render.fillStyle = COLOR.BUMPER_LIT;
        setTimeout(function() {
            bumper.render.fillStyle = COLOR.BUMPER;
        }, 100);
    }
    function updateScore(newCurrentScore) {
        currentScore = newCurrentScore;
        $currentScore.text(currentScore);
        highScore = Math.max(currentScore, highScore);
        $highScore.text(highScore);
    }
    function rand(min, max) {
        return Math.random() * (max - min) + min;
    }
    function boundary(x, y, width, height) {
        return Matter.Bodies.rectangle(x, y, width, height, {
            isStatic: true,
            render: {
                fillStyle: COLOR.OUTER
            }
        });
    }
    function wall(x, y, width, height, color, angle = 0) {
        return Matter.Bodies.rectangle(x, y, width, height, {
            angle: angle,
            isStatic: true,
            chamfer: { 
                radius: 10 
            },
            render: {
                fillStyle: color
            }
        });
    }
    function path(x, y, path) {
        let vertices = Matter.Vertices.fromPath(path);
        return Matter.Bodies.fromVertices(x, y, vertices, {
            isStatic: true,
            render: {
                fillStyle: COLOR.OUTER,
                strokeStyle: COLOR.OUTER,
                lineWidth: 1
            }
        });
    }
    function bumper(x, y) {
        let bumper = Matter.Bodies.circle(x, y, 25, {
            label: 'bumper',
            isStatic: true,
            render: {
                fillStyle: COLOR.BUMPER
            }
        });
        bumper.restitution = BUMPER_BOUNCE;
        return bumper;
    }
    function stopper(x, y, side, position) {
        let attracteeLabel = (side === 'left') ? 'paddleLeftComp' : 'paddleRightComp';
        return Matter.Bodies.circle(x, y, 40, {
            isStatic: true,
            render: {
                visible: false,
            },
            collisionFilter: {
                group: stopperGroup
            },
            plugin: {
                attractors: [function(a, b) {
                    if (b.label === attracteeLabel) 
                    {
                        let isPaddleUp = (side === 'left') ? isLeftPaddleUp : isRightPaddleUp;
                        let isPullingUp = (position === 'up' && isPaddleUp);
                        let isPullingDown = (position === 'down' && !isPaddleUp);
                        if (isPullingUp || isPullingDown) 
                        {
                            return {
                                x: (a.position.x - b.position.x) * PADDLE_PULL,
                                y: (a.position.y - b.position.y) * PADDLE_PULL,
                            };
                        }
                    }
                }]
            }
        });
    }
    function reset(x, width) {
        return Matter.Bodies.rectangle(x, 781, width, 2, {
            label: 'reset',
            isStatic: true,
            render: {
                fillStyle: '#fff'
            }
        });
    }
    window.addEventListener('load', load, false);
})();

成果物

以上。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0