├── .gitignore ├── README.md ├── docs └── proposal.md ├── images ├── Virus-128.png ├── background.jpeg ├── pillblue.png ├── pillblueleft.png ├── pillblueright.png ├── pillred.png ├── pillredleft.png ├── pillredright.png ├── pillyellow.png ├── pillyellowleft.png ├── pillyellowright.png ├── virus.jpg ├── virusblue.png ├── virusred.png └── virusyellow.png ├── index.html ├── lib ├── audio.js ├── bundle.js ├── bundle.js.map ├── drmariojs.js ├── game.js ├── keymaster.js ├── pill.js └── virus.js ├── package.json ├── sounds ├── bgm.mp3 ├── eatblocks.mp3 ├── gameover.mp3 ├── levelclear.mp3 ├── movepill.mp3 └── rotatepill.mp3 ├── stylesheets └── css.css └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile '~/.gitignore_global' 6 | 7 | # Ignore bundler config. 8 | /.bundle 9 | 10 | # Ignore all logfiles and tempfiles. 11 | /log/* 12 | /tmp/* 13 | !/log/.keep 14 | !/tmp/.keep 15 | 16 | /node_modules 17 | /yarn-error.log 18 | 19 | .byebug_history 20 | 21 | node_modules/ 22 | .byebug_history 23 | .DS_Store 24 | npm-debug.log 25 | 26 | # Ignore application configuration 27 | /config/application.yml 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dr Mario JS 2 | 3 | [Dr Mario JS](https://swangs.github.io/drmariojs/) is a web browser puzzle game inspired by Dr Mario. It is built entirely with vanilla JavaScript and HTML5. 4 | 5 | ## How to Play 6 | Create rows and columns of four or more matching colors. Destroy all viruses to advance to the next level. 7 | 8 | ![alt text](https://i.imgur.com/bmdvYwD.gif "drmariodemo") 9 | 10 | ## Features 11 | 9 levels with increasing difficulty 12 | 13 | Engineered with object oriented programming in mind; key objects and functions are bundled together with Webpack 14 | 15 | 2D Array Grid and Canvas Element synced to provide foundations for game animation and mechanics. 16 | ```javascript 17 | newBoard(ctx) { 18 | const board = new Array(16); 19 | for (let i = 0; i < board.length; i++) { 20 | board[i] = new Array(8); 21 | } 22 | this.randomizeViruses(ctx, board); 23 | return board; 24 | } 25 | 26 | draw(ctx) { 27 | if (!this.paused && !this.gameOver) { 28 | ctx.clearRect(0, 0, Game.DIM_X, Game.DIM_Y); 29 | this.allObjects().forEach((object) => { 30 | if (object !== undefined) { 31 | object.draw(); 32 | } 33 | }); 34 | } 35 | } 36 | ``` 37 | -------------------------------------------------------------------------------- /docs/proposal.md: -------------------------------------------------------------------------------- 1 | # Dr. Mario Javascript Project 2 | 3 | Dr. Mario is a tetris-like puzzle game where the goal is to eliminate the viruses on the board by creating rows or columns of 4 matching colors. 4 | 5 | Players will be able to choose the speed and amount of viruses to adjust difficulty. 6 | 7 | ## Functionality and MVP 8 | * Board will be randomly seeded based on difficulty. 9 | * Player controls will be four movements and two rotation buttons. 10 | * Collision detection for viruses and pieces. 11 | * Logic for winning/losing conditions. 12 | * Sounds for BGM, keypress, rotation, and successful match. 13 | 14 | ## Wireframes 15 | ![alt text](https://i.imgur.com/DOo0eGV.png "drmariojs") 16 | 17 | ## Architectures and Technologies 18 | * Vanilla Javascript for overall game structure and logic. 19 | * HTML5 Canvas for DOM Manipulation and Rendering. 20 | * Web Audio API for sounds. 21 | 22 | ## Implementation Timeline 23 | ### Day 1 24 | * Set up Board and Pieces. 25 | ### Day 2 26 | * Implement Controls 27 | ### Day 3 28 | * Build logic for winning game 29 | ### Day 4 30 | * Add sound and styling 31 | 32 | ## Bonus Features 33 | * Never Ending Mode - Viruses proliferate periodically. 34 | * Add original sprites and sounds. 35 | * Create Multiplayer 36 | -------------------------------------------------------------------------------- /images/Virus-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swangs/drmariojs/5ba12ac05bbf8267360b7ca0a7497e350a84311a/images/Virus-128.png -------------------------------------------------------------------------------- /images/background.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swangs/drmariojs/5ba12ac05bbf8267360b7ca0a7497e350a84311a/images/background.jpeg -------------------------------------------------------------------------------- /images/pillblue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swangs/drmariojs/5ba12ac05bbf8267360b7ca0a7497e350a84311a/images/pillblue.png -------------------------------------------------------------------------------- /images/pillblueleft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swangs/drmariojs/5ba12ac05bbf8267360b7ca0a7497e350a84311a/images/pillblueleft.png -------------------------------------------------------------------------------- /images/pillblueright.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swangs/drmariojs/5ba12ac05bbf8267360b7ca0a7497e350a84311a/images/pillblueright.png -------------------------------------------------------------------------------- /images/pillred.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swangs/drmariojs/5ba12ac05bbf8267360b7ca0a7497e350a84311a/images/pillred.png -------------------------------------------------------------------------------- /images/pillredleft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swangs/drmariojs/5ba12ac05bbf8267360b7ca0a7497e350a84311a/images/pillredleft.png -------------------------------------------------------------------------------- /images/pillredright.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swangs/drmariojs/5ba12ac05bbf8267360b7ca0a7497e350a84311a/images/pillredright.png -------------------------------------------------------------------------------- /images/pillyellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swangs/drmariojs/5ba12ac05bbf8267360b7ca0a7497e350a84311a/images/pillyellow.png -------------------------------------------------------------------------------- /images/pillyellowleft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swangs/drmariojs/5ba12ac05bbf8267360b7ca0a7497e350a84311a/images/pillyellowleft.png -------------------------------------------------------------------------------- /images/pillyellowright.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swangs/drmariojs/5ba12ac05bbf8267360b7ca0a7497e350a84311a/images/pillyellowright.png -------------------------------------------------------------------------------- /images/virus.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swangs/drmariojs/5ba12ac05bbf8267360b7ca0a7497e350a84311a/images/virus.jpg -------------------------------------------------------------------------------- /images/virusblue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swangs/drmariojs/5ba12ac05bbf8267360b7ca0a7497e350a84311a/images/virusblue.png -------------------------------------------------------------------------------- /images/virusred.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swangs/drmariojs/5ba12ac05bbf8267360b7ca0a7497e350a84311a/images/virusred.png -------------------------------------------------------------------------------- /images/virusyellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swangs/drmariojs/5ba12ac05bbf8267360b7ca0a7497e350a84311a/images/virusyellow.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Dr Mario JS 4 | 5 | 6 | 7 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |

Controls

30 |

Left - Left Arrow

31 |

Right - Right Arrow

32 |

Down - Down Arrow

33 |

Rotate Left - Z

34 |

Rotate Right - X

35 |

Pause - Space

36 |

Destroy as many Viruses as you can by creating rows and columns of 4 or more matching colors

37 |
38 | 39 |
40 | 48 |

49 |

50 |

51 | 52 |
53 |
54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /lib/audio.js: -------------------------------------------------------------------------------- 1 | class Audio { 2 | 3 | toggleMute() { 4 | const sounds = document.getElementsByTagName("audio"); 5 | for (let i = 0; i < sounds.length; i++) { 6 | sounds[i].muted = !sounds[i].muted; 7 | } 8 | const muteButton = document.getElementById("muteicon"); 9 | if (sounds[0].muted) { 10 | muteButton.classList.remove("fa-volume-up"); 11 | muteButton.classList.add("fa-volume-off"); 12 | } else { 13 | muteButton.classList.remove("fa-volume-off"); 14 | muteButton.classList.add("fa-volume-up"); 15 | } 16 | } 17 | startGame() { 18 | const sounds = document.getElementsByTagName("audio"); 19 | for (let i = 0; i < sounds.length; i++) { 20 | sounds[i].pause(); 21 | sounds.currentTime = 0; 22 | } 23 | const sound = document.getElementById("bgm"); 24 | sound.play(); 25 | } 26 | 27 | bgmStop() { 28 | const sound = document.getElementById("bgm"); 29 | sound.pause(); 30 | sound.currentTime = 0; 31 | } 32 | 33 | pausebgm() { 34 | const sound = document.getElementById("bgm"); 35 | sound.pause(); 36 | } 37 | 38 | playbgm() { 39 | const sound = document.getElementById("bgm"); 40 | sound.play(); 41 | } 42 | 43 | movePill() { 44 | const sound = document.getElementById("movepill"); 45 | sound.currentTime = 0; 46 | sound.play(); 47 | } 48 | 49 | rotatePill() { 50 | const sound = document.getElementById("rotatepill"); 51 | sound.currentTime = 0; 52 | sound.play(); 53 | } 54 | 55 | eatBlocks() { 56 | const sound = document.getElementById("eatblocks"); 57 | sound.currentTime = 0; 58 | sound.play(); 59 | } 60 | 61 | levelClear() { 62 | const bgm = document.getElementById("bgm"); 63 | const sound = document.getElementById("levelclear"); 64 | bgm.pause(); 65 | bgm.currentTime = 0; 66 | sound.play(); 67 | setTimeout(() => { 68 | bgm.play(); 69 | }, 2500); 70 | } 71 | 72 | gameOver() { 73 | const sound = document.getElementById("gameover"); 74 | sound.play(); 75 | } 76 | 77 | } 78 | 79 | export default Audio; 80 | -------------------------------------------------------------------------------- /lib/bundle.js: -------------------------------------------------------------------------------- 1 | /******/ (function(modules) { // webpackBootstrap 2 | /******/ // The module cache 3 | /******/ var installedModules = {}; 4 | /******/ 5 | /******/ // The require function 6 | /******/ function __webpack_require__(moduleId) { 7 | /******/ 8 | /******/ // Check if module is in cache 9 | /******/ if(installedModules[moduleId]) { 10 | /******/ return installedModules[moduleId].exports; 11 | /******/ } 12 | /******/ // Create a new module (and put it into the cache) 13 | /******/ var module = installedModules[moduleId] = { 14 | /******/ i: moduleId, 15 | /******/ l: false, 16 | /******/ exports: {} 17 | /******/ }; 18 | /******/ 19 | /******/ // Execute the module function 20 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 21 | /******/ 22 | /******/ // Flag the module as loaded 23 | /******/ module.l = true; 24 | /******/ 25 | /******/ // Return the exports of the module 26 | /******/ return module.exports; 27 | /******/ } 28 | /******/ 29 | /******/ 30 | /******/ // expose the modules object (__webpack_modules__) 31 | /******/ __webpack_require__.m = modules; 32 | /******/ 33 | /******/ // expose the module cache 34 | /******/ __webpack_require__.c = installedModules; 35 | /******/ 36 | /******/ // define getter function for harmony exports 37 | /******/ __webpack_require__.d = function(exports, name, getter) { 38 | /******/ if(!__webpack_require__.o(exports, name)) { 39 | /******/ Object.defineProperty(exports, name, { 40 | /******/ configurable: false, 41 | /******/ enumerable: true, 42 | /******/ get: getter 43 | /******/ }); 44 | /******/ } 45 | /******/ }; 46 | /******/ 47 | /******/ // getDefaultExport function for compatibility with non-harmony modules 48 | /******/ __webpack_require__.n = function(module) { 49 | /******/ var getter = module && module.__esModule ? 50 | /******/ function getDefault() { return module['default']; } : 51 | /******/ function getModuleExports() { return module; }; 52 | /******/ __webpack_require__.d(getter, 'a', getter); 53 | /******/ return getter; 54 | /******/ }; 55 | /******/ 56 | /******/ // Object.prototype.hasOwnProperty.call 57 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 58 | /******/ 59 | /******/ // __webpack_public_path__ 60 | /******/ __webpack_require__.p = ""; 61 | /******/ 62 | /******/ // Load entry module and return exports 63 | /******/ return __webpack_require__(__webpack_require__.s = 1); 64 | /******/ }) 65 | /************************************************************************/ 66 | /******/ ([ 67 | /* 0 */ 68 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 69 | 70 | "use strict"; 71 | class Audio { 72 | 73 | toggleMute() { 74 | const sounds = document.getElementsByTagName("audio"); 75 | for (let i = 0; i < sounds.length; i++) { 76 | sounds[i].muted = !sounds[i].muted; 77 | } 78 | const muteButton = document.getElementById("muteicon"); 79 | if (sounds[0].muted) { 80 | muteButton.classList.remove("fa-volume-up"); 81 | muteButton.classList.add("fa-volume-off"); 82 | } else { 83 | muteButton.classList.remove("fa-volume-off"); 84 | muteButton.classList.add("fa-volume-up"); 85 | } 86 | } 87 | startGame() { 88 | const sounds = document.getElementsByTagName("audio"); 89 | for (let i = 0; i < sounds.length; i++) { 90 | sounds[i].pause(); 91 | sounds.currentTime = 0; 92 | } 93 | const sound = document.getElementById("bgm"); 94 | sound.play(); 95 | } 96 | 97 | bgmStop() { 98 | const sound = document.getElementById("bgm"); 99 | sound.pause(); 100 | sound.currentTime = 0; 101 | } 102 | 103 | pausebgm() { 104 | const sound = document.getElementById("bgm"); 105 | sound.pause(); 106 | } 107 | 108 | playbgm() { 109 | const sound = document.getElementById("bgm"); 110 | sound.play(); 111 | } 112 | 113 | movePill() { 114 | const sound = document.getElementById("movepill"); 115 | sound.currentTime = 0; 116 | sound.play(); 117 | } 118 | 119 | rotatePill() { 120 | const sound = document.getElementById("rotatepill"); 121 | sound.currentTime = 0; 122 | sound.play(); 123 | } 124 | 125 | eatBlocks() { 126 | const sound = document.getElementById("eatblocks"); 127 | sound.currentTime = 0; 128 | sound.play(); 129 | } 130 | 131 | levelClear() { 132 | const bgm = document.getElementById("bgm"); 133 | const sound = document.getElementById("levelclear"); 134 | bgm.pause(); 135 | bgm.currentTime = 0; 136 | sound.play(); 137 | setTimeout(() => { 138 | bgm.play(); 139 | }, 2500); 140 | } 141 | 142 | gameOver() { 143 | const sound = document.getElementById("gameover"); 144 | sound.play(); 145 | } 146 | 147 | } 148 | 149 | /* harmony default export */ __webpack_exports__["a"] = (Audio); 150 | 151 | 152 | /***/ }), 153 | /* 1 */ 154 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 155 | 156 | "use strict"; 157 | Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); 158 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__game__ = __webpack_require__(2); 159 | 160 | 161 | document.addEventListener("DOMContentLoaded", () => { 162 | const canvasEl = document.getElementsByTagName("canvas")[0]; 163 | canvasEl.width = __WEBPACK_IMPORTED_MODULE_0__game__["a" /* default */].DIM_X; 164 | canvasEl.height = __WEBPACK_IMPORTED_MODULE_0__game__["a" /* default */].DIM_Y; 165 | const ctx = canvasEl.getContext("2d"); 166 | 167 | let game = new __WEBPACK_IMPORTED_MODULE_0__game__["a" /* default */](ctx); 168 | game.start(); 169 | }); 170 | 171 | 172 | /***/ }), 173 | /* 2 */ 174 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 175 | 176 | "use strict"; 177 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__pill__ = __webpack_require__(3); 178 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__virus__ = __webpack_require__(4); 179 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__audio__ = __webpack_require__(0); 180 | 181 | 182 | 183 | 184 | class Game { 185 | constructor(ctx) { 186 | this.ctx = ctx; 187 | this.level = 1; 188 | this.speed = 1000; 189 | this.score = 0; 190 | this.newGame = true; 191 | this.gameOver = false; 192 | this.paused = false; 193 | this.checking = false; 194 | this.changed = false; 195 | this.currentPill = null; 196 | this.virusCount = 0; 197 | this.board = this.newBoard(ctx); 198 | this.audio = new __WEBPACK_IMPORTED_MODULE_2__audio__["a" /* default */]; 199 | } 200 | 201 | newBoard(ctx) { 202 | const board = new Array(16); 203 | for (let i = 0; i < board.length; i++) { 204 | board[i] = new Array(8); 205 | } 206 | this.randomizeViruses(ctx, board); 207 | return board; 208 | } 209 | 210 | randomizeViruses(ctx, board) { 211 | for (let i = 0; i < this.level * 10; i++) { 212 | let randomX = Math.floor(Math.random() * 8); 213 | let randomY = Math.floor(Math.random() * 12) + 4; 214 | while (board[randomY][randomX] !== undefined) { 215 | randomX = Math.floor(Math.random() * 8); 216 | randomY = Math.floor(Math.random() * 12) + 4; 217 | } 218 | const virusColor = ["yellow", "blue", "red"][Math.floor(Math.random() * 3)]; 219 | const virus = new __WEBPACK_IMPORTED_MODULE_1__virus__["a" /* default */](ctx, board, [randomY, randomX], virusColor); 220 | board[randomY][randomX] = virus; 221 | } 222 | } 223 | 224 | newPill(ctx, board) { 225 | if (this.board[0][3] !== undefined || this.board[0][4] !== undefined) { 226 | this.gameOver = true; 227 | } 228 | const pill = new __WEBPACK_IMPORTED_MODULE_0__pill__["a" /* default */](ctx, board); 229 | this.currentPill = pill; 230 | board[0][3] = pill.pill1; 231 | board[0][4] = pill.pill2; 232 | } 233 | 234 | allObjects() { 235 | return [].concat.apply([], this.board); 236 | } 237 | 238 | draw(ctx) { 239 | if (!this.paused && !this.gameOver) { 240 | ctx.clearRect(0, 0, Game.DIM_X, Game.DIM_Y); 241 | this.allObjects().forEach((object) => { 242 | if (object !== undefined) { 243 | object.draw(); 244 | } 245 | }); 246 | document.getElementById("virus").innerHTML = `Viruses Left: ${this.virusCount}`; 247 | document.getElementById("score").innerHTML = `Score: ${this.score}`; 248 | document.getElementById("level").innerHTML = `Level: ${this.level}`; 249 | } 250 | } 251 | 252 | bindKeyHandlers() { 253 | Object.keys(Game.MOVES).forEach((k) => { 254 | const move = Game.MOVES[k]; 255 | key(k, () => { 256 | this.currentPill.move(k); 257 | if (!this.currentPill.active) { 258 | this.checkBoard(); 259 | } 260 | this.draw(this.ctx); 261 | }); 262 | }); 263 | key("space", () => { this.space(); }); 264 | } 265 | 266 | space() { 267 | if (this.newGame) { 268 | this.newGame = false; 269 | this.checkBoard(); 270 | this.audio.startGame(); 271 | requestAnimationFrame(this.animate.bind(this)); 272 | } else if (!this.gameOver) { 273 | this.paused = !this.paused; 274 | this.currentPill.active = !this.currentPill.active; 275 | if (this.paused) { 276 | this.audio.pausebgm(); 277 | } else { 278 | this.audio.playbgm(); 279 | } 280 | this.ctx.font = "60px Arial"; 281 | this.ctx.fillStyle = "red"; 282 | this.ctx.fillText("PAUSED",25,300); 283 | this.ctx.strokeStyle = "white"; 284 | this.ctx.lineWidth = 2; 285 | this.ctx.strokeText("PAUSED",25,300); 286 | this.draw(this.ctx); 287 | } else { 288 | this.level = 1; 289 | this.speed = 1000; 290 | this.score = 0; 291 | this.gameOver = false; 292 | this.board = this.newBoard(this.ctx); 293 | this.checkBoard(); 294 | this.audio.startGame(); 295 | requestAnimationFrame(this.animate.bind(this)); 296 | } 297 | } 298 | 299 | start() { 300 | this.bindKeyHandlers(); 301 | requestAnimationFrame(this.animate.bind(this)); 302 | this.checkBoard(); 303 | } 304 | 305 | animate() { 306 | if (this.newGame) { 307 | document.getElementById("virus").innerHTML = `Viruses Left: ${this.virusCount}`; 308 | document.getElementById("score").innerHTML = `Score: ${this.score}`; 309 | document.getElementById("level").innerHTML = `Level: ${this.level}`; 310 | document.getElementById("mute").addEventListener("click", () => { 311 | this.audio.toggleMute(); 312 | document.getElementById("mute").blur(); 313 | }); 314 | this.ctx.font = "50px Arial"; 315 | this.ctx.fillStyle = "red"; 316 | this.ctx.fillText("Dr Mario JS",15,250); 317 | this.ctx.strokeStyle = "white"; 318 | this.ctx.lineWidth = 2; 319 | this.ctx.strokeText("Dr Mario JS",15,250); 320 | this.ctx.font = "25px Arial"; 321 | this.ctx.fillStyle = "red"; 322 | this.ctx.fillText("Hit Space to Start",45,300); 323 | this.ctx.strokeStyle = "white"; 324 | this.ctx.lineWidth = 1; 325 | this.ctx.strokeText("Hit Space to Start",45,300); 326 | } else if (this.paused) { 327 | setTimeout(() => {requestAnimationFrame(this.animate.bind(this));}, this.speed); 328 | } else if (this.checking){ 329 | setTimeout(() => {requestAnimationFrame(this.animate.bind(this));}, this.speed); 330 | } else if (this.virusCount === 0) { 331 | this.audio.levelClear(); 332 | if (this.level < 10) { 333 | this.level += 1; 334 | this.speed -= 100; 335 | } 336 | this.board = this.newBoard(this.ctx); 337 | this.checkBoard(); 338 | requestAnimationFrame(this.animate.bind(this)); 339 | } else if (this.gameOver) { 340 | this.audio.bgmStop(); 341 | this.audio.gameOver(); 342 | this.ctx.font = "50px Arial"; 343 | this.ctx.fillStyle = "red"; 344 | this.ctx.fillText("Game Over",15,250); 345 | this.ctx.strokeStyle = "white"; 346 | this.ctx.lineWidth = 2; 347 | this.ctx.strokeText("Game Over",15,250); 348 | this.ctx.font = "25px Arial"; 349 | this.ctx.fillStyle = "red"; 350 | this.ctx.fillText("Hit Space to Restart",30,300); 351 | this.ctx.strokeStyle = "white"; 352 | this.ctx.lineWidth = 1; 353 | this.ctx.strokeText("Hit Space to Restart",30,300); 354 | } else { 355 | if (!this.currentPill || !this.currentPill.active) { 356 | this.newPill(this.ctx, this.board); 357 | } else { 358 | this.currentPill.drop(); 359 | if (!this.currentPill.active) { 360 | this.checkBoard(); 361 | } 362 | } 363 | 364 | this.draw(this.ctx); 365 | 366 | setTimeout(() => {requestAnimationFrame(this.animate.bind(this));}, this.speed); 367 | } 368 | } 369 | 370 | checkBoard() { 371 | this.checking = true; 372 | this.checkCols(); 373 | this.checkRows(); 374 | if (this.changed) { 375 | this.changed = false; 376 | this.dropPills(); 377 | setTimeout(() => {this.checkBoard();}, 500); 378 | } else { 379 | this.checking = false; 380 | } 381 | } 382 | 383 | dropPills() { 384 | const transposedBoard = []; 385 | for (var i = 0; i < 8; i++) { 386 | const newRow = []; 387 | for (var j = 15; j >= 0; j--) { 388 | newRow.push(this.board[j][i]); 389 | } 390 | transposedBoard.push(newRow); 391 | } 392 | 393 | for (i = 0; i < transposedBoard.length; i++) { 394 | for (j = 1; j < transposedBoard[i].length; j++) { 395 | if (transposedBoard[i][j] !== undefined && 396 | transposedBoard[i][j].type === "pill" && 397 | transposedBoard[i][j -1 ] === undefined) { 398 | if (transposedBoard[i][j].pair === null) { 399 | transposedBoard[i][j].drop(); 400 | transposedBoard[i][j] = undefined; 401 | this.draw(this.ctx); 402 | this.changed = true; 403 | } else if (transposedBoard[i][j].coords[1] === transposedBoard[i][j].pair.coords[1] || 404 | transposedBoard[i][j].coords[0] !== transposedBoard[i][j].pair.coords[0] || 405 | this.board[transposedBoard[i][j].pair.coords[0] + 1][transposedBoard[i][j].pair.coords[1]] === undefined) { 406 | transposedBoard[i][j].drop(); 407 | transposedBoard[i][j] = undefined; 408 | this.draw(this.ctx); 409 | this.changed = true; 410 | } 411 | } 412 | } 413 | } 414 | } 415 | 416 | checkRows() { 417 | let viruses = []; 418 | let tempRow; 419 | let currentColor; 420 | for (var i = 0; i < this.board.length; i++) { 421 | tempRow = []; 422 | currentColor = null; 423 | for (var j = 0; j < this.board[i].length; j++) { 424 | if (this.board[i][j] !== undefined) { 425 | if (this.board[i][j].type === "virus") { 426 | viruses.push([i, j]); 427 | } 428 | if (currentColor === null) { 429 | currentColor = this.board[i][j].color; 430 | } 431 | if (this.board[i][j].color === currentColor) { 432 | tempRow.push([i, j]); 433 | } 434 | if (this.board[i][j].color !== currentColor || j === 7) { 435 | currentColor = this.board[i][j].color; 436 | if (tempRow.length > 3) { 437 | tempRow.forEach((coord) => { 438 | if (this.board[coord[0]][coord[1]].type === "virus") { 439 | this.score += 100; 440 | } 441 | if (this.board[coord[0]][coord[1]].pair) { 442 | this.board[coord[0]][coord[1]].pair.pair = null; 443 | } 444 | this.board[coord[0]][coord[1]] = undefined; 445 | this.changed = true; 446 | }); 447 | this.audio.eatBlocks(); 448 | } 449 | tempRow = []; 450 | tempRow.push([i, j]); 451 | } 452 | } else { 453 | if (tempRow.length > 3) { 454 | tempRow.forEach((coord) => { 455 | if (this.board[coord[0]][coord[1]].type === "virus") { 456 | this.score += 100; 457 | } 458 | if (this.board[coord[0]][coord[1]].pair) { 459 | this.board[coord[0]][coord[1]].pair.pair = null; 460 | } 461 | this.board[coord[0]][coord[1]] = undefined; 462 | this.changed = true; 463 | }); 464 | this.audio.eatBlocks(); 465 | } 466 | tempRow = []; 467 | currentColor = null; 468 | } 469 | } 470 | } 471 | this.virusCount = viruses.length; 472 | } 473 | 474 | checkCols() { 475 | const transposedBoard = []; 476 | for (var i = 0; i < 8; i++) { 477 | const newRow = []; 478 | for (var j = 0; j < this.board.length; j++) { 479 | newRow.push(this.board[j][i]); 480 | } 481 | transposedBoard.push(newRow); 482 | } 483 | let tempCol = []; 484 | let currentColor = null; 485 | for (i = 0; i < transposedBoard.length; i++) { 486 | tempCol = []; 487 | currentColor = null; 488 | for (j = 0; j < transposedBoard[i].length; j++) { 489 | if (transposedBoard[i][j] !== undefined) { 490 | if (currentColor === null) { 491 | currentColor = transposedBoard[i][j].color; 492 | } 493 | if (transposedBoard[i][j].color === currentColor) { 494 | tempCol.push([i, j]); 495 | } 496 | if (transposedBoard[i][j].color !== currentColor || j === 15) { 497 | currentColor = transposedBoard[i][j].color; 498 | if (tempCol.length > 3) { 499 | tempCol.forEach((coord) => { 500 | if (this.board[coord[1]][coord[0]].type === "virus") { 501 | this.score += 100; 502 | } 503 | if (this.board[coord[1]][coord[0]].pair) { 504 | this.board[coord[1]][coord[0]].pair.pair = null; 505 | } 506 | this.board[coord[1]][coord[0]] = undefined; 507 | this.changed = true; 508 | }); 509 | this.audio.eatBlocks(); 510 | } 511 | tempCol = []; 512 | tempCol.push([i, j]); 513 | } 514 | } else { 515 | if (tempCol.length > 3) { 516 | tempCol.forEach((coord) => { 517 | if (this.board[coord[1]][coord[0]].type === "virus") { 518 | this.score += 100; 519 | } 520 | if (this.board[coord[1]][coord[0]].pair) { 521 | this.board[coord[1]][coord[0]].pair.pair = null; 522 | } 523 | this.board[coord[1]][coord[0]] = undefined; 524 | this.changed = true; 525 | }); 526 | this.audio.eatBlocks(); 527 | } 528 | tempCol = []; 529 | currentColor = null; 530 | } 531 | } 532 | } 533 | } 534 | 535 | 536 | 537 | } 538 | 539 | Game.DIM_X = 288; 540 | Game.DIM_Y = 576; 541 | Game.MOVES = { 542 | left: "left", 543 | right: "right", 544 | down: "down", 545 | z: "z", 546 | x: "x", 547 | }; 548 | 549 | 550 | /* harmony default export */ __webpack_exports__["a"] = (Game); 551 | 552 | 553 | /***/ }), 554 | /* 3 */ 555 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 556 | 557 | "use strict"; 558 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__audio__ = __webpack_require__(0); 559 | 560 | 561 | class Pill { 562 | constructor(ctx, board) { 563 | this.ctx = ctx; 564 | this.board = board; 565 | this.board1 = [0, 3]; 566 | this.board2 = [0, 4]; 567 | this.active = true; 568 | this.horizontal = true; 569 | this.audio = new __WEBPACK_IMPORTED_MODULE_0__audio__["a" /* default */]; 570 | 571 | this.pill1 = new PillBlock(ctx, board, [0, 3], ["yellow", "blue", "red"][Math.floor(Math.random() * 3)], "left"); 572 | this.pill2 = new PillBlock(ctx, board, [0, 4], ["yellow", "blue", "red"][Math.floor(Math.random() * 3)], "right"); 573 | this.pill1.pair = this.pill2; 574 | this.pill2.pair = this.pill1; 575 | } 576 | 577 | drop() { 578 | if ( 579 | this.board1[0] < 15 && 580 | this.board2[0] < 15 && 581 | (this.board[this.board1[0] + 1][this.board1[1]] === undefined || this.board1[0] + 1 === this.board2[0] ) && 582 | (this.board[this.board2[0] + 1][this.board2[1]] === undefined || this.board2[0] + 1=== this.board1[0] ) 583 | ) { 584 | 585 | this.board[this.board1[0]][this.board1[1]] = undefined; 586 | this.board[this.board2[0]][this.board2[1]] = undefined; 587 | 588 | this.board1[0] = this.board1[0] + 1; 589 | this.board2[0] = this.board2[0] + 1; 590 | 591 | this.board[this.board1[0]][this.board1[1]] = this.pill1; 592 | this.board[this.board2[0]][this.board2[1]] = this.pill2; 593 | 594 | this.pill1.coords = [this.board1[0], this.board1[1]]; 595 | this.pill2.coords = [this.board2[0], this.board2[1]]; 596 | } else { 597 | this.active = false; 598 | } 599 | } 600 | 601 | move(k) { 602 | if (this.active) { 603 | if (k === "down") { 604 | this.drop(); 605 | this.audio.movePill(); 606 | } 607 | if (k === "right") { 608 | if ( 609 | this.board1[1] < 7 && 610 | this.board2[1] < 7 && 611 | (this.board[this.board1[0]][this.board1[1] + 1] === undefined || this.board1[1] + 1 == this.board2[1]) && 612 | (this.board[this.board2[0]][this.board2[1] + 1] === undefined || this.board2[1] + 1 == this.board1[1]) 613 | ) { 614 | this.board[this.board1[0]][this.board1[1]] = undefined; 615 | this.board[this.board2[0]][this.board2[1]] = undefined; 616 | 617 | this.board1[1] = this.board1[1] + 1; 618 | this.board2[1] = this.board2[1] + 1; 619 | 620 | this.board[this.board1[0]][this.board1[1]] = this.pill1; 621 | this.board[this.board2[0]][this.board2[1]] = this.pill2; 622 | 623 | this.pill1.coords = [this.board1[0], this.board1[1]]; 624 | this.pill2.coords = [this.board2[0], this.board2[1]]; 625 | 626 | this.audio.movePill(); 627 | } 628 | } 629 | if (k === "left") { 630 | if ( 631 | this.board1[1] > 0 && 632 | this.board2[1] > 0 && 633 | (this.board[this.board1[0]][this.board1[1] - 1] === undefined || this.board1[1] - 1 == this.board2[1]) && 634 | (this.board[this.board2[0]][this.board2[1] - 1] === undefined || this.board2[1] - 1 == this.board1[1]) 635 | ) { 636 | 637 | this.board[this.board1[0]][this.board1[1]] = undefined; 638 | this.board[this.board2[0]][this.board2[1]] = undefined; 639 | 640 | this.board1[1] = this.board1[1] - 1; 641 | this.board2[1] = this.board2[1] - 1; 642 | 643 | this.board[this.board1[0]][this.board1[1]] = this.pill1; 644 | this.board[this.board2[0]][this.board2[1]] = this.pill2; 645 | 646 | this.pill1.coords = [this.board1[0], this.board1[1]]; 647 | this.pill2.coords = [this.board2[0], this.board2[1]]; 648 | 649 | this.audio.movePill(); 650 | } 651 | } 652 | if (k === "z") { 653 | if (this.horizontal) { 654 | if (this.board2[0] > 0 && this.board[this.board1[0] - 1][this.board1[1]] === undefined) { 655 | 656 | this.board[this.board2[0]][this.board2[1]] = undefined; 657 | this.board2[0] = this.board2[0] - 1; 658 | this.board2[1] = this.board2[1] - 1; 659 | this.board[this.board2[0]][this.board2[1]] = this.pill2; 660 | this.pill2.coords = [this.board2[0], this.board2[1]]; 661 | 662 | this.pill1.side = "bottom"; 663 | this.pill2.side = "top"; 664 | 665 | this.horizontal = false; 666 | 667 | this.audio.rotatePill(); 668 | } 669 | } else { 670 | if (this.board[this.board1[0]][this.board1[1] + 1] === undefined && this.board1[1] < 7) { 671 | this.board[this.board2[0]][this.board2[1]] = undefined; 672 | this.board2[0] = this.board2[0] + 1; 673 | this.board2[1] = this.board2[1] + 1; 674 | this.board[this.board2[0]][this.board2[1]] = this.pill2; 675 | this.pill2.coords = [this.board2[0], this.board2[1]]; 676 | 677 | const tempColor = this.pill1.color; 678 | this.pill1.color = this.pill2.color; 679 | this.pill2.color = tempColor; 680 | 681 | this.pill1.side = "left"; 682 | this.pill2.side = "right"; 683 | 684 | this.horizontal = true; 685 | 686 | this.audio.rotatePill(); 687 | } 688 | } 689 | } 690 | if (k === "x") { 691 | if (this.horizontal) { 692 | if (this.board2[0] > 0 && this.board[this.board1[0] - 1][this.board1[1]] === undefined) { 693 | this.board[this.board2[0]][this.board2[1]] = undefined; 694 | this.board2[0] = this.board2[0] - 1; 695 | this.board2[1] = this.board2[1] - 1; 696 | this.board[this.board2[0]][this.board2[1]] = this.pill2; 697 | this.pill2.coords = [this.board2[0], this.board2[1]]; 698 | 699 | const tempColor = this.pill1.color; 700 | this.pill1.color = this.pill2.color; 701 | this.pill2.color = tempColor; 702 | 703 | this.pill1.side = "bottom"; 704 | this.pill2.side = "top"; 705 | 706 | this.horizontal = false; 707 | 708 | this.audio.rotatePill(); 709 | } 710 | } else { 711 | if (this.board[this.board1[0]][this.board1[1] + 1] === undefined && this.board1[1] < 7) { 712 | this.board[this.board2[0]][this.board2[1]] = undefined; 713 | this.board2[0] = this.board2[0] + 1; 714 | this.board2[1] = this.board2[1] + 1; 715 | this.board[this.board2[0]][this.board2[1]] = this.pill2; 716 | this.pill2.coords = [this.board2[0], this.board2[1]]; 717 | 718 | this.pill1.side = "left"; 719 | this.pill2.side = "right"; 720 | 721 | this.horizontal = true; 722 | 723 | this.audio.rotatePill(); 724 | } 725 | } 726 | } 727 | } 728 | 729 | } 730 | } 731 | 732 | class PillBlock { 733 | constructor(ctx, board, coords, color, side){ 734 | this.ctx = ctx; 735 | this.board = board; 736 | this.coords = coords; 737 | this.color = color; 738 | this.type = "pill"; 739 | this.pair = null; 740 | this.side = side; 741 | } 742 | 743 | draw() { 744 | let img = new Image(); 745 | let x = (this.coords[1] * 36); 746 | let y = (this.coords[0] * 36); 747 | let w = 32; 748 | let h = 32; 749 | let degrees = -90; 750 | if (this.pair === null) { 751 | img.src = `images/pill${this.color}.png`; 752 | this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 32, 32); 753 | img.onload = () => { 754 | this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 32, 32); 755 | }; 756 | } else if (this.side === "left") { 757 | img.src = `images/pill${this.color}left.png`; 758 | this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 32, 32); 759 | img.onload = () => { 760 | this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 32, 32); 761 | }; 762 | } else if (this.side === "right"){ 763 | img.src = `images/pill${this.color}right.png`; 764 | this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 32, 32); 765 | img.onload = () => { 766 | this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 32, 32); 767 | }; 768 | } else if (this.side === "top"){ 769 | img.src = `images/pill${this.color}right.png`; 770 | 771 | this.ctx.save(); 772 | this.ctx.translate(x+w/2, y+h/2); 773 | this.ctx.rotate(degrees*Math.PI/180.0); 774 | this.ctx.translate(-x-w/2, -y-h/2); 775 | this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 32, 32); 776 | this.ctx.restore(); 777 | img.onload = () => { 778 | this.ctx.save(); 779 | this.ctx.translate(x+w/2, y+h/2); 780 | this.ctx.rotate(degrees*Math.PI/180.0); 781 | this.ctx.translate(-x-w/2, -y-h/2); 782 | this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 32, 32); 783 | this.ctx.restore(); 784 | }; 785 | } else if (this.side === "bottom"){ 786 | img.src = `images/pill${this.color}left.png`; 787 | 788 | this.ctx.save(); 789 | this.ctx.translate(x+w/2, y+h/2); 790 | this.ctx.rotate(degrees*Math.PI/180.0); 791 | this.ctx.translate(-x-w/2, -y-h/2); 792 | this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 32, 32); 793 | this.ctx.restore(); 794 | img.onload = () => { 795 | this.ctx.save(); 796 | this.ctx.translate(x+w/2, y+h/2); 797 | this.ctx.rotate(degrees*Math.PI/180.0); 798 | this.ctx.translate(-x-w/2, -y-h/2); 799 | this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 32, 32); 800 | this.ctx.restore(); 801 | }; 802 | } 803 | } 804 | 805 | drop() { 806 | if ( 807 | this.coords[0] < 15 && 808 | this.board[this.coords[0] + 1][this.coords[1]] === undefined 809 | ) { 810 | this.board[this.coords[0]][this.coords[1]] = undefined; 811 | this.coords[0] = this.coords[0] + 1; 812 | this.board[this.coords[0]][this.coords[1]] = this; 813 | } 814 | } 815 | } 816 | 817 | 818 | /* harmony default export */ __webpack_exports__["a"] = (Pill); 819 | 820 | 821 | /***/ }), 822 | /* 4 */ 823 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 824 | 825 | "use strict"; 826 | class Virus { 827 | constructor(ctx, board, coords, color){ 828 | this.ctx = ctx; 829 | this.board = board; 830 | this.coords = coords; 831 | this.color = color; 832 | this.type = "virus"; 833 | this.pair = null; 834 | } 835 | 836 | draw() { 837 | this.board[this.coords[0]][this.coords[1]] = this; 838 | 839 | let img = new Image(); 840 | img.src = `images/virus${this.color}.png`; 841 | this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 36, 36); 842 | img.onload = () => { 843 | this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 36, 36); 844 | }; 845 | } 846 | } 847 | 848 | /* harmony default export */ __webpack_exports__["a"] = (Virus); 849 | 850 | 851 | /***/ }) 852 | /******/ ]); 853 | //# sourceMappingURL=bundle.js.map -------------------------------------------------------------------------------- /lib/bundle.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack:///webpack/bootstrap cdcbe3fba067e32c6047","webpack:///./lib/audio.js","webpack:///./lib/drmariojs.js","webpack:///./lib/game.js","webpack:///./lib/pill.js","webpack:///./lib/virus.js"],"names":[],"mappings":";AAAA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;AAEA;AACA;;;;;;;;AC7DA;;AAEA;AACA;AACA,mBAAmB,mBAAmB;AACtC;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,mBAAmB,mBAAmB;AACtC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;;;;;;;;;AC9EA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,CAAC;;;;;;;;;;;ACVD;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,mBAAmB,kBAAkB;AACrC;AACA;AACA;AACA;AACA;;AAEA;AACA,mBAAmB,qBAAqB;AACxC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP,oEAAoE,gBAAgB;AACpF,6DAA6D,WAAW;AACxE,6DAA6D,WAAW;AACxE;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP,KAAK;AACL,wBAAwB,cAAc,EAAE;AACxC;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,oEAAoE,gBAAgB;AACpF,6DAA6D,WAAW;AACxE,6DAA6D,WAAW;AACxE;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL,wBAAwB,gDAAgD;AACxE,KAAK;AACL,wBAAwB,gDAAgD;AACxE,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;;AAEA;;AAEA,wBAAwB,gDAAgD;AACxE;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,mBAAmB;AAC3C,KAAK;AACL;AACA;AACA;;AAEA;AACA;AACA,mBAAmB,OAAO;AAC1B;AACA,sBAAsB,QAAQ;AAC9B;AACA;AACA;AACA;;AAEA,eAAe,4BAA4B;AAC3C,iBAAiB,+BAA+B;AAChD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,mBAAmB,uBAAuB;AAC1C;AACA;AACA,qBAAqB,0BAA0B;AAC/C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,mBAAmB,OAAO;AAC1B;AACA,qBAAqB,uBAAuB;AAC5C;AACA;AACA;AACA;AACA;AACA;AACA,eAAe,4BAA4B;AAC3C;AACA;AACA,iBAAiB,+BAA+B;AAChD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;AAIA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;;;;;;;;;AClXA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,KAAK;AACL;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA,WAAW;AACX;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA,WAAW;AACX;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8BAA8B,WAAW;AACzC;AACA;AACA;AACA;AACA,KAAK;AACL,8BAA8B,WAAW;AACzC;AACA;AACA;AACA;AACA,KAAK;AACL,8BAA8B,WAAW;AACzC;AACA;AACA;AACA;AACA,KAAK;AACL,8BAA8B,WAAW;;AAEzC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL,8BAA8B,WAAW;;AAEzC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;;;;;;;;ACnQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA,6BAA6B,WAAW;AACxC;AACA;AACA;AACA;AACA;AACA;;AAEA","file":"./lib/bundle.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 1);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap cdcbe3fba067e32c6047","class Audio {\n\n toggleMute() {\n const sounds = document.getElementsByTagName(\"audio\");\n for (let i = 0; i < sounds.length; i++) {\n sounds[i].muted = !sounds[i].muted;\n }\n const muteButton = document.getElementById(\"muteicon\");\n if (sounds[0].muted) {\n muteButton.classList.remove(\"fa-volume-up\");\n muteButton.classList.add(\"fa-volume-off\");\n } else {\n muteButton.classList.remove(\"fa-volume-off\");\n muteButton.classList.add(\"fa-volume-up\");\n }\n }\n startGame() {\n const sounds = document.getElementsByTagName(\"audio\");\n for (let i = 0; i < sounds.length; i++) {\n sounds[i].pause();\n sounds.currentTime = 0;\n }\n const sound = document.getElementById(\"bgm\");\n sound.play();\n }\n\n bgmStop() {\n const sound = document.getElementById(\"bgm\");\n sound.pause();\n sound.currentTime = 0;\n }\n\n pausebgm() {\n const sound = document.getElementById(\"bgm\");\n sound.pause();\n }\n\n playbgm() {\n const sound = document.getElementById(\"bgm\");\n sound.play();\n }\n\n movePill() {\n const sound = document.getElementById(\"movepill\");\n sound.currentTime = 0;\n sound.play();\n }\n\n rotatePill() {\n const sound = document.getElementById(\"rotatepill\");\n sound.currentTime = 0;\n sound.play();\n }\n\n eatBlocks() {\n const sound = document.getElementById(\"eatblocks\");\n sound.currentTime = 0;\n sound.play();\n }\n\n levelClear() {\n const bgm = document.getElementById(\"bgm\");\n const sound = document.getElementById(\"levelclear\");\n bgm.pause();\n bgm.currentTime = 0;\n sound.play();\n setTimeout(() => {\n bgm.play();\n }, 2500);\n }\n\n gameOver() {\n const sound = document.getElementById(\"gameover\");\n sound.play();\n }\n\n}\n\nexport default Audio;\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./lib/audio.js\n// module id = 0\n// module chunks = 0","import Game from './game';\n\ndocument.addEventListener(\"DOMContentLoaded\", () => {\n const canvasEl = document.getElementsByTagName(\"canvas\")[0];\n canvasEl.width = Game.DIM_X;\n canvasEl.height = Game.DIM_Y;\n const ctx = canvasEl.getContext(\"2d\");\n\n let game = new Game(ctx);\n game.start();\n});\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./lib/drmariojs.js\n// module id = 1\n// module chunks = 0","import Pill from './pill';\nimport Virus from './virus';\nimport Audio from './audio';\n\nclass Game {\n constructor(ctx) {\n this.ctx = ctx;\n this.level = 1;\n this.speed = 1000;\n this.score = 0;\n this.newGame = true;\n this.gameOver = false;\n this.paused = false;\n this.checking = false;\n this.changed = false;\n this.currentPill = null;\n this.virusCount = 0;\n this.board = this.newBoard(ctx);\n this.audio = new Audio;\n }\n\n newBoard(ctx) {\n const board = new Array(16);\n for (let i = 0; i < board.length; i++) {\n board[i] = new Array(8);\n }\n this.randomizeViruses(ctx, board);\n return board;\n }\n\n randomizeViruses(ctx, board) {\n for (let i = 0; i < this.level * 10; i++) {\n let randomX = Math.floor(Math.random() * 8);\n let randomY = Math.floor(Math.random() * 12) + 4;\n while (board[randomY][randomX] !== undefined) {\n randomX = Math.floor(Math.random() * 8);\n randomY = Math.floor(Math.random() * 12) + 4;\n }\n const virusColor = [\"yellow\", \"blue\", \"red\"][Math.floor(Math.random() * 3)];\n const virus = new Virus(ctx, board, [randomY, randomX], virusColor);\n board[randomY][randomX] = virus;\n }\n }\n\n newPill(ctx, board) {\n if (this.board[0][3] !== undefined || this.board[0][4] !== undefined) {\n this.gameOver = true;\n }\n const pill = new Pill(ctx, board);\n this.currentPill = pill;\n board[0][3] = pill.pill1;\n board[0][4] = pill.pill2;\n }\n\n allObjects() {\n return [].concat.apply([], this.board);\n }\n\n draw(ctx) {\n if (!this.paused && !this.gameOver) {\n ctx.clearRect(0, 0, Game.DIM_X, Game.DIM_Y);\n this.allObjects().forEach((object) => {\n if (object !== undefined) {\n object.draw();\n }\n });\n document.getElementById(\"virus\").innerHTML = `Viruses Left: ${this.virusCount}`;\n document.getElementById(\"score\").innerHTML = `Score: ${this.score}`;\n document.getElementById(\"level\").innerHTML = `Level: ${this.level}`;\n }\n }\n\n bindKeyHandlers() {\n Object.keys(Game.MOVES).forEach((k) => {\n const move = Game.MOVES[k];\n key(k, () => {\n this.currentPill.move(k);\n if (!this.currentPill.active) {\n this.checkBoard();\n }\n this.draw(this.ctx);\n });\n });\n key(\"space\", () => { this.space(); });\n }\n\n space() {\n if (this.newGame) {\n this.newGame = false;\n this.checkBoard();\n this.audio.startGame();\n requestAnimationFrame(this.animate.bind(this));\n } else if (!this.gameOver) {\n this.paused = !this.paused;\n this.currentPill.active = !this.currentPill.active;\n if (this.paused) {\n this.audio.pausebgm();\n } else {\n this.audio.playbgm();\n }\n this.ctx.font = \"60px Arial\";\n this.ctx.fillStyle = \"red\";\n this.ctx.fillText(\"PAUSED\",25,300);\n this.ctx.strokeStyle = \"white\";\n this.ctx.lineWidth = 2;\n this.ctx.strokeText(\"PAUSED\",25,300);\n this.draw(this.ctx);\n } else {\n this.level = 1;\n this.speed = 1000;\n this.score = 0;\n this.gameOver = false;\n this.board = this.newBoard(this.ctx);\n this.checkBoard();\n this.audio.startGame();\n requestAnimationFrame(this.animate.bind(this));\n }\n }\n\n start() {\n this.bindKeyHandlers();\n requestAnimationFrame(this.animate.bind(this));\n this.checkBoard();\n }\n\n animate() {\n if (this.newGame) {\n document.getElementById(\"virus\").innerHTML = `Viruses Left: ${this.virusCount}`;\n document.getElementById(\"score\").innerHTML = `Score: ${this.score}`;\n document.getElementById(\"level\").innerHTML = `Level: ${this.level}`;\n document.getElementById(\"mute\").addEventListener(\"click\", () => {\n this.audio.toggleMute();\n document.getElementById(\"mute\").blur();\n });\n this.ctx.font = \"50px Arial\";\n this.ctx.fillStyle = \"red\";\n this.ctx.fillText(\"Dr Mario JS\",15,250);\n this.ctx.strokeStyle = \"white\";\n this.ctx.lineWidth = 2;\n this.ctx.strokeText(\"Dr Mario JS\",15,250);\n this.ctx.font = \"25px Arial\";\n this.ctx.fillStyle = \"red\";\n this.ctx.fillText(\"Hit Space to Start\",45,300);\n this.ctx.strokeStyle = \"white\";\n this.ctx.lineWidth = 1;\n this.ctx.strokeText(\"Hit Space to Start\",45,300);\n } else if (this.paused) {\n setTimeout(() => {requestAnimationFrame(this.animate.bind(this));}, this.speed);\n } else if (this.checking){\n setTimeout(() => {requestAnimationFrame(this.animate.bind(this));}, this.speed);\n } else if (this.virusCount === 0) {\n this.audio.levelClear();\n if (this.level < 10) {\n this.level += 1;\n this.speed -= 100;\n }\n this.board = this.newBoard(this.ctx);\n this.checkBoard();\n requestAnimationFrame(this.animate.bind(this));\n } else if (this.gameOver) {\n this.audio.bgmStop();\n this.audio.gameOver();\n this.ctx.font = \"50px Arial\";\n this.ctx.fillStyle = \"red\";\n this.ctx.fillText(\"Game Over\",15,250);\n this.ctx.strokeStyle = \"white\";\n this.ctx.lineWidth = 2;\n this.ctx.strokeText(\"Game Over\",15,250);\n this.ctx.font = \"25px Arial\";\n this.ctx.fillStyle = \"red\";\n this.ctx.fillText(\"Hit Space to Restart\",30,300);\n this.ctx.strokeStyle = \"white\";\n this.ctx.lineWidth = 1;\n this.ctx.strokeText(\"Hit Space to Restart\",30,300);\n } else {\n if (!this.currentPill || !this.currentPill.active) {\n this.newPill(this.ctx, this.board);\n } else {\n this.currentPill.drop();\n if (!this.currentPill.active) {\n this.checkBoard();\n }\n }\n\n this.draw(this.ctx);\n\n setTimeout(() => {requestAnimationFrame(this.animate.bind(this));}, this.speed);\n }\n }\n\n checkBoard() {\n this.checking = true;\n this.checkCols();\n this.checkRows();\n if (this.changed) {\n this.changed = false;\n this.dropPills();\n setTimeout(() => {this.checkBoard();}, 500);\n } else {\n this.checking = false;\n }\n }\n\n dropPills() {\n const transposedBoard = [];\n for (var i = 0; i < 8; i++) {\n const newRow = [];\n for (var j = 15; j >= 0; j--) {\n newRow.push(this.board[j][i]);\n }\n transposedBoard.push(newRow);\n }\n\n for (i = 0; i < transposedBoard.length; i++) {\n for (j = 1; j < transposedBoard[i].length; j++) {\n if (transposedBoard[i][j] !== undefined &&\n transposedBoard[i][j].type === \"pill\" &&\n transposedBoard[i][j -1 ] === undefined) {\n if (transposedBoard[i][j].pair === null) {\n transposedBoard[i][j].drop();\n transposedBoard[i][j] = undefined;\n this.draw(this.ctx);\n this.changed = true;\n } else if (transposedBoard[i][j].coords[1] === transposedBoard[i][j].pair.coords[1] ||\n transposedBoard[i][j].coords[0] !== transposedBoard[i][j].pair.coords[0] ||\n this.board[transposedBoard[i][j].pair.coords[0] + 1][transposedBoard[i][j].pair.coords[1]] === undefined) {\n transposedBoard[i][j].drop();\n transposedBoard[i][j] = undefined;\n this.draw(this.ctx);\n this.changed = true;\n }\n }\n }\n }\n }\n\n checkRows() {\n let viruses = [];\n let tempRow;\n let currentColor;\n for (var i = 0; i < this.board.length; i++) {\n tempRow = [];\n currentColor = null;\n for (var j = 0; j < this.board[i].length; j++) {\n if (this.board[i][j] !== undefined) {\n if (this.board[i][j].type === \"virus\") {\n viruses.push([i, j]);\n }\n if (currentColor === null) {\n currentColor = this.board[i][j].color;\n }\n if (this.board[i][j].color === currentColor) {\n tempRow.push([i, j]);\n }\n if (this.board[i][j].color !== currentColor || j === 7) {\n currentColor = this.board[i][j].color;\n if (tempRow.length > 3) {\n tempRow.forEach((coord) => {\n if (this.board[coord[0]][coord[1]].type === \"virus\") {\n this.score += 100;\n }\n if (this.board[coord[0]][coord[1]].pair) {\n this.board[coord[0]][coord[1]].pair.pair = null;\n }\n this.board[coord[0]][coord[1]] = undefined;\n this.changed = true;\n });\n this.audio.eatBlocks();\n }\n tempRow = [];\n tempRow.push([i, j]);\n }\n } else {\n if (tempRow.length > 3) {\n tempRow.forEach((coord) => {\n if (this.board[coord[0]][coord[1]].type === \"virus\") {\n this.score += 100;\n }\n if (this.board[coord[0]][coord[1]].pair) {\n this.board[coord[0]][coord[1]].pair.pair = null;\n }\n this.board[coord[0]][coord[1]] = undefined;\n this.changed = true;\n });\n this.audio.eatBlocks();\n }\n tempRow = [];\n currentColor = null;\n }\n }\n }\n this.virusCount = viruses.length;\n }\n\n checkCols() {\n const transposedBoard = [];\n for (var i = 0; i < 8; i++) {\n const newRow = [];\n for (var j = 0; j < this.board.length; j++) {\n newRow.push(this.board[j][i]);\n }\n transposedBoard.push(newRow);\n }\n let tempCol = [];\n let currentColor = null;\n for (i = 0; i < transposedBoard.length; i++) {\n tempCol = [];\n currentColor = null;\n for (j = 0; j < transposedBoard[i].length; j++) {\n if (transposedBoard[i][j] !== undefined) {\n if (currentColor === null) {\n currentColor = transposedBoard[i][j].color;\n }\n if (transposedBoard[i][j].color === currentColor) {\n tempCol.push([i, j]);\n }\n if (transposedBoard[i][j].color !== currentColor || j === 15) {\n currentColor = transposedBoard[i][j].color;\n if (tempCol.length > 3) {\n tempCol.forEach((coord) => {\n if (this.board[coord[1]][coord[0]].type === \"virus\") {\n this.score += 100;\n }\n if (this.board[coord[1]][coord[0]].pair) {\n this.board[coord[1]][coord[0]].pair.pair = null;\n }\n this.board[coord[1]][coord[0]] = undefined;\n this.changed = true;\n });\n this.audio.eatBlocks();\n }\n tempCol = [];\n tempCol.push([i, j]);\n }\n } else {\n if (tempCol.length > 3) {\n tempCol.forEach((coord) => {\n if (this.board[coord[1]][coord[0]].type === \"virus\") {\n this.score += 100;\n }\n if (this.board[coord[1]][coord[0]].pair) {\n this.board[coord[1]][coord[0]].pair.pair = null;\n }\n this.board[coord[1]][coord[0]] = undefined;\n this.changed = true;\n });\n this.audio.eatBlocks();\n }\n tempCol = [];\n currentColor = null;\n }\n }\n }\n }\n\n\n\n}\n\nGame.DIM_X = 288;\nGame.DIM_Y = 576;\nGame.MOVES = {\n left: \"left\",\n right: \"right\",\n down: \"down\",\n z: \"z\",\n x: \"x\",\n};\n\n\nexport default Game;\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./lib/game.js\n// module id = 2\n// module chunks = 0","import Audio from './audio';\n\nclass Pill {\n constructor(ctx, board) {\n this.ctx = ctx;\n this.board = board;\n this.board1 = [0, 3];\n this.board2 = [0, 4];\n this.active = true;\n this.horizontal = true;\n this.audio = new Audio;\n\n this.pill1 = new PillBlock(ctx, board, [0, 3], [\"yellow\", \"blue\", \"red\"][Math.floor(Math.random() * 3)], \"left\");\n this.pill2 = new PillBlock(ctx, board, [0, 4], [\"yellow\", \"blue\", \"red\"][Math.floor(Math.random() * 3)], \"right\");\n this.pill1.pair = this.pill2;\n this.pill2.pair = this.pill1;\n }\n\n drop() {\n if (\n this.board1[0] < 15 &&\n this.board2[0] < 15 &&\n (this.board[this.board1[0] + 1][this.board1[1]] === undefined || this.board1[0] + 1 === this.board2[0] ) &&\n (this.board[this.board2[0] + 1][this.board2[1]] === undefined || this.board2[0] + 1=== this.board1[0] )\n ) {\n\n this.board[this.board1[0]][this.board1[1]] = undefined;\n this.board[this.board2[0]][this.board2[1]] = undefined;\n\n this.board1[0] = this.board1[0] + 1;\n this.board2[0] = this.board2[0] + 1;\n\n this.board[this.board1[0]][this.board1[1]] = this.pill1;\n this.board[this.board2[0]][this.board2[1]] = this.pill2;\n\n this.pill1.coords = [this.board1[0], this.board1[1]];\n this.pill2.coords = [this.board2[0], this.board2[1]];\n } else {\n this.active = false;\n }\n }\n\n move(k) {\n if (this.active) {\n if (k === \"down\") {\n this.drop();\n this.audio.movePill();\n }\n if (k === \"right\") {\n if (\n this.board1[1] < 7 &&\n this.board2[1] < 7 &&\n (this.board[this.board1[0]][this.board1[1] + 1] === undefined || this.board1[1] + 1 == this.board2[1]) &&\n (this.board[this.board2[0]][this.board2[1] + 1] === undefined || this.board2[1] + 1 == this.board1[1])\n ) {\n this.board[this.board1[0]][this.board1[1]] = undefined;\n this.board[this.board2[0]][this.board2[1]] = undefined;\n\n this.board1[1] = this.board1[1] + 1;\n this.board2[1] = this.board2[1] + 1;\n\n this.board[this.board1[0]][this.board1[1]] = this.pill1;\n this.board[this.board2[0]][this.board2[1]] = this.pill2;\n\n this.pill1.coords = [this.board1[0], this.board1[1]];\n this.pill2.coords = [this.board2[0], this.board2[1]];\n\n this.audio.movePill();\n }\n }\n if (k === \"left\") {\n if (\n this.board1[1] > 0 &&\n this.board2[1] > 0 &&\n (this.board[this.board1[0]][this.board1[1] - 1] === undefined || this.board1[1] - 1 == this.board2[1]) &&\n (this.board[this.board2[0]][this.board2[1] - 1] === undefined || this.board2[1] - 1 == this.board1[1])\n ) {\n\n this.board[this.board1[0]][this.board1[1]] = undefined;\n this.board[this.board2[0]][this.board2[1]] = undefined;\n\n this.board1[1] = this.board1[1] - 1;\n this.board2[1] = this.board2[1] - 1;\n\n this.board[this.board1[0]][this.board1[1]] = this.pill1;\n this.board[this.board2[0]][this.board2[1]] = this.pill2;\n\n this.pill1.coords = [this.board1[0], this.board1[1]];\n this.pill2.coords = [this.board2[0], this.board2[1]];\n\n this.audio.movePill();\n }\n }\n if (k === \"z\") {\n if (this.horizontal) {\n if (this.board2[0] > 0 && this.board[this.board1[0] - 1][this.board1[1]] === undefined) {\n\n this.board[this.board2[0]][this.board2[1]] = undefined;\n this.board2[0] = this.board2[0] - 1;\n this.board2[1] = this.board2[1] - 1;\n this.board[this.board2[0]][this.board2[1]] = this.pill2;\n this.pill2.coords = [this.board2[0], this.board2[1]];\n\n this.pill1.side = \"bottom\";\n this.pill2.side = \"top\";\n\n this.horizontal = false;\n\n this.audio.rotatePill();\n }\n } else {\n if (this.board[this.board1[0]][this.board1[1] + 1] === undefined && this.board1[1] < 7) {\n this.board[this.board2[0]][this.board2[1]] = undefined;\n this.board2[0] = this.board2[0] + 1;\n this.board2[1] = this.board2[1] + 1;\n this.board[this.board2[0]][this.board2[1]] = this.pill2;\n this.pill2.coords = [this.board2[0], this.board2[1]];\n\n const tempColor = this.pill1.color;\n this.pill1.color = this.pill2.color;\n this.pill2.color = tempColor;\n\n this.pill1.side = \"left\";\n this.pill2.side = \"right\";\n\n this.horizontal = true;\n\n this.audio.rotatePill();\n }\n }\n }\n if (k === \"x\") {\n if (this.horizontal) {\n if (this.board2[0] > 0 && this.board[this.board1[0] - 1][this.board1[1]] === undefined) {\n this.board[this.board2[0]][this.board2[1]] = undefined;\n this.board2[0] = this.board2[0] - 1;\n this.board2[1] = this.board2[1] - 1;\n this.board[this.board2[0]][this.board2[1]] = this.pill2;\n this.pill2.coords = [this.board2[0], this.board2[1]];\n\n const tempColor = this.pill1.color;\n this.pill1.color = this.pill2.color;\n this.pill2.color = tempColor;\n\n this.pill1.side = \"bottom\";\n this.pill2.side = \"top\";\n\n this.horizontal = false;\n\n this.audio.rotatePill();\n }\n } else {\n if (this.board[this.board1[0]][this.board1[1] + 1] === undefined && this.board1[1] < 7) {\n this.board[this.board2[0]][this.board2[1]] = undefined;\n this.board2[0] = this.board2[0] + 1;\n this.board2[1] = this.board2[1] + 1;\n this.board[this.board2[0]][this.board2[1]] = this.pill2;\n this.pill2.coords = [this.board2[0], this.board2[1]];\n\n this.pill1.side = \"left\";\n this.pill2.side = \"right\";\n\n this.horizontal = true;\n\n this.audio.rotatePill();\n }\n }\n }\n }\n\n }\n}\n\nclass PillBlock {\n constructor(ctx, board, coords, color, side){\n this.ctx = ctx;\n this.board = board;\n this.coords = coords;\n this.color = color;\n this.type = \"pill\";\n this.pair = null;\n this.side = side;\n }\n\n draw() {\n let img = new Image();\n let x = (this.coords[1] * 36);\n let y = (this.coords[0] * 36);\n let w = 32;\n let h = 32;\n let degrees = -90;\n if (this.pair === null) {\n img.src = `images/pill${this.color}.png`;\n this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 32, 32);\n img.onload = () => {\n this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 32, 32);\n };\n } else if (this.side === \"left\") {\n img.src = `images/pill${this.color}left.png`;\n this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 32, 32);\n img.onload = () => {\n this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 32, 32);\n };\n } else if (this.side === \"right\"){\n img.src = `images/pill${this.color}right.png`;\n this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 32, 32);\n img.onload = () => {\n this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 32, 32);\n };\n } else if (this.side === \"top\"){\n img.src = `images/pill${this.color}right.png`;\n\n this.ctx.save();\n this.ctx.translate(x+w/2, y+h/2);\n this.ctx.rotate(degrees*Math.PI/180.0);\n this.ctx.translate(-x-w/2, -y-h/2);\n this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 32, 32);\n this.ctx.restore();\n img.onload = () => {\n this.ctx.save();\n this.ctx.translate(x+w/2, y+h/2);\n this.ctx.rotate(degrees*Math.PI/180.0);\n this.ctx.translate(-x-w/2, -y-h/2);\n this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 32, 32);\n this.ctx.restore();\n };\n } else if (this.side === \"bottom\"){\n img.src = `images/pill${this.color}left.png`;\n\n this.ctx.save();\n this.ctx.translate(x+w/2, y+h/2);\n this.ctx.rotate(degrees*Math.PI/180.0);\n this.ctx.translate(-x-w/2, -y-h/2);\n this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 32, 32);\n this.ctx.restore();\n img.onload = () => {\n this.ctx.save();\n this.ctx.translate(x+w/2, y+h/2);\n this.ctx.rotate(degrees*Math.PI/180.0);\n this.ctx.translate(-x-w/2, -y-h/2);\n this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 32, 32);\n this.ctx.restore();\n };\n }\n }\n\n drop() {\n if (\n this.coords[0] < 15 &&\n this.board[this.coords[0] + 1][this.coords[1]] === undefined\n ) {\n this.board[this.coords[0]][this.coords[1]] = undefined;\n this.coords[0] = this.coords[0] + 1;\n this.board[this.coords[0]][this.coords[1]] = this;\n }\n }\n}\n\n\nexport default Pill;\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./lib/pill.js\n// module id = 3\n// module chunks = 0","class Virus {\n constructor(ctx, board, coords, color){\n this.ctx = ctx;\n this.board = board;\n this.coords = coords;\n this.color = color;\n this.type = \"virus\";\n this.pair = null;\n }\n\n draw() {\n this.board[this.coords[0]][this.coords[1]] = this;\n\n let img = new Image();\n img.src = `images/virus${this.color}.png`;\n this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 36, 36);\n img.onload = () => {\n this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 36, 36);\n };\n }\n}\n\nexport default Virus;\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./lib/virus.js\n// module id = 4\n// module chunks = 0"],"sourceRoot":""} -------------------------------------------------------------------------------- /lib/drmariojs.js: -------------------------------------------------------------------------------- 1 | import Game from './game'; 2 | 3 | document.addEventListener("DOMContentLoaded", () => { 4 | const canvasEl = document.getElementsByTagName("canvas")[0]; 5 | canvasEl.width = Game.DIM_X; 6 | canvasEl.height = Game.DIM_Y; 7 | const ctx = canvasEl.getContext("2d"); 8 | 9 | let game = new Game(ctx); 10 | game.start(); 11 | }); 12 | -------------------------------------------------------------------------------- /lib/game.js: -------------------------------------------------------------------------------- 1 | import Pill from './pill'; 2 | import Virus from './virus'; 3 | import Audio from './audio'; 4 | 5 | class Game { 6 | constructor(ctx) { 7 | this.ctx = ctx; 8 | this.level = 1; 9 | this.speed = 1000; 10 | this.score = 0; 11 | this.newGame = true; 12 | this.gameOver = false; 13 | this.paused = false; 14 | this.checking = false; 15 | this.changed = false; 16 | this.currentPill = null; 17 | this.virusCount = 0; 18 | this.board = this.newBoard(ctx); 19 | this.audio = new Audio; 20 | } 21 | 22 | newBoard(ctx) { 23 | const board = new Array(16); 24 | for (let i = 0; i < board.length; i++) { 25 | board[i] = new Array(8); 26 | } 27 | this.randomizeViruses(ctx, board); 28 | return board; 29 | } 30 | 31 | randomizeViruses(ctx, board) { 32 | for (let i = 0; i < this.level * 10; i++) { 33 | let randomX = Math.floor(Math.random() * 8); 34 | let randomY = Math.floor(Math.random() * 12) + 4; 35 | while (board[randomY][randomX] !== undefined) { 36 | randomX = Math.floor(Math.random() * 8); 37 | randomY = Math.floor(Math.random() * 12) + 4; 38 | } 39 | const virusColor = ["yellow", "blue", "red"][Math.floor(Math.random() * 3)]; 40 | const virus = new Virus(ctx, board, [randomY, randomX], virusColor); 41 | board[randomY][randomX] = virus; 42 | } 43 | } 44 | 45 | newPill(ctx, board) { 46 | if (this.board[0][3] !== undefined || this.board[0][4] !== undefined) { 47 | this.gameOver = true; 48 | } 49 | const pill = new Pill(ctx, board); 50 | this.currentPill = pill; 51 | board[0][3] = pill.pill1; 52 | board[0][4] = pill.pill2; 53 | } 54 | 55 | allObjects() { 56 | return [].concat.apply([], this.board); 57 | } 58 | 59 | draw(ctx) { 60 | if (!this.paused && !this.gameOver) { 61 | ctx.clearRect(0, 0, Game.DIM_X, Game.DIM_Y); 62 | this.allObjects().forEach((object) => { 63 | if (object !== undefined) { 64 | object.draw(); 65 | } 66 | }); 67 | document.getElementById("virus").innerHTML = `Viruses Left: ${this.virusCount}`; 68 | document.getElementById("score").innerHTML = `Score: ${this.score}`; 69 | document.getElementById("level").innerHTML = `Level: ${this.level}`; 70 | } 71 | } 72 | 73 | bindKeyHandlers() { 74 | Object.keys(Game.MOVES).forEach((k) => { 75 | const move = Game.MOVES[k]; 76 | key(k, () => { 77 | this.currentPill.move(k); 78 | if (!this.currentPill.active) { 79 | this.checkBoard(); 80 | } 81 | this.draw(this.ctx); 82 | }); 83 | }); 84 | key("space", () => { this.space(); }); 85 | } 86 | 87 | space() { 88 | if (this.newGame) { 89 | this.newGame = false; 90 | this.checkBoard(); 91 | this.audio.startGame(); 92 | requestAnimationFrame(this.animate.bind(this)); 93 | } else if (!this.gameOver) { 94 | this.paused = !this.paused; 95 | this.currentPill.active = !this.currentPill.active; 96 | if (this.paused) { 97 | this.audio.pausebgm(); 98 | } else { 99 | this.audio.playbgm(); 100 | } 101 | this.ctx.font = "60px Arial"; 102 | this.ctx.fillStyle = "red"; 103 | this.ctx.fillText("PAUSED",25,300); 104 | this.ctx.strokeStyle = "white"; 105 | this.ctx.lineWidth = 2; 106 | this.ctx.strokeText("PAUSED",25,300); 107 | this.draw(this.ctx); 108 | } else { 109 | this.level = 1; 110 | this.speed = 1000; 111 | this.score = 0; 112 | this.gameOver = false; 113 | this.board = this.newBoard(this.ctx); 114 | this.checkBoard(); 115 | this.audio.startGame(); 116 | requestAnimationFrame(this.animate.bind(this)); 117 | } 118 | } 119 | 120 | start() { 121 | this.bindKeyHandlers(); 122 | requestAnimationFrame(this.animate.bind(this)); 123 | this.checkBoard(); 124 | } 125 | 126 | animate() { 127 | if (this.newGame) { 128 | document.getElementById("virus").innerHTML = `Viruses Left: ${this.virusCount}`; 129 | document.getElementById("score").innerHTML = `Score: ${this.score}`; 130 | document.getElementById("level").innerHTML = `Level: ${this.level}`; 131 | document.getElementById("mute").addEventListener("click", () => { 132 | this.audio.toggleMute(); 133 | document.getElementById("mute").blur(); 134 | }); 135 | this.ctx.font = "50px Arial"; 136 | this.ctx.fillStyle = "red"; 137 | this.ctx.fillText("Dr Mario JS",15,250); 138 | this.ctx.strokeStyle = "white"; 139 | this.ctx.lineWidth = 2; 140 | this.ctx.strokeText("Dr Mario JS",15,250); 141 | this.ctx.font = "25px Arial"; 142 | this.ctx.fillStyle = "red"; 143 | this.ctx.fillText("Hit Space to Start",45,300); 144 | this.ctx.strokeStyle = "white"; 145 | this.ctx.lineWidth = 1; 146 | this.ctx.strokeText("Hit Space to Start",45,300); 147 | } else if (this.paused) { 148 | setTimeout(() => {requestAnimationFrame(this.animate.bind(this));}, this.speed); 149 | } else if (this.checking){ 150 | setTimeout(() => {requestAnimationFrame(this.animate.bind(this));}, this.speed); 151 | } else if (this.virusCount === 0) { 152 | this.audio.levelClear(); 153 | if (this.level < 10) { 154 | this.level += 1; 155 | this.speed -= 100; 156 | } 157 | this.board = this.newBoard(this.ctx); 158 | this.checkBoard(); 159 | requestAnimationFrame(this.animate.bind(this)); 160 | } else if (this.gameOver) { 161 | this.audio.bgmStop(); 162 | this.audio.gameOver(); 163 | this.ctx.font = "50px Arial"; 164 | this.ctx.fillStyle = "red"; 165 | this.ctx.fillText("Game Over",15,250); 166 | this.ctx.strokeStyle = "white"; 167 | this.ctx.lineWidth = 2; 168 | this.ctx.strokeText("Game Over",15,250); 169 | this.ctx.font = "25px Arial"; 170 | this.ctx.fillStyle = "red"; 171 | this.ctx.fillText("Hit Space to Restart",30,300); 172 | this.ctx.strokeStyle = "white"; 173 | this.ctx.lineWidth = 1; 174 | this.ctx.strokeText("Hit Space to Restart",30,300); 175 | } else { 176 | if (!this.currentPill || !this.currentPill.active) { 177 | this.newPill(this.ctx, this.board); 178 | } else { 179 | this.currentPill.drop(); 180 | if (!this.currentPill.active) { 181 | this.checkBoard(); 182 | } 183 | } 184 | 185 | this.draw(this.ctx); 186 | 187 | setTimeout(() => {requestAnimationFrame(this.animate.bind(this));}, this.speed); 188 | } 189 | } 190 | 191 | checkBoard() { 192 | this.checking = true; 193 | this.checkCols(); 194 | this.checkRows(); 195 | if (this.changed) { 196 | this.changed = false; 197 | this.dropPills(); 198 | setTimeout(() => {this.checkBoard();}, 500); 199 | } else { 200 | this.checking = false; 201 | } 202 | } 203 | 204 | dropPills() { 205 | const transposedBoard = []; 206 | for (var i = 0; i < 8; i++) { 207 | const newRow = []; 208 | for (var j = 15; j >= 0; j--) { 209 | newRow.push(this.board[j][i]); 210 | } 211 | transposedBoard.push(newRow); 212 | } 213 | 214 | for (i = 0; i < transposedBoard.length; i++) { 215 | for (j = 1; j < transposedBoard[i].length; j++) { 216 | if (transposedBoard[i][j] !== undefined && 217 | transposedBoard[i][j].type === "pill" && 218 | transposedBoard[i][j -1 ] === undefined) { 219 | if (transposedBoard[i][j].pair === null) { 220 | transposedBoard[i][j].drop(); 221 | transposedBoard[i][j] = undefined; 222 | this.draw(this.ctx); 223 | this.changed = true; 224 | } else if (transposedBoard[i][j].coords[1] === transposedBoard[i][j].pair.coords[1] || 225 | transposedBoard[i][j].coords[0] !== transposedBoard[i][j].pair.coords[0] || 226 | this.board[transposedBoard[i][j].pair.coords[0] + 1][transposedBoard[i][j].pair.coords[1]] === undefined) { 227 | transposedBoard[i][j].drop(); 228 | transposedBoard[i][j] = undefined; 229 | this.draw(this.ctx); 230 | this.changed = true; 231 | } 232 | } 233 | } 234 | } 235 | } 236 | 237 | checkRows() { 238 | let viruses = []; 239 | let tempRow; 240 | let currentColor; 241 | for (var i = 0; i < this.board.length; i++) { 242 | tempRow = []; 243 | currentColor = null; 244 | for (var j = 0; j < this.board[i].length; j++) { 245 | if (this.board[i][j] !== undefined) { 246 | if (this.board[i][j].type === "virus") { 247 | viruses.push([i, j]); 248 | } 249 | if (currentColor === null) { 250 | currentColor = this.board[i][j].color; 251 | } 252 | if (this.board[i][j].color === currentColor) { 253 | tempRow.push([i, j]); 254 | } 255 | if (this.board[i][j].color !== currentColor || j === 7) { 256 | currentColor = this.board[i][j].color; 257 | if (tempRow.length > 3) { 258 | tempRow.forEach((coord) => { 259 | if (this.board[coord[0]][coord[1]].type === "virus") { 260 | this.score += 100; 261 | } 262 | if (this.board[coord[0]][coord[1]].pair) { 263 | this.board[coord[0]][coord[1]].pair.pair = null; 264 | } 265 | this.board[coord[0]][coord[1]] = undefined; 266 | this.changed = true; 267 | }); 268 | this.audio.eatBlocks(); 269 | } 270 | tempRow = []; 271 | tempRow.push([i, j]); 272 | } 273 | } else { 274 | if (tempRow.length > 3) { 275 | tempRow.forEach((coord) => { 276 | if (this.board[coord[0]][coord[1]].type === "virus") { 277 | this.score += 100; 278 | } 279 | if (this.board[coord[0]][coord[1]].pair) { 280 | this.board[coord[0]][coord[1]].pair.pair = null; 281 | } 282 | this.board[coord[0]][coord[1]] = undefined; 283 | this.changed = true; 284 | }); 285 | this.audio.eatBlocks(); 286 | } 287 | tempRow = []; 288 | currentColor = null; 289 | } 290 | } 291 | } 292 | this.virusCount = viruses.length; 293 | } 294 | 295 | checkCols() { 296 | const transposedBoard = []; 297 | for (var i = 0; i < 8; i++) { 298 | const newRow = []; 299 | for (var j = 0; j < this.board.length; j++) { 300 | newRow.push(this.board[j][i]); 301 | } 302 | transposedBoard.push(newRow); 303 | } 304 | let tempCol = []; 305 | let currentColor = null; 306 | for (i = 0; i < transposedBoard.length; i++) { 307 | tempCol = []; 308 | currentColor = null; 309 | for (j = 0; j < transposedBoard[i].length; j++) { 310 | if (transposedBoard[i][j] !== undefined) { 311 | if (currentColor === null) { 312 | currentColor = transposedBoard[i][j].color; 313 | } 314 | if (transposedBoard[i][j].color === currentColor) { 315 | tempCol.push([i, j]); 316 | } 317 | if (transposedBoard[i][j].color !== currentColor || j === 15) { 318 | currentColor = transposedBoard[i][j].color; 319 | if (tempCol.length > 3) { 320 | tempCol.forEach((coord) => { 321 | if (this.board[coord[1]][coord[0]].type === "virus") { 322 | this.score += 100; 323 | } 324 | if (this.board[coord[1]][coord[0]].pair) { 325 | this.board[coord[1]][coord[0]].pair.pair = null; 326 | } 327 | this.board[coord[1]][coord[0]] = undefined; 328 | this.changed = true; 329 | }); 330 | this.audio.eatBlocks(); 331 | } 332 | tempCol = []; 333 | tempCol.push([i, j]); 334 | } 335 | } else { 336 | if (tempCol.length > 3) { 337 | tempCol.forEach((coord) => { 338 | if (this.board[coord[1]][coord[0]].type === "virus") { 339 | this.score += 100; 340 | } 341 | if (this.board[coord[1]][coord[0]].pair) { 342 | this.board[coord[1]][coord[0]].pair.pair = null; 343 | } 344 | this.board[coord[1]][coord[0]] = undefined; 345 | this.changed = true; 346 | }); 347 | this.audio.eatBlocks(); 348 | } 349 | tempCol = []; 350 | currentColor = null; 351 | } 352 | } 353 | } 354 | } 355 | 356 | 357 | 358 | } 359 | 360 | Game.DIM_X = 288; 361 | Game.DIM_Y = 576; 362 | Game.MOVES = { 363 | left: "left", 364 | right: "right", 365 | down: "down", 366 | z: "z", 367 | x: "x", 368 | }; 369 | 370 | 371 | export default Game; 372 | -------------------------------------------------------------------------------- /lib/keymaster.js: -------------------------------------------------------------------------------- 1 | // keymaster.js 2 | // (c) 2011-2012 Thomas Fuchs 3 | // keymaster.js may be freely distributed under the MIT license. 4 | 5 | ;(function(global){ 6 | var k, 7 | _handlers = {}, 8 | _mods = { 16: false, 18: false, 17: false, 91: false }, 9 | _scope = 'all', 10 | // modifier keys 11 | _MODIFIERS = { 12 | '⇧': 16, shift: 16, 13 | '⌥': 18, alt: 18, option: 18, 14 | '⌃': 17, ctrl: 17, control: 17, 15 | '⌘': 91, command: 91 16 | }, 17 | // special keys 18 | _MAP = { 19 | backspace: 8, tab: 9, clear: 12, 20 | enter: 13, 'return': 13, 21 | esc: 27, escape: 27, space: 32, 22 | left: 37, up: 38, 23 | right: 39, down: 40, 24 | del: 46, 'delete': 46, 25 | home: 36, end: 35, 26 | pageup: 33, pagedown: 34, 27 | ',': 188, '.': 190, '/': 191, 28 | '`': 192, '-': 189, '=': 187, 29 | ';': 186, '\'': 222, 30 | '[': 219, ']': 221, '\\': 220 31 | }, 32 | code = function(x){ 33 | return _MAP[x] || x.toUpperCase().charCodeAt(0); 34 | }, 35 | _downKeys = []; 36 | 37 | for(k=1;k<20;k++) _MODIFIERS['f'+k] = 111+k; 38 | 39 | // IE doesn't support Array#indexOf, so have a simple replacement 40 | function index(array, item){ 41 | var i = array.length; 42 | while(i--) if(array[i]===item) return i; 43 | return -1; 44 | } 45 | 46 | var modifierMap = { 47 | 16:'shiftKey', 48 | 18:'altKey', 49 | 17:'ctrlKey', 50 | 91:'metaKey' 51 | }; 52 | function updateModifierKey(event) { 53 | for(k in _mods) _mods[k] = event[modifierMap[k]]; 54 | }; 55 | 56 | // handle keydown event 57 | function dispatch(event, scope){ 58 | var key, handler, k, i, modifiersMatch; 59 | key = event.keyCode; 60 | 61 | if (index(_downKeys, key) == -1) { 62 | _downKeys.push(key); 63 | } 64 | 65 | // if a modifier key, set the key. property to true and return 66 | if(key == 93 || key == 224) key = 91; // right command on webkit, command on Gecko 67 | if(key in _mods) { 68 | _mods[key] = true; 69 | // 'assignKey' from inside this closure is exported to window.key 70 | for(k in _MODIFIERS) if(_MODIFIERS[k] == key) assignKey[k] = true; 71 | return; 72 | } 73 | updateModifierKey(event); 74 | 75 | // see if we need to ignore the keypress (filter() can can be overridden) 76 | // by default ignore key presses if a select, textarea, or input is focused 77 | if(!assignKey.filter.call(this, event)) return; 78 | 79 | // abort if no potentially matching shortcuts found 80 | if (!(key in _handlers)) return; 81 | 82 | // for each potential shortcut 83 | for (i = 0; i < _handlers[key].length; i++) { 84 | handler = _handlers[key][i]; 85 | 86 | // see if it's in the current scope 87 | if(handler.scope == scope || handler.scope == 'all'){ 88 | // check if modifiers match if any 89 | modifiersMatch = handler.mods.length > 0; 90 | for(k in _mods) 91 | if((!_mods[k] && index(handler.mods, +k) > -1) || 92 | (_mods[k] && index(handler.mods, +k) == -1)) modifiersMatch = false; 93 | // call the handler and stop the event if neccessary 94 | if((handler.mods.length == 0 && !_mods[16] && !_mods[18] && !_mods[17] && !_mods[91]) || modifiersMatch){ 95 | if(handler.method(event, handler)===false){ 96 | if(event.preventDefault) event.preventDefault(); 97 | else event.returnValue = false; 98 | if(event.stopPropagation) event.stopPropagation(); 99 | if(event.cancelBubble) event.cancelBubble = true; 100 | } 101 | } 102 | } 103 | } 104 | }; 105 | 106 | // unset modifier keys on keyup 107 | function clearModifier(event){ 108 | var key = event.keyCode, k, 109 | i = index(_downKeys, key); 110 | 111 | // remove key from _downKeys 112 | if (i >= 0) { 113 | _downKeys.splice(i, 1); 114 | } 115 | 116 | if(key == 93 || key == 224) key = 91; 117 | if(key in _mods) { 118 | _mods[key] = false; 119 | for(k in _MODIFIERS) if(_MODIFIERS[k] == key) assignKey[k] = false; 120 | } 121 | }; 122 | 123 | function resetModifiers() { 124 | for(k in _mods) _mods[k] = false; 125 | for(k in _MODIFIERS) assignKey[k] = false; 126 | } 127 | 128 | // parse and assign shortcut 129 | function assignKey(key, scope, method){ 130 | var keys, mods, i, mi; 131 | if (method === undefined) { 132 | method = scope; 133 | scope = 'all'; 134 | } 135 | key = key.replace(/\s/g,''); 136 | keys = key.split(','); 137 | 138 | if((keys[keys.length-1])=='') 139 | keys[keys.length-2] += ','; 140 | // for each shortcut 141 | for (i = 0; i < keys.length; i++) { 142 | // set modifier keys if any 143 | mods = []; 144 | key = keys[i].split('+'); 145 | if(key.length > 1){ 146 | mods = key.slice(0,key.length-1); 147 | for (mi = 0; mi < mods.length; mi++) 148 | mods[mi] = _MODIFIERS[mods[mi]]; 149 | key = [key[key.length-1]]; 150 | } 151 | // convert to keycode and... 152 | key = key[0] 153 | key = code(key); 154 | // ...store handler 155 | if (!(key in _handlers)) _handlers[key] = []; 156 | _handlers[key].push({ shortcut: keys[i], scope: scope, method: method, key: keys[i], mods: mods }); 157 | } 158 | }; 159 | 160 | // Returns true if the key with code 'keyCode' is currently down 161 | // Converts strings into key codes. 162 | function isPressed(keyCode) { 163 | if (typeof(keyCode)=='string') { 164 | keyCode = code(keyCode); 165 | } 166 | return index(_downKeys, keyCode) != -1; 167 | } 168 | 169 | function getPressedKeyCodes() { 170 | return _downKeys.slice(0); 171 | } 172 | 173 | function filter(event){ 174 | var tagName = (event.target || event.srcElement).tagName; 175 | // ignore keypressed in any elements that support keyboard data input 176 | return !(tagName == 'INPUT' || tagName == 'SELECT' || tagName == 'TEXTAREA'); 177 | } 178 | 179 | // initialize key. to false 180 | for(k in _MODIFIERS) assignKey[k] = false; 181 | 182 | // set current scope (default 'all') 183 | function setScope(scope){ _scope = scope || 'all' }; 184 | function getScope(){ return _scope || 'all' }; 185 | 186 | // delete all handlers for a given scope 187 | function deleteScope(scope){ 188 | var key, handlers, i; 189 | 190 | for (key in _handlers) { 191 | handlers = _handlers[key]; 192 | for (i = 0; i < handlers.length; ) { 193 | if (handlers[i].scope === scope) handlers.splice(i, 1); 194 | else i++; 195 | } 196 | } 197 | }; 198 | 199 | // cross-browser events 200 | function addEvent(object, event, method) { 201 | if (object.addEventListener) 202 | object.addEventListener(event, method, false); 203 | else if(object.attachEvent) 204 | object.attachEvent('on'+event, function(){ method(window.event) }); 205 | }; 206 | 207 | // set the handlers globally on document 208 | addEvent(document, 'keydown', function(event) { dispatch(event, _scope) }); // Passing _scope to a callback to ensure it remains the same by execution. Fixes #48 209 | addEvent(document, 'keyup', clearModifier); 210 | 211 | // reset modifiers to false whenever the window is (re)focused. 212 | addEvent(window, 'focus', resetModifiers); 213 | 214 | // store previously defined key 215 | var previousKey = global.key; 216 | 217 | // restore previously defined key and return reference to our key object 218 | function noConflict() { 219 | var k = global.key; 220 | global.key = previousKey; 221 | return k; 222 | } 223 | 224 | // set window.key and window.key.set/get/deleteScope, and the default filter 225 | global.key = assignKey; 226 | global.key.setScope = setScope; 227 | global.key.getScope = getScope; 228 | global.key.deleteScope = deleteScope; 229 | global.key.filter = filter; 230 | global.key.isPressed = isPressed; 231 | global.key.getPressedKeyCodes = getPressedKeyCodes; 232 | global.key.noConflict = noConflict; 233 | 234 | if(typeof module !== 'undefined') module.exports = key; 235 | 236 | })(this); 237 | -------------------------------------------------------------------------------- /lib/pill.js: -------------------------------------------------------------------------------- 1 | import Audio from './audio'; 2 | 3 | class Pill { 4 | constructor(ctx, board) { 5 | this.ctx = ctx; 6 | this.board = board; 7 | this.board1 = [0, 3]; 8 | this.board2 = [0, 4]; 9 | this.active = true; 10 | this.horizontal = true; 11 | this.audio = new Audio; 12 | 13 | this.pill1 = new PillBlock(ctx, board, [0, 3], ["yellow", "blue", "red"][Math.floor(Math.random() * 3)], "left"); 14 | this.pill2 = new PillBlock(ctx, board, [0, 4], ["yellow", "blue", "red"][Math.floor(Math.random() * 3)], "right"); 15 | this.pill1.pair = this.pill2; 16 | this.pill2.pair = this.pill1; 17 | } 18 | 19 | drop() { 20 | if ( 21 | this.board1[0] < 15 && 22 | this.board2[0] < 15 && 23 | (this.board[this.board1[0] + 1][this.board1[1]] === undefined || this.board1[0] + 1 === this.board2[0] ) && 24 | (this.board[this.board2[0] + 1][this.board2[1]] === undefined || this.board2[0] + 1=== this.board1[0] ) 25 | ) { 26 | 27 | this.board[this.board1[0]][this.board1[1]] = undefined; 28 | this.board[this.board2[0]][this.board2[1]] = undefined; 29 | 30 | this.board1[0] = this.board1[0] + 1; 31 | this.board2[0] = this.board2[0] + 1; 32 | 33 | this.board[this.board1[0]][this.board1[1]] = this.pill1; 34 | this.board[this.board2[0]][this.board2[1]] = this.pill2; 35 | 36 | this.pill1.coords = [this.board1[0], this.board1[1]]; 37 | this.pill2.coords = [this.board2[0], this.board2[1]]; 38 | } else { 39 | this.active = false; 40 | } 41 | } 42 | 43 | move(k) { 44 | if (this.active) { 45 | if (k === "down") { 46 | this.drop(); 47 | this.audio.movePill(); 48 | } 49 | if (k === "right") { 50 | if ( 51 | this.board1[1] < 7 && 52 | this.board2[1] < 7 && 53 | (this.board[this.board1[0]][this.board1[1] + 1] === undefined || this.board1[1] + 1 == this.board2[1]) && 54 | (this.board[this.board2[0]][this.board2[1] + 1] === undefined || this.board2[1] + 1 == this.board1[1]) 55 | ) { 56 | this.board[this.board1[0]][this.board1[1]] = undefined; 57 | this.board[this.board2[0]][this.board2[1]] = undefined; 58 | 59 | this.board1[1] = this.board1[1] + 1; 60 | this.board2[1] = this.board2[1] + 1; 61 | 62 | this.board[this.board1[0]][this.board1[1]] = this.pill1; 63 | this.board[this.board2[0]][this.board2[1]] = this.pill2; 64 | 65 | this.pill1.coords = [this.board1[0], this.board1[1]]; 66 | this.pill2.coords = [this.board2[0], this.board2[1]]; 67 | 68 | this.audio.movePill(); 69 | } 70 | } 71 | if (k === "left") { 72 | if ( 73 | this.board1[1] > 0 && 74 | this.board2[1] > 0 && 75 | (this.board[this.board1[0]][this.board1[1] - 1] === undefined || this.board1[1] - 1 == this.board2[1]) && 76 | (this.board[this.board2[0]][this.board2[1] - 1] === undefined || this.board2[1] - 1 == this.board1[1]) 77 | ) { 78 | 79 | this.board[this.board1[0]][this.board1[1]] = undefined; 80 | this.board[this.board2[0]][this.board2[1]] = undefined; 81 | 82 | this.board1[1] = this.board1[1] - 1; 83 | this.board2[1] = this.board2[1] - 1; 84 | 85 | this.board[this.board1[0]][this.board1[1]] = this.pill1; 86 | this.board[this.board2[0]][this.board2[1]] = this.pill2; 87 | 88 | this.pill1.coords = [this.board1[0], this.board1[1]]; 89 | this.pill2.coords = [this.board2[0], this.board2[1]]; 90 | 91 | this.audio.movePill(); 92 | } 93 | } 94 | if (k === "z") { 95 | if (this.horizontal) { 96 | if (this.board2[0] > 0 && this.board[this.board1[0] - 1][this.board1[1]] === undefined) { 97 | 98 | this.board[this.board2[0]][this.board2[1]] = undefined; 99 | this.board2[0] = this.board2[0] - 1; 100 | this.board2[1] = this.board2[1] - 1; 101 | this.board[this.board2[0]][this.board2[1]] = this.pill2; 102 | this.pill2.coords = [this.board2[0], this.board2[1]]; 103 | 104 | this.pill1.side = "bottom"; 105 | this.pill2.side = "top"; 106 | 107 | this.horizontal = false; 108 | 109 | this.audio.rotatePill(); 110 | } 111 | } else { 112 | if (this.board[this.board1[0]][this.board1[1] + 1] === undefined && this.board1[1] < 7) { 113 | this.board[this.board2[0]][this.board2[1]] = undefined; 114 | this.board2[0] = this.board2[0] + 1; 115 | this.board2[1] = this.board2[1] + 1; 116 | this.board[this.board2[0]][this.board2[1]] = this.pill2; 117 | this.pill2.coords = [this.board2[0], this.board2[1]]; 118 | 119 | const tempColor = this.pill1.color; 120 | this.pill1.color = this.pill2.color; 121 | this.pill2.color = tempColor; 122 | 123 | this.pill1.side = "left"; 124 | this.pill2.side = "right"; 125 | 126 | this.horizontal = true; 127 | 128 | this.audio.rotatePill(); 129 | } 130 | } 131 | } 132 | if (k === "x") { 133 | if (this.horizontal) { 134 | if (this.board2[0] > 0 && this.board[this.board1[0] - 1][this.board1[1]] === undefined) { 135 | this.board[this.board2[0]][this.board2[1]] = undefined; 136 | this.board2[0] = this.board2[0] - 1; 137 | this.board2[1] = this.board2[1] - 1; 138 | this.board[this.board2[0]][this.board2[1]] = this.pill2; 139 | this.pill2.coords = [this.board2[0], this.board2[1]]; 140 | 141 | const tempColor = this.pill1.color; 142 | this.pill1.color = this.pill2.color; 143 | this.pill2.color = tempColor; 144 | 145 | this.pill1.side = "bottom"; 146 | this.pill2.side = "top"; 147 | 148 | this.horizontal = false; 149 | 150 | this.audio.rotatePill(); 151 | } 152 | } else { 153 | if (this.board[this.board1[0]][this.board1[1] + 1] === undefined && this.board1[1] < 7) { 154 | this.board[this.board2[0]][this.board2[1]] = undefined; 155 | this.board2[0] = this.board2[0] + 1; 156 | this.board2[1] = this.board2[1] + 1; 157 | this.board[this.board2[0]][this.board2[1]] = this.pill2; 158 | this.pill2.coords = [this.board2[0], this.board2[1]]; 159 | 160 | this.pill1.side = "left"; 161 | this.pill2.side = "right"; 162 | 163 | this.horizontal = true; 164 | 165 | this.audio.rotatePill(); 166 | } 167 | } 168 | } 169 | } 170 | 171 | } 172 | } 173 | 174 | class PillBlock { 175 | constructor(ctx, board, coords, color, side){ 176 | this.ctx = ctx; 177 | this.board = board; 178 | this.coords = coords; 179 | this.color = color; 180 | this.type = "pill"; 181 | this.pair = null; 182 | this.side = side; 183 | } 184 | 185 | draw() { 186 | let img = new Image(); 187 | let x = (this.coords[1] * 36); 188 | let y = (this.coords[0] * 36); 189 | let w = 32; 190 | let h = 32; 191 | let degrees = -90; 192 | if (this.pair === null) { 193 | img.src = `images/pill${this.color}.png`; 194 | this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 32, 32); 195 | img.onload = () => { 196 | this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 32, 32); 197 | }; 198 | } else if (this.side === "left") { 199 | img.src = `images/pill${this.color}left.png`; 200 | this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 32, 32); 201 | img.onload = () => { 202 | this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 32, 32); 203 | }; 204 | } else if (this.side === "right"){ 205 | img.src = `images/pill${this.color}right.png`; 206 | this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 32, 32); 207 | img.onload = () => { 208 | this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 32, 32); 209 | }; 210 | } else if (this.side === "top"){ 211 | img.src = `images/pill${this.color}right.png`; 212 | 213 | this.ctx.save(); 214 | this.ctx.translate(x+w/2, y+h/2); 215 | this.ctx.rotate(degrees*Math.PI/180.0); 216 | this.ctx.translate(-x-w/2, -y-h/2); 217 | this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 32, 32); 218 | this.ctx.restore(); 219 | img.onload = () => { 220 | this.ctx.save(); 221 | this.ctx.translate(x+w/2, y+h/2); 222 | this.ctx.rotate(degrees*Math.PI/180.0); 223 | this.ctx.translate(-x-w/2, -y-h/2); 224 | this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 32, 32); 225 | this.ctx.restore(); 226 | }; 227 | } else if (this.side === "bottom"){ 228 | img.src = `images/pill${this.color}left.png`; 229 | 230 | this.ctx.save(); 231 | this.ctx.translate(x+w/2, y+h/2); 232 | this.ctx.rotate(degrees*Math.PI/180.0); 233 | this.ctx.translate(-x-w/2, -y-h/2); 234 | this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 32, 32); 235 | this.ctx.restore(); 236 | img.onload = () => { 237 | this.ctx.save(); 238 | this.ctx.translate(x+w/2, y+h/2); 239 | this.ctx.rotate(degrees*Math.PI/180.0); 240 | this.ctx.translate(-x-w/2, -y-h/2); 241 | this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 32, 32); 242 | this.ctx.restore(); 243 | }; 244 | } 245 | } 246 | 247 | drop() { 248 | if ( 249 | this.coords[0] < 15 && 250 | this.board[this.coords[0] + 1][this.coords[1]] === undefined 251 | ) { 252 | this.board[this.coords[0]][this.coords[1]] = undefined; 253 | this.coords[0] = this.coords[0] + 1; 254 | this.board[this.coords[0]][this.coords[1]] = this; 255 | } 256 | } 257 | } 258 | 259 | 260 | export default Pill; 261 | -------------------------------------------------------------------------------- /lib/virus.js: -------------------------------------------------------------------------------- 1 | class Virus { 2 | constructor(ctx, board, coords, color){ 3 | this.ctx = ctx; 4 | this.board = board; 5 | this.coords = coords; 6 | this.color = color; 7 | this.type = "virus"; 8 | this.pair = null; 9 | } 10 | 11 | draw() { 12 | this.board[this.coords[0]][this.coords[1]] = this; 13 | 14 | let img = new Image(); 15 | img.src = `images/virus${this.color}.png`; 16 | this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 36, 36); 17 | img.onload = () => { 18 | this.ctx.drawImage(img, this.coords[1] * 36, this.coords[0] * 36, 36, 36); 19 | }; 20 | } 21 | } 22 | 23 | export default Virus; 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "drmariojs", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "webpack -w", 9 | "postinstall": "webpack" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/swangs/javascript_project.git" 14 | }, 15 | "keywords": [], 16 | "author": "", 17 | "license": "ISC", 18 | "bugs": { 19 | "url": "https://github.com/swangs/javascript_project/issues" 20 | }, 21 | "homepage": "https://github.com/swangs/javascript_project#readme", 22 | "dependencies": { 23 | "webpack": "^3.11.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /sounds/bgm.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swangs/drmariojs/5ba12ac05bbf8267360b7ca0a7497e350a84311a/sounds/bgm.mp3 -------------------------------------------------------------------------------- /sounds/eatblocks.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swangs/drmariojs/5ba12ac05bbf8267360b7ca0a7497e350a84311a/sounds/eatblocks.mp3 -------------------------------------------------------------------------------- /sounds/gameover.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swangs/drmariojs/5ba12ac05bbf8267360b7ca0a7497e350a84311a/sounds/gameover.mp3 -------------------------------------------------------------------------------- /sounds/levelclear.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swangs/drmariojs/5ba12ac05bbf8267360b7ca0a7497e350a84311a/sounds/levelclear.mp3 -------------------------------------------------------------------------------- /sounds/movepill.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swangs/drmariojs/5ba12ac05bbf8267360b7ca0a7497e350a84311a/sounds/movepill.mp3 -------------------------------------------------------------------------------- /sounds/rotatepill.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swangs/drmariojs/5ba12ac05bbf8267360b7ca0a7497e350a84311a/sounds/rotatepill.mp3 -------------------------------------------------------------------------------- /stylesheets/css.css: -------------------------------------------------------------------------------- 1 | body{ 2 | background-image: url("../images/virus.jpg"); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | font-family: 'Orbitron', sans-serif; 6 | color: #ffffff; 7 | display: flex; 8 | align-items: center; 9 | justify-content: space-around; 10 | } 11 | 12 | .gamecontainer { 13 | width: 80%; 14 | height: 80%; 15 | display: flex; 16 | align-items: center; 17 | justify-content: space-around; 18 | 19 | } 20 | 21 | canvas { 22 | background: #000000; 23 | background: linear-gradient(#252525, #252525); 24 | border: 2px solid #FFFFFF; 25 | border-radius: 20px; 26 | } 27 | 28 | h1 { 29 | text-align: center; 30 | } 31 | 32 | h2 { 33 | font-size: 20px; 34 | } 35 | 36 | p { 37 | font-size: 20px; 38 | font-weight: 700; 39 | margin-left: 0px; 40 | } 41 | 42 | .controls { 43 | min-width: 250px; 44 | max-width: 250px; 45 | /* height: 360px; */ 46 | background: rgba(25, 25, 25, 0.9); 47 | border-radius: 20px; 48 | padding: 0px 20px; 49 | } 50 | 51 | .information { 52 | min-width: 250px; 53 | max-width: 250px; 54 | height: 150px; 55 | background: rgba(25, 25, 25, 0.9); 56 | border-radius: 20px; 57 | padding: 20px; 58 | display: flex; 59 | flex-direction: column; 60 | justify-content: space-around; 61 | } 62 | 63 | button { 64 | width: 30px; 65 | height: 30px; 66 | } 67 | button:hover{ 68 | cursor: pointer; 69 | outline: none; 70 | } 71 | 72 | .swang-links { 73 | position: relative; 74 | /* top: 25px; */ 75 | left: 150px; 76 | width: 100px; 77 | height: 50px; 78 | display: flex; 79 | justify-content: space-between; 80 | } 81 | 82 | a { 83 | color: #FFFFFF; 84 | } 85 | a:visited { text-decoration: none; color:#FFFFFF; } 86 | a:hover { text-decoration: none; color:#0074BB; } 87 | a:hover, a:active { text-decoration: none; color:#0074BB } 88 | 89 | #mute { 90 | border-radius: 5px; 91 | min-width: 20px; 92 | min-height: 20px; 93 | position: relative; 94 | bottom: 5px; 95 | } 96 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | entry: "./lib/drmariojs.js", 3 | output: { 4 | filename: "./lib/bundle.js" 5 | }, 6 | devtool: 'source-map', 7 | }; 8 | --------------------------------------------------------------------------------