Path: blob/main/assets/javascript/pacman/functions.js
15371 views
var NONE = 4,1UP = 3,2LEFT = 2,3DOWN = 1,4RIGHT = 11,5WAITING = 5,6PAUSE = 6,7PLAYING = 7,8COUNTDOWN = 8,9EATEN_PAUSE = 9,10DYING = 10,11Pacman = {};1213Pacman.FPS = 30;1415Pacman.Ghost = function (game, map, colour) {1617var position = null,18direction = null,19eatable = null,20eaten = null,21due = null;2223function getNewCoord(dir, current) {2425var speed = isVunerable() ? 1 : isHidden() ? 4 : 2,26xSpeed = (dir === LEFT && -speed || dir === RIGHT && speed || 0),27ySpeed = (dir === DOWN && speed || dir === UP && -speed || 0);2829return {30"x": addBounded(current.x, xSpeed),31"y": addBounded(current.y, ySpeed)32};33};3435/* Collision detection(walls) is done when a ghost lands on an36* exact block, make sure they dont skip over it37*/38function addBounded(x1, x2) {39var rem = x1 % 10,40result = rem + x2;41if (rem !== 0 && result > 10) {42return x1 + (10 - rem);43} else if(rem > 0 && result < 0) {44return x1 - rem;45}46return x1 + x2;47};4849function isVunerable() {50return eatable !== null;51};5253function isDangerous() {54return eaten === null;55};5657function isHidden() {58return eatable === null && eaten !== null;59};6061function getRandomDirection() {62var moves = (direction === LEFT || direction === RIGHT)63? [UP, DOWN] : [LEFT, RIGHT];64return moves[Math.floor(Math.random() * 2)];65};6667function reset() {68eaten = null;69eatable = null;70position = {"x": 90, "y": 80};71direction = getRandomDirection();72due = getRandomDirection();73};7475function onWholeSquare(x) {76return x % 10 === 0;77};7879function oppositeDirection(dir) {80return dir === LEFT && RIGHT ||81dir === RIGHT && LEFT ||82dir === UP && DOWN || UP;83};8485function makeEatable() {86direction = oppositeDirection(direction);87eatable = game.getTick();88};8990function eat() {91eatable = null;92eaten = game.getTick();93};9495function pointToCoord(x) {96return Math.round(x / 10);97};9899function nextSquare(x, dir) {100var rem = x % 10;101if (rem === 0) {102return x;103} else if (dir === RIGHT || dir === DOWN) {104return x + (10 - rem);105} else {106return x - rem;107}108};109110function onGridSquare(pos) {111return onWholeSquare(pos.y) && onWholeSquare(pos.x);112};113114function secondsAgo(tick) {115return (game.getTick() - tick) / Pacman.FPS;116};117118function getColour() {119if (eatable) {120if (secondsAgo(eatable) > 5) {121return game.getTick() % 20 > 10 ? "#FFFFFF" : "#0000BB";122} else {123return "#0000BB";124}125} else if(eaten) {126return "#222";127}128return colour;129};130131function draw(ctx) {132133var s = map.blockSize,134top = (position.y/10) * s,135left = (position.x/10) * s;136137if (eatable && secondsAgo(eatable) > 8) {138eatable = null;139}140141if (eaten && secondsAgo(eaten) > 3) {142eaten = null;143}144145var tl = left + s;146var base = top + s - 3;147var inc = s / 10;148149var high = game.getTick() % 10 > 5 ? 3 : -3;150var low = game.getTick() % 10 > 5 ? -3 : 3;151152ctx.fillStyle = getColour();153ctx.beginPath();154155ctx.moveTo(left, base);156157ctx.quadraticCurveTo(left, top, left + (s/2), top);158ctx.quadraticCurveTo(left + s, top, left+s, base);159160// Wavy things at the bottom161ctx.quadraticCurveTo(tl-(inc*1), base+high, tl - (inc * 2), base);162ctx.quadraticCurveTo(tl-(inc*3), base+low, tl - (inc * 4), base);163ctx.quadraticCurveTo(tl-(inc*5), base+high, tl - (inc * 6), base);164ctx.quadraticCurveTo(tl-(inc*7), base+low, tl - (inc * 8), base);165ctx.quadraticCurveTo(tl-(inc*9), base+high, tl - (inc * 10), base);166167ctx.closePath();168ctx.fill();169170ctx.beginPath();171ctx.fillStyle = "#FFF";172ctx.arc(left + 6,top + 6, s / 6, 0, 300, false);173ctx.arc((left + s) - 6,top + 6, s / 6, 0, 300, false);174ctx.closePath();175ctx.fill();176177var f = s / 12;178var off = {};179off[RIGHT] = [f, 0];180off[LEFT] = [-f, 0];181off[UP] = [0, -f];182off[DOWN] = [0, f];183184ctx.beginPath();185ctx.fillStyle = "#000";186ctx.arc(left+6+off[direction][0], top+6+off[direction][1],187s / 15, 0, 300, false);188ctx.arc((left+s)-6+off[direction][0], top+6+off[direction][1],189s / 15, 0, 300, false);190ctx.closePath();191ctx.fill();192193};194195function pane(pos) {196197if (pos.y === 100 && pos.x >= 190 && direction === RIGHT) {198return {"y": 100, "x": -10};199}200201if (pos.y === 100 && pos.x <= -10 && direction === LEFT) {202return position = {"y": 100, "x": 190};203}204205return false;206};207208function move(ctx) {209210var oldPos = position,211onGrid = onGridSquare(position),212npos = null;213214if (due !== direction) {215216npos = getNewCoord(due, position);217218if (onGrid &&219map.isFloorSpace({220"y":pointToCoord(nextSquare(npos.y, due)),221"x":pointToCoord(nextSquare(npos.x, due))})) {222direction = due;223} else {224npos = null;225}226}227228if (npos === null) {229npos = getNewCoord(direction, position);230}231232if (onGrid &&233map.isWallSpace({234"y" : pointToCoord(nextSquare(npos.y, direction)),235"x" : pointToCoord(nextSquare(npos.x, direction))236})) {237238due = getRandomDirection();239return move(ctx);240}241242position = npos;243244var tmp = pane(position);245if (tmp) {246position = tmp;247}248249due = getRandomDirection();250251return {252"new" : position,253"old" : oldPos254};255};256257return {258"eat" : eat,259"isVunerable" : isVunerable,260"isDangerous" : isDangerous,261"makeEatable" : makeEatable,262"reset" : reset,263"move" : move,264"draw" : draw265};266};267268Pacman.User = function (game, map) {269270var position = null,271direction = null,272eaten = null,273due = null,274lives = null,275score = 5,276keyMap = {};277278keyMap[KEY.ARROW_LEFT] = LEFT;279keyMap[KEY.ARROW_UP] = UP;280keyMap[KEY.ARROW_RIGHT] = RIGHT;281keyMap[KEY.ARROW_DOWN] = DOWN;282283keyMap[KEY.A] = LEFT;284keyMap[KEY.W] = UP;285keyMap[KEY.D] = RIGHT;286keyMap[KEY.S] = DOWN;287288function addScore(nScore) {289score += nScore;290if (score >= 10000 && score - nScore < 10000) {291lives += 1;292}293};294295function theScore() {296return score;297};298299function loseLife() {300lives -= 1;301};302303function getLives() {304return lives;305};306307function initUser() {308score = 0;309lives = 3;310newLevel();311}312313function newLevel() {314resetPosition();315eaten = 0;316};317318function resetPosition() {319position = {"x": 90, "y": 120};320direction = LEFT;321due = LEFT;322};323324function reset() {325initUser();326resetPosition();327};328329function keyDown(e) {330if (typeof keyMap[e.keyCode] !== "undefined") {331due = keyMap[e.keyCode];332e.preventDefault();333e.stopPropagation();334return false;335}336return true;337};338339function getNewCoord(dir, current) {340return {341"x": current.x + (dir === LEFT && -2 || dir === RIGHT && 2 || 0),342"y": current.y + (dir === DOWN && 2 || dir === UP && -2 || 0)343};344};345346function onWholeSquare(x) {347return x % 10 === 0;348};349350function pointToCoord(x) {351return Math.round(x/10);352};353354function nextSquare(x, dir) {355var rem = x % 10;356if (rem === 0) {357return x;358} else if (dir === RIGHT || dir === DOWN) {359return x + (10 - rem);360} else {361return x - rem;362}363};364365function next(pos, dir) {366return {367"y" : pointToCoord(nextSquare(pos.y, dir)),368"x" : pointToCoord(nextSquare(pos.x, dir)),369};370};371372function onGridSquare(pos) {373return onWholeSquare(pos.y) && onWholeSquare(pos.x);374};375376function isOnSamePlane(due, dir) {377return ((due === LEFT || due === RIGHT) &&378(dir === LEFT || dir === RIGHT)) ||379((due === UP || due === DOWN) &&380(dir === UP || dir === DOWN));381};382383function move(ctx) {384385var npos = null,386nextWhole = null,387oldPosition = position,388block = null;389390if (due !== direction) {391npos = getNewCoord(due, position);392393if (isOnSamePlane(due, direction) ||394(onGridSquare(position) &&395map.isFloorSpace(next(npos, due)))) {396direction = due;397} else {398npos = null;399}400}401402if (npos === null) {403npos = getNewCoord(direction, position);404}405406if (onGridSquare(position) && map.isWallSpace(next(npos, direction))) {407direction = NONE;408}409410if (direction === NONE) {411return {"new" : position, "old" : position};412}413414if (npos.y === 100 && npos.x >= 190 && direction === RIGHT) {415npos = {"y": 100, "x": -10};416}417418if (npos.y === 100 && npos.x <= -12 && direction === LEFT) {419npos = {"y": 100, "x": 190};420}421422position = npos;423nextWhole = next(position, direction);424425block = map.block(nextWhole);426427if ((isMidSquare(position.y) || isMidSquare(position.x)) &&428block === Pacman.BISCUIT || block === Pacman.PILL) {429430map.setBlock(nextWhole, Pacman.EMPTY);431addScore((block === Pacman.BISCUIT) ? 10 : 50);432eaten += 1;433434if (eaten === 182) {435game.completedLevel();436}437438if (block === Pacman.PILL) {439game.eatenPill();440}441}442443return {444"new" : position,445"old" : oldPosition446};447};448449function isMidSquare(x) {450var rem = x % 10;451return rem > 3 || rem < 7;452};453454function calcAngle(dir, pos) {455if (dir == RIGHT && (pos.x % 10 < 5)) {456return {"start":0.25, "end":1.75, "direction": false};457} else if (dir === DOWN && (pos.y % 10 < 5)) {458return {"start":0.75, "end":2.25, "direction": false};459} else if (dir === UP && (pos.y % 10 < 5)) {460return {"start":1.25, "end":1.75, "direction": true};461} else if (dir === LEFT && (pos.x % 10 < 5)) {462return {"start":0.75, "end":1.25, "direction": true};463}464return {"start":0, "end":2, "direction": false};465};466467function drawDead(ctx, amount) {468469var size = map.blockSize,470half = size / 2;471472if (amount >= 1) {473return;474}475476ctx.fillStyle = "#FFFF00";477ctx.beginPath();478ctx.moveTo(((position.x/10) * size) + half,479((position.y/10) * size) + half);480481ctx.arc(((position.x/10) * size) + half,482((position.y/10) * size) + half,483half, 0, Math.PI * 2 * amount, true);484485ctx.fill();486};487488function draw(ctx) {489490var s = map.blockSize,491angle = calcAngle(direction, position);492493ctx.fillStyle = "#FFFF00";494495ctx.beginPath();496497ctx.moveTo(((position.x/10) * s) + s / 2,498((position.y/10) * s) + s / 2);499500ctx.arc(((position.x/10) * s) + s / 2,501((position.y/10) * s) + s / 2,502s / 2, Math.PI * angle.start,503Math.PI * angle.end, angle.direction);504505ctx.fill();506};507508initUser();509510return {511"draw" : draw,512"drawDead" : drawDead,513"loseLife" : loseLife,514"getLives" : getLives,515"score" : score,516"addScore" : addScore,517"theScore" : theScore,518"keyDown" : keyDown,519"move" : move,520"newLevel" : newLevel,521"reset" : reset,522"resetPosition" : resetPosition523};524};525526Pacman.Map = function (size) {527528var height = null,529width = null,530blockSize = size,531pillSize = 0,532map = null;533534function withinBounds(y, x) {535return y >= 0 && y < height && x >= 0 && x < width;536}537538function isWall(pos) {539return withinBounds(pos.y, pos.x) && map[pos.y][pos.x] === Pacman.WALL;540}541542function isFloorSpace(pos) {543if (!withinBounds(pos.y, pos.x)) {544return false;545}546var peice = map[pos.y][pos.x];547return peice === Pacman.EMPTY ||548peice === Pacman.BISCUIT ||549peice === Pacman.PILL;550}551552function drawWall(ctx) {553554var i, j, p, line;555556ctx.strokeStyle = "#0000FF";557ctx.lineWidth = 5;558ctx.lineCap = "round";559560for (i = 0; i < Pacman.WALLS.length; i += 1) {561line = Pacman.WALLS[i];562ctx.beginPath();563564for (j = 0; j < line.length; j += 1) {565566p = line[j];567568if (p.move) {569ctx.moveTo(p.move[0] * blockSize, p.move[1] * blockSize);570} else if (p.line) {571ctx.lineTo(p.line[0] * blockSize, p.line[1] * blockSize);572} else if (p.curve) {573ctx.quadraticCurveTo(p.curve[0] * blockSize,574p.curve[1] * blockSize,575p.curve[2] * blockSize,576p.curve[3] * blockSize);577}578}579ctx.stroke();580}581}582583function reset() {584map = Pacman.MAP.clone();585height = map.length;586width = map[0].length;587};588589function block(pos) {590return map[pos.y][pos.x];591};592593function setBlock(pos, type) {594map[pos.y][pos.x] = type;595};596597function drawPills(ctx) {598599if (++pillSize > 30) {600pillSize = 0;601}602603for (i = 0; i < height; i += 1) {604for (j = 0; j < width; j += 1) {605if (map[i][j] === Pacman.PILL) {606ctx.beginPath();607608ctx.fillStyle = "#000";609ctx.fillRect((j * blockSize), (i * blockSize),610blockSize, blockSize);611612ctx.fillStyle = "#FFF";613ctx.arc((j * blockSize) + blockSize / 2,614(i * blockSize) + blockSize / 2,615Math.abs(5 - (pillSize/3)),6160,617Math.PI * 2, false);618ctx.fill();619ctx.closePath();620}621}622}623};624625function draw(ctx) {626627var i, j, size = blockSize;628629ctx.fillStyle = "#000";630ctx.fillRect(0, 0, width * size, height * size);631632drawWall(ctx);633634for (i = 0; i < height; i += 1) {635for (j = 0; j < width; j += 1) {636drawBlock(i, j, ctx);637}638}639};640641function drawBlock(y, x, ctx) {642643var layout = map[y][x];644645if (layout === Pacman.PILL) {646return;647}648649ctx.beginPath();650651if (layout === Pacman.EMPTY || layout === Pacman.BLOCK ||652layout === Pacman.BISCUIT) {653654ctx.fillStyle = "#000";655ctx.fillRect((x * blockSize), (y * blockSize),656blockSize, blockSize);657658if (layout === Pacman.BISCUIT) {659ctx.fillStyle = "#FFF";660ctx.fillRect((x * blockSize) + (blockSize / 2.5),661(y * blockSize) + (blockSize / 2.5),662blockSize / 6, blockSize / 6);663}664}665ctx.closePath();666};667668reset();669670return {671"draw" : draw,672"drawBlock" : drawBlock,673"drawPills" : drawPills,674"block" : block,675"setBlock" : setBlock,676"reset" : reset,677"isWallSpace" : isWall,678"isFloorSpace" : isFloorSpace,679"height" : height,680"width" : width,681"blockSize" : blockSize682};683};684685Pacman.Audio = function(game) {686687var files = [],688endEvents = [],689progressEvents = [],690playing = [];691692function load(name, path, cb) {693694var f = files[name] = document.createElement("audio");695696progressEvents[name] = function(event) { progress(event, name, cb); };697698f.addEventListener("canplaythrough", progressEvents[name], true);699f.setAttribute("preload", "true");700f.setAttribute("autobuffer", "true");701f.setAttribute("src", path);702f.pause();703};704705function progress(event, name, callback) {706if (event.loaded === event.total && typeof callback === "function") {707callback();708files[name].removeEventListener("canplaythrough",709progressEvents[name], true);710}711};712713function disableSound() {714for (var i = 0; i < playing.length; i++) {715files[playing[i]].pause();716files[playing[i]].currentTime = 0;717}718playing = [];719};720721function ended(name) {722723var i, tmp = [], found = false;724725files[name].removeEventListener("ended", endEvents[name], true);726727for (i = 0; i < playing.length; i++) {728if (!found && playing[i]) {729found = true;730} else {731tmp.push(playing[i]);732}733}734playing = tmp;735};736737function play(name) {738if (!game.soundDisabled()) {739endEvents[name] = function() { ended(name); };740playing.push(name);741files[name].addEventListener("ended", endEvents[name], true);742files[name].play();743}744};745746function pause() {747for (var i = 0; i < playing.length; i++) {748files[playing[i]].pause();749}750};751752function resume() {753for (var i = 0; i < playing.length; i++) {754files[playing[i]].play();755}756};757758return {759"disableSound" : disableSound,760"load" : load,761"play" : play,762"pause" : pause,763"resume" : resume764};765};766767var PACMAN = (function () {768769var state = WAITING,770audio = null,771ghosts = [],772ghostSpecs = ["#00FFDE", "#FF0000", "#FFB8DE", "#FFB847"],773eatenCount = 0,774level = 0,775tick = 0,776ghostPos, userPos,777stateChanged = true,778timerStart = null,779lastTime = 0,780ctx = null,781timer = null,782map = null,783user = null,784stored = null;785786function getTick() {787return tick;788};789790function drawScore(text, position) {791ctx.fillStyle = "#FFFFFF";792ctx.font = "12px BDCartoonShoutRegular";793ctx.fillText(text,794(position["new"]["x"] / 10) * map.blockSize,795((position["new"]["y"] + 5) / 10) * map.blockSize);796}797798function dialog(text) {799ctx.fillStyle = "#FFFF00";800ctx.font = "18px Calibri";801var width = ctx.measureText(text).width,802x = ((map.width * map.blockSize) - width) / 2;803ctx.fillText(text, x, (map.height * 10) + 8);804}805806function soundDisabled() {807return localStorage["soundDisabled"] === "true";808};809810function startLevel() {811user.resetPosition();812for (var i = 0; i < ghosts.length; i += 1) {813ghosts[i].reset();814}815audio.play("start");816timerStart = tick;817setState(COUNTDOWN);818}819820function startNewGame() {821setState(WAITING);822level = 1;823user.reset();824map.reset();825map.draw(ctx);826startLevel();827}828829function keyDown(e) {830if (e.keyCode === KEY.N) {831startNewGame();832} else if (e.keyCode === KEY.S) {833audio.disableSound();834localStorage["soundDisabled"] = !soundDisabled();835} else if (e.keyCode === KEY.P && state === PAUSE) {836audio.resume();837map.draw(ctx);838setState(stored);839} else if (e.keyCode === KEY.P) {840stored = state;841setState(PAUSE);842audio.pause();843map.draw(ctx);844dialog("Paused");845} else if (state !== PAUSE) {846return user.keyDown(e);847}848return true;849}850851function loseLife() {852setState(WAITING);853user.loseLife();854if (user.getLives() > 0) {855startLevel();856}857}858859function setState(nState) {860state = nState;861stateChanged = true;862};863864function collided(user, ghost) {865return (Math.sqrt(Math.pow(ghost.x - user.x, 2) +866Math.pow(ghost.y - user.y, 2))) < 10;867};868869function drawFooter() {870871var topLeft = (map.height * map.blockSize),872textBase = topLeft + 17;873874ctx.fillStyle = "#000000";875ctx.fillRect(0, topLeft, (map.width * map.blockSize), 30);876877ctx.fillStyle = "#FFFF00";878879for (var i = 0, len = user.getLives(); i < len; i++) {880ctx.fillStyle = "#FFFF00";881ctx.beginPath();882ctx.moveTo(150 + (25 * i) + map.blockSize / 2,883(topLeft+1) + map.blockSize / 2);884885ctx.arc(150 + (25 * i) + map.blockSize / 2,886(topLeft+1) + map.blockSize / 2,887map.blockSize / 2, Math.PI * 0.25, Math.PI * 1.75, false);888ctx.fill();889}890891ctx.fillStyle = !soundDisabled() ? "#00FF00" : "#FF0000";892ctx.font = "bold 16px sans-serif";893//ctx.fillText("♪", 10, textBase);894ctx.fillText("s", 10, textBase);895896ctx.fillStyle = "#FFFF00";897ctx.font = "14px Calibri";898ctx.fillText("Score: " + user.theScore(), 30, textBase);899ctx.fillText("Level: " + level, 260, textBase);900}901902function redrawBlock(pos) {903map.drawBlock(Math.floor(pos.y/10), Math.floor(pos.x/10), ctx);904map.drawBlock(Math.ceil(pos.y/10), Math.ceil(pos.x/10), ctx);905}906907function mainDraw() {908909var diff, u, i, len, nScore;910911ghostPos = [];912913for (i = 0, len = ghosts.length; i < len; i += 1) {914ghostPos.push(ghosts[i].move(ctx));915}916u = user.move(ctx);917918for (i = 0, len = ghosts.length; i < len; i += 1) {919redrawBlock(ghostPos[i].old);920}921redrawBlock(u.old);922923for (i = 0, len = ghosts.length; i < len; i += 1) {924ghosts[i].draw(ctx);925}926user.draw(ctx);927928userPos = u["new"];929930for (i = 0, len = ghosts.length; i < len; i += 1) {931if (collided(userPos, ghostPos[i]["new"])) {932if (ghosts[i].isVunerable()) {933audio.play("eatghost");934ghosts[i].eat();935eatenCount += 1;936nScore = eatenCount * 50;937drawScore(nScore, ghostPos[i]);938user.addScore(nScore);939setState(EATEN_PAUSE);940timerStart = tick;941} else if (ghosts[i].isDangerous()) {942audio.play("die");943setState(DYING);944timerStart = tick;945}946}947}948};949950function mainLoop() {951952var diff;953954if (state !== PAUSE) {955++tick;956}957958map.drawPills(ctx);959960if (state === PLAYING) {961mainDraw();962} else if (state === WAITING && stateChanged) {963stateChanged = false;964map.draw(ctx);965dialog("Press N to start a New game");966} else if (state === EATEN_PAUSE &&967(tick - timerStart) > (Pacman.FPS / 3)) {968map.draw(ctx);969setState(PLAYING);970} else if (state === DYING) {971if (tick - timerStart > (Pacman.FPS * 2)) {972loseLife();973} else {974redrawBlock(userPos);975for (i = 0, len = ghosts.length; i < len; i += 1) {976redrawBlock(ghostPos[i].old);977ghostPos.push(ghosts[i].draw(ctx));978}979user.drawDead(ctx, (tick - timerStart) / (Pacman.FPS * 2));980}981} else if (state === COUNTDOWN) {982983diff = 5 + Math.floor((timerStart - tick) / Pacman.FPS);984985if (diff === 0) {986map.draw(ctx);987setState(PLAYING);988} else {989if (diff !== lastTime) {990lastTime = diff;991map.draw(ctx);992dialog("Starting in: " + diff);993}994}995}996997drawFooter();998}9991000function eatenPill() {1001audio.play("eatpill");1002timerStart = tick;1003eatenCount = 0;1004for (i = 0; i < ghosts.length; i += 1) {1005ghosts[i].makeEatable(ctx);1006}1007};10081009function completedLevel() {1010setState(WAITING);1011level += 1;1012map.reset();1013user.newLevel();1014startLevel();1015};10161017function keyPress(e) {1018if (state !== WAITING && state !== PAUSE) {1019e.preventDefault();1020e.stopPropagation();1021}1022};10231024function init(wrapper, root) {10251026var i, len, ghost,1027blockSize = wrapper.offsetWidth / 19,1028canvas = document.createElement("canvas");10291030canvas.setAttribute("width", (blockSize * 19) + "px");1031canvas.setAttribute("height", (blockSize * 22) + 30 + "px");10321033wrapper.appendChild(canvas);10341035ctx = canvas.getContext('2d');10361037audio = new Pacman.Audio({"soundDisabled":soundDisabled});1038map = new Pacman.Map(blockSize);1039user = new Pacman.User({1040"completedLevel" : completedLevel,1041"eatenPill" : eatenPill1042}, map);10431044for (i = 0, len = ghostSpecs.length; i < len; i += 1) {1045ghost = new Pacman.Ghost({"getTick":getTick}, map, ghostSpecs[i]);1046ghosts.push(ghost);1047}10481049map.draw(ctx);1050dialog("Loading ...");10511052var extension = Modernizr.audio.ogg ? 'ogg' : 'mp3';10531054var audio_files = [1055["start", root + "audio/opening_song." + extension],1056["die", root + "audio/die." + extension],1057["eatghost", root + "audio/eatghost." + extension],1058["eatpill", root + "audio/eatpill." + extension],1059["eating", root + "audio/eating.short." + extension],1060["eating2", root + "audio/eating.short." + extension]1061];10621063load(audio_files, function() { loaded(); });1064};10651066function load(arr, callback) {10671068if (arr.length === 0) {1069callback();1070} else {1071var x = arr.pop();1072audio.load(x[0], x[1], function() { load(arr, callback); });1073}1074};10751076function loaded() {10771078dialog("Press N to Start");10791080document.addEventListener("keydown", keyDown, true);1081document.addEventListener("keypress", keyPress, true);10821083timer = window.setInterval(mainLoop, 1000 / Pacman.FPS);1084};10851086return {1087"init" : init1088};10891090}());10911092/* Human readable keyCode index */1093var KEY = {'BACKSPACE': 8, 'TAB': 9, 'NUM_PAD_CLEAR': 12, 'ENTER': 13, 'SHIFT': 16, 'CTRL': 17, 'ALT': 18, 'PAUSE': 19, 'CAPS_LOCK': 20, 'ESCAPE': 27, 'SPACEBAR': 32, 'PAGE_UP': 33, 'PAGE_DOWN': 34, 'END': 35, 'HOME': 36, 'ARROW_LEFT': 37, 'ARROW_UP': 38, 'ARROW_RIGHT': 39, 'ARROW_DOWN': 40, 'PRINT_SCREEN': 44, 'INSERT': 45, 'DELETE': 46, 'SEMICOLON': 59, 'WINDOWS_LEFT': 91, 'WINDOWS_RIGHT': 92, 'SELECT': 93, 'NUM_PAD_ASTERISK': 106, 'NUM_PAD_PLUS_SIGN': 107, 'NUM_PAD_HYPHEN-MINUS': 109, 'NUM_PAD_FULL_STOP': 110, 'NUM_PAD_SOLIDUS': 111, 'NUM_LOCK': 144, 'SCROLL_LOCK': 145, 'SEMICOLON': 186, 'EQUALS_SIGN': 187, 'COMMA': 188, 'HYPHEN-MINUS': 189, 'FULL_STOP': 190, 'SOLIDUS': 191, 'GRAVE_ACCENT': 192, 'LEFT_SQUARE_BRACKET': 219, 'REVERSE_SOLIDUS': 220, 'RIGHT_SQUARE_BRACKET': 221, 'APOSTROPHE': 222};10941095(function () {1096/* 0 - 9 */1097for (var i = 48; i <= 57; i++) {1098KEY['' + (i - 48)] = i;1099}1100/* A - Z */1101for (i = 65; i <= 90; i++) {1102KEY['' + String.fromCharCode(i)] = i;1103}1104/* NUM_PAD_0 - NUM_PAD_9 */1105for (i = 96; i <= 105; i++) {1106KEY['NUM_PAD_' + (i - 96)] = i;1107}1108/* F1 - F12 */1109for (i = 112; i <= 123; i++) {1110KEY['F' + (i - 112 + 1)] = i;1111}1112})();11131114Pacman.WALL = 0;1115Pacman.BISCUIT = 1;1116Pacman.EMPTY = 2;1117Pacman.BLOCK = 3;1118Pacman.PILL = 4;11191120Pacman.MAP = [1121[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],1122[0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0],1123[0, 4, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 4, 0],1124[0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0],1125[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],1126[0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0],1127[0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0],1128[0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0],1129[2, 2, 2, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 2, 2, 2],1130[0, 0, 0, 0, 1, 0, 1, 0, 0, 3, 0, 0, 1, 0, 1, 0, 0, 0, 0],1131[2, 2, 2, 2, 1, 1, 1, 0, 3, 3, 3, 0, 1, 1, 1, 2, 2, 2, 2],1132[0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0],1133[2, 2, 2, 0, 1, 0, 1, 1, 1, 2, 1, 1, 1, 0, 1, 0, 2, 2, 2],1134[0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0],1135[0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0],1136[0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0],1137[0, 4, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 4, 0],1138[0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0],1139[0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0],1140[0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0],1141[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],1142[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]1143];11441145Pacman.WALLS = [11461147[{"move": [0, 9.5]}, {"line": [3, 9.5]},1148{"curve": [3.5, 9.5, 3.5, 9]}, {"line": [3.5, 8]},1149{"curve": [3.5, 7.5, 3, 7.5]}, {"line": [1, 7.5]},1150{"curve": [0.5, 7.5, 0.5, 7]}, {"line": [0.5, 1]},1151{"curve": [0.5, 0.5, 1, 0.5]}, {"line": [9, 0.5]},1152{"curve": [9.5, 0.5, 9.5, 1]}, {"line": [9.5, 3.5]}],11531154[{"move": [9.5, 1]},1155{"curve": [9.5, 0.5, 10, 0.5]}, {"line": [18, 0.5]},1156{"curve": [18.5, 0.5, 18.5, 1]}, {"line": [18.5, 7]},1157{"curve": [18.5, 7.5, 18, 7.5]}, {"line": [16, 7.5]},1158{"curve": [15.5, 7.5, 15.5, 8]}, {"line": [15.5, 9]},1159{"curve": [15.5, 9.5, 16, 9.5]}, {"line": [19, 9.5]}],11601161[{"move": [2.5, 5.5]}, {"line": [3.5, 5.5]}],11621163[{"move": [3, 2.5]},1164{"curve": [3.5, 2.5, 3.5, 3]},1165{"curve": [3.5, 3.5, 3, 3.5]},1166{"curve": [2.5, 3.5, 2.5, 3]},1167{"curve": [2.5, 2.5, 3, 2.5]}],11681169[{"move": [15.5, 5.5]}, {"line": [16.5, 5.5]}],11701171[{"move": [16, 2.5]}, {"curve": [16.5, 2.5, 16.5, 3]},1172{"curve": [16.5, 3.5, 16, 3.5]}, {"curve": [15.5, 3.5, 15.5, 3]},1173{"curve": [15.5, 2.5, 16, 2.5]}],11741175[{"move": [6, 2.5]}, {"line": [7, 2.5]}, {"curve": [7.5, 2.5, 7.5, 3]},1176{"curve": [7.5, 3.5, 7, 3.5]}, {"line": [6, 3.5]},1177{"curve": [5.5, 3.5, 5.5, 3]}, {"curve": [5.5, 2.5, 6, 2.5]}],11781179[{"move": [12, 2.5]}, {"line": [13, 2.5]}, {"curve": [13.5, 2.5, 13.5, 3]},1180{"curve": [13.5, 3.5, 13, 3.5]}, {"line": [12, 3.5]},1181{"curve": [11.5, 3.5, 11.5, 3]}, {"curve": [11.5, 2.5, 12, 2.5]}],11821183[{"move": [7.5, 5.5]}, {"line": [9, 5.5]}, {"curve": [9.5, 5.5, 9.5, 6]},1184{"line": [9.5, 7.5]}],1185[{"move": [9.5, 6]}, {"curve": [9.5, 5.5, 10.5, 5.5]},1186{"line": [11.5, 5.5]}],118711881189[{"move": [5.5, 5.5]}, {"line": [5.5, 7]}, {"curve": [5.5, 7.5, 6, 7.5]},1190{"line": [7.5, 7.5]}],1191[{"move": [6, 7.5]}, {"curve": [5.5, 7.5, 5.5, 8]}, {"line": [5.5, 9.5]}],11921193[{"move": [13.5, 5.5]}, {"line": [13.5, 7]},1194{"curve": [13.5, 7.5, 13, 7.5]}, {"line": [11.5, 7.5]}],1195[{"move": [13, 7.5]}, {"curve": [13.5, 7.5, 13.5, 8]},1196{"line": [13.5, 9.5]}],11971198[{"move": [0, 11.5]}, {"line": [3, 11.5]}, {"curve": [3.5, 11.5, 3.5, 12]},1199{"line": [3.5, 13]}, {"curve": [3.5, 13.5, 3, 13.5]}, {"line": [1, 13.5]},1200{"curve": [0.5, 13.5, 0.5, 14]}, {"line": [0.5, 17]},1201{"curve": [0.5, 17.5, 1, 17.5]}, {"line": [1.5, 17.5]}],1202[{"move": [1, 17.5]}, {"curve": [0.5, 17.5, 0.5, 18]}, {"line": [0.5, 21]},1203{"curve": [0.5, 21.5, 1, 21.5]}, {"line": [18, 21.5]},1204{"curve": [18.5, 21.5, 18.5, 21]}, {"line": [18.5, 18]},1205{"curve": [18.5, 17.5, 18, 17.5]}, {"line": [17.5, 17.5]}],1206[{"move": [18, 17.5]}, {"curve": [18.5, 17.5, 18.5, 17]},1207{"line": [18.5, 14]}, {"curve": [18.5, 13.5, 18, 13.5]},1208{"line": [16, 13.5]}, {"curve": [15.5, 13.5, 15.5, 13]},1209{"line": [15.5, 12]}, {"curve": [15.5, 11.5, 16, 11.5]},1210{"line": [19, 11.5]}],12111212[{"move": [5.5, 11.5]}, {"line": [5.5, 13.5]}],1213[{"move": [13.5, 11.5]}, {"line": [13.5, 13.5]}],12141215[{"move": [2.5, 15.5]}, {"line": [3, 15.5]},1216{"curve": [3.5, 15.5, 3.5, 16]}, {"line": [3.5, 17.5]}],1217[{"move": [16.5, 15.5]}, {"line": [16, 15.5]},1218{"curve": [15.5, 15.5, 15.5, 16]}, {"line": [15.5, 17.5]}],12191220[{"move": [5.5, 15.5]}, {"line": [7.5, 15.5]}],1221[{"move": [11.5, 15.5]}, {"line": [13.5, 15.5]}],12221223[{"move": [2.5, 19.5]}, {"line": [5, 19.5]},1224{"curve": [5.5, 19.5, 5.5, 19]}, {"line": [5.5, 17.5]}],1225[{"move": [5.5, 19]}, {"curve": [5.5, 19.5, 6, 19.5]},1226{"line": [7.5, 19.5]}],12271228[{"move": [11.5, 19.5]}, {"line": [13, 19.5]},1229{"curve": [13.5, 19.5, 13.5, 19]}, {"line": [13.5, 17.5]}],1230[{"move": [13.5, 19]}, {"curve": [13.5, 19.5, 14, 19.5]},1231{"line": [16.5, 19.5]}],12321233[{"move": [7.5, 13.5]}, {"line": [9, 13.5]},1234{"curve": [9.5, 13.5, 9.5, 14]}, {"line": [9.5, 15.5]}],1235[{"move": [9.5, 14]}, {"curve": [9.5, 13.5, 10, 13.5]},1236{"line": [11.5, 13.5]}],12371238[{"move": [7.5, 17.5]}, {"line": [9, 17.5]},1239{"curve": [9.5, 17.5, 9.5, 18]}, {"line": [9.5, 19.5]}],1240[{"move": [9.5, 18]}, {"curve": [9.5, 17.5, 10, 17.5]},1241{"line": [11.5, 17.5]}],12421243[{"move": [8.5, 9.5]}, {"line": [8, 9.5]}, {"curve": [7.5, 9.5, 7.5, 10]},1244{"line": [7.5, 11]}, {"curve": [7.5, 11.5, 8, 11.5]},1245{"line": [11, 11.5]}, {"curve": [11.5, 11.5, 11.5, 11]},1246{"line": [11.5, 10]}, {"curve": [11.5, 9.5, 11, 9.5]},1247{"line": [10.5, 9.5]}]1248];12491250Object.prototype.clone = function () {1251var i, newObj = (this instanceof Array) ? [] : {};1252for (i in this) {1253if (i === 'clone') {1254continue;1255}1256if (this[i] && typeof this[i] === "object") {1257newObj[i] = this[i].clone();1258} else {1259newObj[i] = this[i];1260}1261}1262return newObj;1263};12641265$(function(){1266var el = document.getElementById("pacman");12671268if (Modernizr.canvas && Modernizr.localstorage &&1269Modernizr.audio && (Modernizr.audio.ogg || Modernizr.audio.mp3)) {1270window.setTimeout(function () { PACMAN.init(el, "https://raw.githubusercontent.com/daleharvey/pacman/master/"); }, 0);1271} else {1272el.innerHTML = "Sorry, needs a decent browser<br /><small>" +1273"(firefox 3.6+, Chrome 4+, Opera 10+ and Safari 4+)</small>";1274}1275});12761277