8

Angry Chickens 2

 2 years ago
source link: https://slicker.me/javascript/ac2/chickens2.htm
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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.js' type='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({     element: document.body,     engine: engine }); 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, {             x: chicken.position.x,             y: chicken.position.y         }, {             x: Math.sin(angle) * strength / 1000,             y: -Math.cos(angle) * strength / 1000         });     ovalPressed = false;     move = 0;     strength = 0; }   function down(x, y) {     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(pointerX, pointerY);     event.preventDefault(); }   function newchicken() {     chicken = Bodies.circle(100, 420, 20, {         render: {             sprite: {                 texture: 'chicken.png'             }         }     });     World.add(engine.world, chicken); }   function reset() {     planks.splice(0, planks.length);     targets.splice(0, targets.length);     targetCount = maxTargets;     let floor = Bodies.rectangle(100, 500, 50, 50, {         isStatic: true     });     World.add(engine.world, floor);       for (let i = 0; i < maxTargets; i++) {         let x = 100 + Math.random() * 700;         let y = 100 + Math.random() * 400;         let floor = Bodies.rectangle(x, y, 20, 20, {             isStatic: true         });         floor.render.fillStyle = 'brown';         let target = Bodies.circle(x, y - 25, 10, {             render: {                 sprite: {                     texture: 'pig.png'                 }             }         });         x = 150 + Math.random() * 400;         y = 100 + Math.random() * 400;         targets.push(target);         let floor2 = Bodies.rectangle(x, y, 20, 20, {             isStatic: true         });         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 win! Play again!', 20, 50);         counter--;     } else         context.fillText(targetCount + ' remaining', 20, 50);       for (let n = 0; n < maxTargets; n++) {         if (targets[n].position.y > 600 && targets[n].label != 'dead') {             targetCount--;             targets[n].label = 'dead';             World.remove(engine.world, targets[n]);             if (targetCount == 0) {                 counter = 500;                 World.clear(world);                 reset();             }         }     }     if (chicken.position.y > 600) {         World.remove(world, chicken);         newchicken();     }     context.beginPath();     context.moveTo(chicken.position.x, chicken.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(buttons, 0, 500); });   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 = 0; n < planks.length; n++) {             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(x, y); });   window.onresize = resize; resize(); reset();   </script> </body> </html>


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK