Angry Chickens 2

My Angry Chickens game had some very positive reviews and I decided it's time for a sequel.

The original was vanilla JS, this time we'll use the awesome Matter.js library to add a physics engine.

The Easter Chicken must knock down all the pigs: press the left/right button to change the angle. Hold and release the red oval to launch the chicken. Click here to play the fullscreen version.





Explanation of the code (below):

Lines [3-19] initiate the Matter.js engine. Read this tutorial to learn the basics
[20-24] Setup the canvas and put in the top left corner. This makes it easier to calculate the coordinates of mouse clicks and screen touches.
[25-26] The image for the buttons.
[27-37] Declare variables.
[39-51] This function handles the release of the mouse button/screen touch. Launch the chicken if the ovalPressed variable is true.
[53-64] Handle mouse down/screen touch. If the left or right button is clicked, set the 'move' value accordingly. If the red oval is clicked and the chicken is not moving, start the shot.
[66-72] If the screen is touched, get the coordinates of the first touch and pass them to the 'down' function.
[74-83] Create a new chicken.
[85-118] (Re-)create the world. This is done when the game starts or restarts.
Planks are the brown ('wooden') rectangles that break on collision. Targets are the pigs. A floor is an unbreakable gray ('stone') rectangle. Floor2 is the larger stone for the chicken.
Planks, stones and pigs are placed randomly on the screen.
[120-123] Resize the canvas (if the mobile device is rotated or browser window is resized).
[125-158] After each frame is drawn:
[126] Move the angle by the value determined by the buttons.
[127-132] Display the message.
[134-145] Check if a pig fell below the screen. If so, mark it as dead and reduce the count of targets remaining.
[139-142] All pigs are dead: you win!
[146-149] If the chicken fell down, create a new one.
[150-153] Draw the line indicating the angle.
[155-157] If the oval is pressed, increase the strength of the shot.
[160-172] Check each collision. If a plank collides with the chicken, remove the plank.
[174-181] Mouse and touch event listeners.
[183-184] Do the initial resize and set the listener.
[185] Start the game!

Happy Easter!

<html>
<body>
<script src='matter.min.jstype='text/javascript'></script>
<script>
let Engine = Matter.Engine
    Render = Matter.Render,
    World = Matter.World,
    Bodies = Matter.Bodies,
    Events = Matter.Events,
    Body = Matter.Body;
let engine = Engine.create();
let render = Render.create({
    elementdocument.body,
    engineengine
});
let world = engine.world;
Engine.run(engine);
Render.run(render);
render.options.wireframes = false;
render.canvas.style.position = "absolute";
render.canvas.style.left = "0";
render.canvas.style.top = "0";
let context = render.canvas.getContext('2d');
context.font = 'bold 30px sans-serif';
let buttons = new Image();
buttons.src = 'buttons.png';
let move = 0;
let angle = Math.PI / 4;
let chicken;
let targetCount;
let maxTargets = 5;
let strength = 0;
let ovalPressed = false;
let maxStrength = 200;
let planks = [];
let targets = [];
let counter = 0;
 
function up(e) {
    if (ovalPressed)
        Body.applyForce(chicken, {
            xchicken.position.x,
            ychicken.position.y
        }, {
            xMath.sin(angle) * strength / 1000,
            y: -Math.cos(angle) * strength / 1000
        });
    ovalPressed = false;
    move = 0;
    strength = 0;
}
 
function down(xy) {
    if (y > window.innerHeight * 0.83) {
 
        if (x < window.innerWidth * 0.25)
            move = -0.02;
        if (x > window.innerWidth * 0.75)
            move = 0.02;
        if (x < window.innerWidth * 0.75 && chicken.speed < 0.3 && x > window.innerWidth * 0.25) {
            ovalPressed = true;
        }
    }
}
 
function touchStart(event) {
    var touchobj = event.changedTouches[0];
    let pointerX = touchobj.clientX;
    let pointerY = touchobj.clientY;
    down(pointerXpointerY);
    event.preventDefault();
}
 
