Pac-Man Controls Click in Game box to Activate Controls. Refresh Page to Start New Game! Too follow along, you can use any editor, but I recommend NotePad++. It’s free and easy to use. Below is the Code Just ensure files are in single folder with subfolder of “img” for code to work. Place below images in “img” folder. Save images as their names are listed. block.png capBottom.png capLeft.png capRight.png capTop.png pipeConnectorBottom.png pipeConnectorDownwards.png pipeConnectorLeft.png pipeConnectorRight.png pipeConnectorTop.png pipeCorner1.png pipeCorner2.png pipeCorner3.png pipeCorner4.png pipeCross.png pipeHorizontal.png pipeVertical.png HTML Code for Web Page. Save file as .html <script>body {margin: 0;background-color: black;padding: 10px 20px;}</script> JavaScript Code. Save file as .js const canvas = document.querySelector(‘canvas’)const c = canvas.getContext(‘2d’) const scoreEL = document.querySelector(‘#scoreEL’) canvas.width = innerWidthcanvas.height = innerHeight class Boundary {static width = 40static height = 40constructor({position, image}) {this.position = positionthis.width = 40this.height = 40this.image = image} draw() { //c.fillStyle = 'blue' //c.fillRect(this.position.x, this.position.y, this.width, this.height c.drawImage (this.image, this.position.x, this.position.y) } } class Player {constructor({position, velocity}) {this.position = positionthis.velocity = velocitythis.radius = 15this.radians = .75this.openRate = .12this.rotation = 0} draw() { c.save() c.translate(this.position.x, this.position.y) c.rotate(this.rotation) c.translate(-this.position.x, -this.position.y) c.beginPath() c.arc(this.position.x, this.position.y, this.radius, this.radians, Math.PI *2 - this.radians) c.lineTo(this.position.x, this.position.y) c.fillStyle = 'yellow' c.fill() c.closePath() c.restore() } update() { this.draw() this.position.x += this.velocity.x this.position.y += this.velocity.y if (this.radians < 0 || this.radians > .75) this.openRate = - this.openRate this.radians += this.openRate } } class Ghost {static speed = 2constructor({position, velocity, color = ‘red’}) {this.position = positionthis.velocity = velocitythis.radius = 15this.color = colorthis.prevCollisions = []this.speed = 2this.scared = false} draw() { c.beginPath() c.arc(this.position.x, this.position.y, this.radius, 0, Math.PI *2) c.fillStyle = this.scared ? 'blue' : this.color c.fill() c.closePath() } update() { this.draw() this.position.x += this.velocity.x this.position.y += this.velocity.y } } class Pellet {constructor({position}) {this.position = positionthis.radius = 3} draw() { c.beginPath() c.arc(this.position.x, this.position.y, this.radius, 0, Math.PI *2) c.fillStyle = 'white' c.fill() c.closePath() } } class PowerUp {constructor({position}) {this.position = positionthis.radius = 8} draw() { c.beginPath() c.arc(this.position.x, this.position.y, this.radius, 0, Math.PI *2) c.fillStyle = 'white' c.fill() c.closePath() } } const pellets = []const boundaries = []const powerUps = []const ghosts = [new Ghost({position: {x: Boundary.width * 6 + Boundary.width / 2,y: Boundary.height + Boundary.height / 2},velocity: {x: Ghost.speed,y: 0}}),new Ghost({position: {x: Boundary.width * 6 + Boundary.width / 2,y: Boundary.height * 3 + Boundary.height / 2},velocity: {x: Ghost.speed,y: 0},color: ‘pink’})]const player = new Player({position: {x: Boundary.width + Boundary.width / 2,y: Boundary.height + Boundary.height / 2},velocity: {x: 0,y: 0}}) const keys = {w: {pressed: false},a: {pressed: false},s: {pressed: false},d: {pressed: false}} let lastKey = ”let score = 0 const map = [[‘1’, ‘-‘, ‘-‘, ‘-‘, ‘-‘, ‘-‘, ‘-‘, ‘-‘, ‘-‘, ‘-‘, ‘2’],[‘|’, ‘.’, ‘.’, ‘.’, ‘.’, ‘.’, ‘.’, ‘.’, ‘.’, ‘.’, ‘|’],[‘|’, ‘.’, ‘b’, ‘.’, ‘[‘, ‘7’, ‘]’, ‘.’, ‘b’, ‘.’, ‘|’],[‘|’, ‘.’, ‘.’, ‘.’, ‘.’, ‘‘, ‘.’, ‘.’, ‘.’, ‘.’, ‘|’], [‘|’, ‘.’, ‘[‘, ‘]’, ‘.’, ‘.’, ‘.’, ‘[‘, ‘]’, ‘.’, ‘|’], [‘|’, ‘.’, ‘.’, ‘.’, ‘.’, ‘^’, ‘.’, ‘.’, ‘.’, ‘.’, ‘|’], [‘|’, ‘.’, ‘b’, ‘.’, ‘[‘, ‘+’, ‘]’, ‘.’, ‘b’, ‘.’, ‘|’], [‘|’, ‘.’, ‘.’, ‘.’, ‘.’, ‘‘, ‘.’, ‘.’, ‘.’, ‘.’, ‘|’],[‘|’, ‘.’, ‘[‘, ‘]’, ‘.’, ‘.’, ‘.’, ‘[‘, ‘]’, ‘.’, ‘|’],[‘|’, ‘.’, ‘.’, ‘.’, ‘.’, ‘^’, ‘.’, ‘.’, ‘.’, ‘.’, ‘|’],[‘|’, ‘.’, ‘b’, ‘.’, ‘[‘, ‘5’, ‘]’, ‘.’, ‘b’, ‘.’, ‘|’],[‘|’, ‘.’, ‘.’, ‘.’, ‘.’, ‘.’, ‘.’, ‘.’, ‘.’, ‘p’, ‘|’],[‘4’, ‘-‘, ‘-‘, ‘-‘, ‘-‘, ‘-‘, ‘-‘, ‘-‘, ‘-‘, ‘-‘, ‘3’]] function createImage(src) {const image = new Image()image.src = srcreturn image} map.forEach ((row, i) => {row.forEach ((symbol, j) => {switch(symbol) {case ‘-‘:boundaries.push(new Boundary({position: {x: Boundary.width * j,y: Boundary.height * i},image: createImage(‘./img/pipeHorizontal.png’)}))breakcase ‘|’:boundaries.push(new Boundary({position: {x: Boundary.width * j,y: Boundary.height * i},image: createImage(‘./img/pipeVertical.png’)}))breakcase ‘1’:boundaries.push(new Boundary({position: {x: Boundary.width * j,y: Boundary.height * i},image: createImage(‘./img/pipeCorner1.png’)}))breakcase ‘2’:boundaries.push(new Boundary({position: {x: Boundary.width * j,y: Boundary.height * i},image: createImage(‘./img/pipeCorner2.png’)}))breakcase ‘3’:boundaries.push(new Boundary({position: {x: Boundary.width * j,y: Boundary.height * i},image: createImage(‘./img/pipeCorner3.png’)}))breakcase ‘4’:boundaries.push(new Boundary({position: {x: Boundary.width * j,y: Boundary.height * i},image: createImage(‘./img/pipeCorner4.png’)}))breakcase ‘b’:boundaries.push(new Boundary({position: {x: Boundary.width * j,y: Boundary.height * i},image: createImage(‘./img/block.png’)}))breakcase ‘‘: boundaries.push( new Boundary({ position: { x: j * Boundary.width, y: i * Boundary.height }, image: createImage(‘./img/capLeft.png’) }) ) break case ‘‘:boundaries.push(new Boundary({position: {x: j * Boundary.width,y: i * Boundary.height},image: createImage(‘./img/capRight.png’)}))breakcase ‘_’:boundaries.push(new Boundary({position: {x: j * Boundary.width,y: i * Boundary.height},image: createImage(‘./img/capBottom.png’)}))breakcase ‘^’:boundaries.push(new Boundary({position: {x: j * Boundary.width,y: i * Boundary.height},image: createImage(‘./img/capTop.png’)}))breakcase ‘+’:boundaries.push(new Boundary({position: {x: j * Boundary.width,y: i * Boundary.height},image: createImage(‘./img/pipeCross.png’)}))breakcase ‘5’:boundaries.push(new Boundary({position: {x: j * Boundary.width,y: i * Boundary.height},color: ‘blue’,image: createImage(‘./img/pipeConnectorTop.png’)}))breakcase ‘6’:boundaries.push(new Boundary({position: {x: j * Boundary.width,y: i * Boundary.height},color: ‘blue’,image: createImage(‘./img/pipeConnectorRight.png’)}))breakcase ‘7’:boundaries.push(new Boundary({position: {x: j * Boundary.width,y: i * Boundary.height},color: ‘blue’,image: createImage(‘./img/pipeConnectorBottom.png’)}))breakcase ‘8’:boundaries.push(new Boundary({position: {x: j * Boundary.width,y: i * Boundary.height},image: createImage(‘./img/pipeConnectorLeft.png’)}))breakcase ‘.’:pellets.push(new Pellet({position: {x: j * Boundary.width + Boundary.width /2,y: i * Boundary.height + Boundary.height /2}}))breakcase ‘p’:powerUps.push(new PowerUp({position: {x: j * Boundary.width + Boundary.width /2,y: i * Boundary.height + Boundary.height /2}}))break}})}) function circleCollidesWithRetangle({circle, rectangle}) {const padding = Boundary.width /2 – circle.radius – 1return (circle.position.y – circle.radius + circle.velocity.y<= rectangle.position.y + rectangle.height + padding && circle.position.x + circle.radius + circle.velocity.x >=rectangle.position.x – padding &&circle.position.y + circle.radius + circle.velocity.y>=rectangle.position.y – padding &&circle.position.x – circle.radius + circle.velocity.x<=rectangle.position.x + rectangle.width + padding)} let animationIdfunction animate() {animationId = requestAnimationFrame(animate)c.clearRect(0, 0, canvas.width, canvas.height)if (keys.w.pressed && lastKey === ‘w’) {for (let i = 0; i < boundaries.length; i++) {const boundary = boundaries[i]if (circleCollidesWithRetangle({circle: {…player,velocity: {x: 0,y: -5}},rectangle: boundary})) {player.velocity.y = 0break} else {player.velocity.y = -5}}} else if (keys.a.pressed && lastKey === ‘a’) {for (let i = 0; i < boundaries.length; i++) {const boundary = boundaries[i]if (circleCollidesWithRetangle({circle: {…player,velocity: {x: -5,y: 0}},rectangle: boundary})) {player.velocity.x = 0break} else {player.velocity.x = -5}}} else if (keys.s.pressed && lastKey === ‘s’) {for (let i = 0; i < boundaries.length; i++) {const boundary = boundaries[i]if (circleCollidesWithRetangle({circle: {…player,velocity: {x: 0,y: 5}},rectangle: boundary})) {player.velocity.y = 0break} else {player.velocity.y = 5}}} else if (keys.d.pressed && lastKey === ‘d’) {for (let i = 0; i < boundaries.length; i++) {const boundary = boundaries[i]if (circleCollidesWithRetangle({circle: {…player,velocity: {x: 5,y: 0}},rectangle: boundary})) {player.velocity.x = 0break} else {player.velocity.x = 5}}} // detect collision between ghosts and player for (let i = ghosts.length -1; 0 <= i; i--) { const ghost = ghosts[i] // ghosts touches player if ( Math.hypot( ghost.position.x - player.position.x, ghost.position.y - player.position.y ) < ghost.radius + player.radius ) { if (ghost.scared) { ghosts.splice(i, 1) } else { cancelAnimationFrame(animationId) console.log('you lose') } } } // Win condition goes here if (pellets.length === 0) { console.log('you win') cancelAnimationFrame(animationId) } // power ups go for (let i = powerUps.length -1; 0 <= i; i--) { const powerUp = powerUps[i] powerUp.draw() // player collides with powerup if ( Math.hypot( powerUp.position.x - player.position.x, powerUp.position.y - player.position.y ) < powerUp.radius + player.radius ){ powerUps.splice(i, 1) // make ghosts scared ghosts.forEach((ghost) => { ghost.scared = true setTimeout(() => { ghost.scared = false }, 5000) }) } } // Touch pellets here for (let i = pellets.length -1; 0 <= i; i--) { const pellet = pellets[i] pellet.draw() if ( Math.hypot( pellet.position.x - player.position.x, pellet.position.y - player.position.y ) < pellet.radius + player.radius ) { console.log('touching') pellets.splice(i, 1) score += 10 scoreEL.innerHTML = score } } boundaries.forEach ((boundary) => { boundary.draw() if ( circleCollidesWithRetangle({ circle: player, rectangle: boundary }) ) { player.velocity.x = 0 player.velocity.y = 0 } })player.update() ghosts.forEach((ghost) => { ghost.update() const collisions = [] boundaries.forEach((boundary) => { if ( !collisions.includes('right') && circleCollidesWithRetangle({ circle: { ...ghost, velocity: { x: ghost.speed, y: 0 }}, rectangle: boundary }) ) { collisions.push('right') } if ( !collisions.includes('left') && circleCollidesWithRetangle({ circle: { ...ghost, velocity: { x: -ghost.speed, y: 0 }}, rectangle: boundary }) ) { collisions.push('left') } if ( !collisions.includes('up') && circleCollidesWithRetangle({ circle: { ...ghost, velocity: { x: 0, y: -ghost.speed }}, rectangle: boundary }) ) { collisions.push('up') } if ( !collisions.includes('down') && circleCollidesWithRetangle({ circle: { ...ghost, velocity: { x: 0, y: ghost.speed }}, rectangle: boundary }) ) { collisions.push('down') } }) if (collisions.length > ghost.prevCollisions.length) ghost.prevCollisions = collisions if ( JSON.stringify(collisions) !== JSON.stringify(ghost.prevCollisions)) { //console.log('gogo') if (ghost.velocity.x > 0) ghost.prevCollisions.push('right') else if (ghost.velocity.x < 0) ghost.prevCollisions.push('left') else if (ghost.velocity.y < 0) ghost.prevCollisions.push('up') else if (ghost.velocity.y > 0) ghost.prevCollisions.push('down') console.log(collisions) console.log(ghost.prevCollisions) const pathways = ghost.prevCollisions.filter((collision) => { return !collisions.includes(collision) }) console.log({pathways}) const direction = pathways[Math.floor(Math.random() * pathways.length)] console.log({direction}) switch (direction) { case 'down': ghost.velocity.y = ghost.speed ghost.velocity.x = 0 break case 'up': ghost.velocity.y = -ghost.speed ghost.velocity.x = 0 break case 'right': ghost.velocity.y = 0 ghost.velocity.x = ghost.speed break case 'left': ghost.velocity.y = 0 ghost.velocity.x = -ghost.speed break } ghost.prevCollisions = [] } //console.log(collisions) }) if (player.velocity.x > 0) player.rotation = 0 else if (player.velocity.x < 0) player.rotation = Math.PI else if (player.velocity.y > 0) player.rotation = Math.PI / 2 else if (player.velocity.y < 0) player.rotation = Math.PI * 1.5 } // end of animate() animate() addEventListener(‘keydown’, ({key}) => {switch (key) {case ‘w’:keys.w.pressed = truelastKey = ‘w’breakcase ‘a’:keys.a.pressed = truelastKey = ‘a’breakcase ‘s’:keys.s.pressed = truelastKey = ‘s’breakcase ‘d’:keys.d.pressed = truelastKey = ‘d’break}}) addEventListener('keyup', ({key}) => { switch (key) { case 'w': keys.w.pressed = false break case 'a': keys.a.pressed = false break case 's': keys.s.pressed = false break case 'd': keys.d.pressed = false break } })