function newchicken() {
    chicken = Bodies.circle(10042020, {
        render: {
            sprite: {
                texture: 'chicken.png'
            }
        }
    });
    World.add(engine.worldchicken);
}
 
function reset() {
    planks.splice(0planks.length);
    targets.splice(0targets.length);
    targetCount = maxTargets;
    let floor = Bodies.rectangle(1005005050, {
        isStatictrue
    });
    World.add(engine.worldfloor);
 
    for (let i = 0i < maxTargetsi++) {
        let x = 100 + Math.random() * 700;
        let y = 100 + Math.random() * 400;
        let floor = Bodies.rectangle(xy2020, {
            isStatictrue
        });
        floor.render.fillStyle = 'brown';
        let target = Bodies.circle(xy - 2510, {
            render: {
                sprite: {
                    texture: 'pig.png'
                }
            }
        });
        x = 150 + Math.random() * 400;
        y = 100 + Math.random() * 400;
        targets.push(target);
        let floor2 = Bodies.rectangle(xy2020, {
            isStatictrue
        });
        planks.push(floor);
        World.add(engine.world, [floor, floor2, target]);
    }
    newchicken();
}
 
function resize() {
    render.canvas.style.width = window.innerWidth;
    render.canvas.style.height = window.innerHeight;
}
 
Events.on(render, 'afterRender', function() {
    angle = angle + move;
    context.fillStyle = 'black';
    if (counter) {
        context.fillText('You winPlay again!', 2050);
        counter--;
    } else
        context.fillText(targetCount + ' remaining', 2050);
 
    for (let n = 0n < maxTargetsn++) {
        if (targets[n].position.y > 600 && targets[n].label != 'dead') {
            targetCount--;
            targets[n].label = 'dead';
            World.remove(engine.worldtargets[n]);
            if (targetCount == 0) {
                counter = 500;
                World.clear(world);
                reset();
            }
        }
    }
    if (chicken.position.y > 600) {
        World.remove(worldchicken);
        newchicken();
    }
    context.beginPath();
    context.moveTo(chicken.position.xchicken.position.y);
    context.lineTo(chicken.position.x + (40 + strength) * Math.sin(angle), chicken.position.y - (40 + strength) * Math.cos(angle));
    context.stroke();
 
    if (ovalPressed && strength < maxStrength)
        strength = strength + 2;
    context.drawImage(buttons0500);
});
 
Matter.Events.on(engine, 'collisionStart', function(event) {
    var pairs = event.pairs.slice();
    let a = pairs[0].bodyA;
    let b = pairs[0].bodyB;
    if (a == chicken || b == chicken) {
        for (let n = 0n < planks.lengthn++) {
            let collisionCheck = planks[n];
            if (a == collisionCheck || b == collisionCheck) {
                World.remove(world, [a]);
            }
        }
    }
});
 
render.canvas.addEventListener('touchstart', touchStart);
render.canvas.addEventListener('touchend', up);
render.canvas.addEventListener('mouseup', up);
render.canvas.addEventListener('mousedown', function(e) {
    let x = e.offsetX;
    let y = e.offsetY;
    down(xy);
});
 
window.onresize = resize;
resize();
reset();
 
</script>
</body>
</html>





Check out these programming tutorials:

JavaScript:

Animated particle constellations (42 lines)
Optical illusion (18 lines)

Spinning squares - visual effect (25 lines)

Oldschool fire effect (20 lines)

Fireworks (60 lines)

Animated fractal (32 lines)

Minesweeper game (80 lines)

Physics engine for beginners

Physics engine - interactive sandbox

Physics engine - silly contraption

Starfield (21 lines)

Yin Yang with a twist (4 circles and 20 lines)

Tile map editor (70 lines)

Sine scroller (30 lines)

Turtle graphics

Interactive animated sprites

Image transition effect (16 lines)

Wholla lotta quadratic curves (50 lines)

Your first program in JavaScript: you need 5 minutes and a notepad


Fractals in Excel

Python in Blender 3d:

Domino effect (10 lines)


Wrecking ball effect (14 lines)

3d fractal in Blender Python