├── src ├── index.js ├── vendor │ ├── phaser.js │ └── fontawesome.js ├── vendor.js ├── stylesheet │ ├── variables.scss │ └── main.scss ├── config │ ├── const-variable.js │ └── config.js ├── scenes │ ├── boot.js │ ├── credits.js │ ├── endGame.js │ ├── title.js │ ├── option.js │ ├── score.js │ ├── user.js │ ├── preload.js │ └── game.js └── module │ ├── user.js │ ├── sound.js │ ├── api.js │ └── main.js ├── Btns.xcf ├── game-play.gif ├── dist ├── assets │ ├── sky.png │ ├── game │ │ ├── hero.png │ │ ├── menu.png │ │ ├── star.png │ │ ├── test.png │ │ ├── ground.png │ │ ├── hero1.png │ │ ├── hero2.png │ │ ├── replay.png │ │ ├── star2.png │ │ ├── star3.png │ │ ├── submit.png │ │ ├── asteroid2.png │ │ ├── endgame.png │ │ └── metalface78x92.png │ └── ui │ │ ├── back.png │ │ ├── score.png │ │ ├── bgMusic.mp3 │ │ ├── checked.png │ │ ├── credits.png │ │ ├── settings.png │ │ ├── empty-tag.png │ │ ├── play-game.png │ │ └── unchecked.png ├── index.html └── main.bundle.js ├── .vscode └── settings.json ├── .babelrc ├── server.js ├── .eslintrc.json ├── .stickler.yml ├── webpack.config.js ├── LICENSE ├── test └── module.test.js ├── package.json ├── .gitignore ├── README.md └── stylelint.config.js /src/index.js: -------------------------------------------------------------------------------- 1 | import './module/main'; -------------------------------------------------------------------------------- /src/vendor/phaser.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import 'phaser'; 3 | -------------------------------------------------------------------------------- /src/vendor.js: -------------------------------------------------------------------------------- 1 | import './vendor/fontawesome'; 2 | import './vendor/phaser'; 3 | -------------------------------------------------------------------------------- /Btns.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dandush03/Microverse-JS-Capstone/HEAD/Btns.xcf -------------------------------------------------------------------------------- /game-play.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dandush03/Microverse-JS-Capstone/HEAD/game-play.gif -------------------------------------------------------------------------------- /dist/assets/sky.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dandush03/Microverse-JS-Capstone/HEAD/dist/assets/sky.png -------------------------------------------------------------------------------- /src/stylesheet/variables.scss: -------------------------------------------------------------------------------- 1 | 2 | $space: 5px; 3 | $p-max: 100%; 4 | $vh-max: 100vh; 5 | $vw-max: 100vw; 6 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "anims", 4 | "metaleyes", 5 | "metalface" 6 | ] 7 | } -------------------------------------------------------------------------------- /dist/assets/game/hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dandush03/Microverse-JS-Capstone/HEAD/dist/assets/game/hero.png -------------------------------------------------------------------------------- /dist/assets/game/menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dandush03/Microverse-JS-Capstone/HEAD/dist/assets/game/menu.png -------------------------------------------------------------------------------- /dist/assets/game/star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dandush03/Microverse-JS-Capstone/HEAD/dist/assets/game/star.png -------------------------------------------------------------------------------- /dist/assets/game/test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dandush03/Microverse-JS-Capstone/HEAD/dist/assets/game/test.png -------------------------------------------------------------------------------- /dist/assets/ui/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dandush03/Microverse-JS-Capstone/HEAD/dist/assets/ui/back.png -------------------------------------------------------------------------------- /dist/assets/ui/score.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dandush03/Microverse-JS-Capstone/HEAD/dist/assets/ui/score.png -------------------------------------------------------------------------------- /dist/assets/game/ground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dandush03/Microverse-JS-Capstone/HEAD/dist/assets/game/ground.png -------------------------------------------------------------------------------- /dist/assets/game/hero1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dandush03/Microverse-JS-Capstone/HEAD/dist/assets/game/hero1.png -------------------------------------------------------------------------------- /dist/assets/game/hero2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dandush03/Microverse-JS-Capstone/HEAD/dist/assets/game/hero2.png -------------------------------------------------------------------------------- /dist/assets/game/replay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dandush03/Microverse-JS-Capstone/HEAD/dist/assets/game/replay.png -------------------------------------------------------------------------------- /dist/assets/game/star2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dandush03/Microverse-JS-Capstone/HEAD/dist/assets/game/star2.png -------------------------------------------------------------------------------- /dist/assets/game/star3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dandush03/Microverse-JS-Capstone/HEAD/dist/assets/game/star3.png -------------------------------------------------------------------------------- /dist/assets/game/submit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dandush03/Microverse-JS-Capstone/HEAD/dist/assets/game/submit.png -------------------------------------------------------------------------------- /dist/assets/ui/bgMusic.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dandush03/Microverse-JS-Capstone/HEAD/dist/assets/ui/bgMusic.mp3 -------------------------------------------------------------------------------- /dist/assets/ui/checked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dandush03/Microverse-JS-Capstone/HEAD/dist/assets/ui/checked.png -------------------------------------------------------------------------------- /dist/assets/ui/credits.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dandush03/Microverse-JS-Capstone/HEAD/dist/assets/ui/credits.png -------------------------------------------------------------------------------- /dist/assets/ui/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dandush03/Microverse-JS-Capstone/HEAD/dist/assets/ui/settings.png -------------------------------------------------------------------------------- /src/config/const-variable.js: -------------------------------------------------------------------------------- 1 | const GAME_HEIGHT = 600; 2 | const GAME_WIDTH = 800; 3 | export { GAME_HEIGHT, GAME_WIDTH }; -------------------------------------------------------------------------------- /dist/assets/game/asteroid2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dandush03/Microverse-JS-Capstone/HEAD/dist/assets/game/asteroid2.png -------------------------------------------------------------------------------- /dist/assets/game/endgame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dandush03/Microverse-JS-Capstone/HEAD/dist/assets/game/endgame.png -------------------------------------------------------------------------------- /dist/assets/ui/empty-tag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dandush03/Microverse-JS-Capstone/HEAD/dist/assets/ui/empty-tag.png -------------------------------------------------------------------------------- /dist/assets/ui/play-game.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dandush03/Microverse-JS-Capstone/HEAD/dist/assets/ui/play-game.png -------------------------------------------------------------------------------- /dist/assets/ui/unchecked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dandush03/Microverse-JS-Capstone/HEAD/dist/assets/ui/unchecked.png -------------------------------------------------------------------------------- /dist/assets/game/metalface78x92.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dandush03/Microverse-JS-Capstone/HEAD/dist/assets/game/metalface78x92.png -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"], 3 | "ignore": [ 4 | "*.scss" 5 | ], 6 | "plugins": [ 7 | "@babel/plugin-transform-runtime" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /src/vendor/fontawesome.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import '@fortawesome/fontawesome-free/js/all'; 3 | 4 | import '@fortawesome/fontawesome-free/js/regular'; 5 | import '@fortawesome/fontawesome-free/js/solid'; 6 | import '@fortawesome/fontawesome-free/js/brands'; 7 | -------------------------------------------------------------------------------- /src/stylesheet/main.scss: -------------------------------------------------------------------------------- 1 | @import './variables'; 2 | 3 | * { 4 | box-sizing: border-box; 5 | } 6 | 7 | body { 8 | display: flex; 9 | height: $vh-max; 10 | justify-content: center; 11 | margin: 0; 12 | padding: 0; 13 | width: $vw-max; 14 | 15 | > canvas { 16 | width: $vw-max; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | const path = require('path'); 3 | const express = require('express'); 4 | 5 | const app = express(); 6 | 7 | app.use(express.static(path.join(__dirname, 'dist'))); 8 | app.set('port', process.env.PORT || 8080); 9 | 10 | const server = app.listen(app.get('port'), () => { 11 | console.log('listening on port ', server.address().port); 12 | }); -------------------------------------------------------------------------------- /src/scenes/boot.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-undef 2 | export default class BootScene extends Phaser.Scene { 3 | constructor() { 4 | super('Boot'); 5 | } 6 | 7 | preload() { 8 | this.load.image('logo', 'https://res.cloudinary.com/dl-cultures/image/upload/v1588612118/logo/HeroLogo.svg'); 9 | } 10 | 11 | create() { 12 | this.scene.start('Preload'); 13 | } 14 | } -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es6": true, 5 | "jest": true 6 | }, 7 | "parserOptions": { 8 | "ecmaVersion": 2018, 9 | "sourceType": "module" 10 | }, 11 | "extends": ["airbnb-base"], 12 | "rules": { 13 | "no-shadow": "off", 14 | "no-param-reassign": "off", 15 | "eol-last": "off", 16 | "arrow-parens": "off" 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /src/module/user.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-underscore-dangle */ 2 | export default class User { 3 | constructor() { 4 | this._user = ''; 5 | this._score = 0; 6 | } 7 | 8 | set user(value) { 9 | this._user = value; 10 | } 11 | 12 | get user() { 13 | return this._user; 14 | } 15 | 16 | set score(value) { 17 | this._score = value; 18 | } 19 | 20 | get score() { 21 | return this._score; 22 | } 23 | } -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | DL-First-JS-Game 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/config/config.js: -------------------------------------------------------------------------------- 1 | import { GAME_HEIGHT, GAME_WIDTH } from './const-variable'; 2 | 3 | export default { 4 | parent: 'phaser-container', 5 | // eslint-disable-next-line no-undef 6 | type: Phaser.AUTO, 7 | width: GAME_WIDTH, 8 | height: GAME_HEIGHT, 9 | physics: { 10 | default: 'arcade', 11 | arcade: { 12 | gravity: { y: GAME_HEIGHT * 2 }, 13 | debug: false, 14 | x: 0, 15 | y: 0, 16 | width: GAME_WIDTH * 100, 17 | height: GAME_HEIGHT, 18 | thickness: 32, 19 | }, 20 | }, 21 | }; -------------------------------------------------------------------------------- /.stickler.yml: -------------------------------------------------------------------------------- 1 | 2 | # add the linters you want stickler to use for this project 3 | linters: 4 | eslint: 5 | 6 | # indicate where is the config file for stylelint 7 | config: './.eslintrc.json' 8 | 9 | stylelint: 10 | # indicate where is the config file for stylelint 11 | config: 'stylelint.config.js' 12 | 13 | # add the files here you want to be ignored by stylelint 14 | files: 15 | ignore: 16 | - 'dist/*' 17 | 18 | # PLEASE DO NOT enable auto fixing options 19 | # if you need extra support from you linter - do it in your local env as described in README for this config 20 | 21 | # find full documentation here: https://stickler-ci.com/docs -------------------------------------------------------------------------------- /src/module/sound.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-underscore-dangle */ 2 | export default class Sound { 3 | constructor() { 4 | this._soundOn = true; 5 | this._musicOn = true; 6 | this._bgMusicPlaying = false; 7 | } 8 | 9 | set musicOn(value) { 10 | this._musicOn = value; 11 | } 12 | 13 | get musicOn() { 14 | return this._musicOn; 15 | } 16 | 17 | set soundOn(value) { 18 | this._soundOn = value; 19 | } 20 | 21 | get soundOn() { 22 | return this._soundOn; 23 | } 24 | 25 | set bgMusicPlaying(value) { 26 | this._bgMusicPlaying = value; 27 | } 28 | 29 | get bgMusicPlaying() { 30 | return this._bgMusicPlaying; 31 | } 32 | } -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | entry: { 5 | main: './src/index.js', 6 | vendor: './src/vendor.js', 7 | }, 8 | output: { 9 | filename: '[name].bundle.js', 10 | path: path.resolve(__dirname, 'dist'), 11 | }, 12 | module: { 13 | rules: [ 14 | { 15 | test: /\.s[ac]ss$/i, 16 | use: [ 17 | // Creates `style` nodes from JS strings 18 | 'style-loader', 19 | // Translates CSS into CommonJS 20 | 'css-loader', 21 | // Compiles Sass to CSS 22 | 'sass-loader', 23 | ], 24 | }, 25 | { 26 | test: /\.(gif|svg|jpg|png)$/, 27 | loader: 'file-loader', 28 | }, 29 | ], 30 | }, 31 | devServer: { 32 | contentBase: path.join(__dirname, 'dist'), 33 | compress: true, 34 | port: 9000, 35 | }, 36 | }; 37 | -------------------------------------------------------------------------------- /src/module/api.js: -------------------------------------------------------------------------------- 1 | const ApiGet = async (method, userName = null, scores = null) => { 2 | let settings; 3 | let url; 4 | 5 | 6 | if (method === 'POST') { 7 | const postData = { user: userName, score: scores }; 8 | url = 'https://us-central1-js-capstone-backend.cloudfunctions.net/api/games/dl-game/scores/'; 9 | settings = { 10 | method: 'POST', 11 | body: JSON.stringify(postData), 12 | headers: { 13 | 'Content-Type': 'application/json', 14 | }, 15 | }; 16 | } else { 17 | url = 'https://us-central1-js-capstone-backend.cloudfunctions.net/api/games/dl-game/scores/'; 18 | settings = { mode: 'cors' }; 19 | } 20 | 21 | let response; 22 | 23 | try { 24 | response = await fetch(url, settings); 25 | } catch (e) { 26 | response = e; 27 | } 28 | const data = await response.json(); 29 | return data.result; 30 | }; 31 | 32 | 33 | // eslint-disable-next-line import/prefer-default-export 34 | export default ApiGet; 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Daniel Laloush 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/module/main.js: -------------------------------------------------------------------------------- 1 | import '../stylesheet/main.scss'; 2 | import config from '../config/config'; 3 | import BootScene from '../scenes/boot'; 4 | import PreloadScene from '../scenes/preload'; 5 | import TitleScene from '../scenes/title'; 6 | import OptionsScene from '../scenes/option'; 7 | import CreditsScene from '../scenes/credits'; 8 | import GameScene from '../scenes/game'; 9 | import ScoresScene from '../scenes/score'; 10 | import UserScene from '../scenes/user'; 11 | import EndGameScene from '../scenes/endGame'; 12 | 13 | import Sound from './sound'; 14 | import User from './user'; 15 | 16 | // eslint-disable-next-line no-undef 17 | class Game extends Phaser.Game { 18 | constructor() { 19 | super(config); 20 | const soundModel = new Sound(); 21 | const userModel = new User(); 22 | this.globals = { soundModel, bgMusic: null, userModel }; 23 | this.scene.add('Boot', BootScene); 24 | this.scene.add('Preload', PreloadScene); 25 | this.scene.add('Title', TitleScene); 26 | this.scene.add('Options', OptionsScene); 27 | this.scene.add('Credits', CreditsScene); 28 | this.scene.add('Scores', ScoresScene); 29 | this.scene.add('User', UserScene); 30 | this.scene.add('Game', GameScene); 31 | this.scene.add('EndGame', EndGameScene); 32 | this.scene.start('Boot'); 33 | } 34 | } 35 | 36 | window.game = new Game(); -------------------------------------------------------------------------------- /src/scenes/credits.js: -------------------------------------------------------------------------------- 1 | import { GAME_HEIGHT, GAME_WIDTH } from '../config/const-variable'; 2 | 3 | // eslint-disable-next-line no-undef 4 | export default class CreditsScene extends Phaser.Scene { 5 | constructor() { 6 | super('Credits'); 7 | } 8 | 9 | create() { 10 | this.add.image(GAME_WIDTH / 2, (GAME_HEIGHT / 2), 'sky'); 11 | this.add.image(GAME_WIDTH - 68, GAME_HEIGHT - 34, 'logo').setScale(0.3); 12 | 13 | this.gameBtn = this.add.image(110, 50, 'back').setInteractive(); 14 | this.gameBtn.on('pointerdown', () => { 15 | this.scene.start('Title'); 16 | }); 17 | 18 | this.input.on('pointerover', (event, gameObjects) => { 19 | gameObjects[0].setScale(1.1); 20 | }); 21 | 22 | this.input.on('pointerout', (event, gameObjects) => { 23 | gameObjects[0].setScale(1); 24 | }); 25 | 26 | const authorText = this.make.text({ 27 | x: GAME_WIDTH / 2, 28 | y: GAME_HEIGHT / 2 - 50, 29 | text: 'Author:', 30 | style: { 31 | font: '36px monospace', 32 | fill: '#422115', 33 | }, 34 | }); 35 | 36 | authorText.setOrigin(0.5, 0); 37 | const heroText = this.make.text({ 38 | x: GAME_WIDTH / 2, 39 | y: GAME_HEIGHT / 2 + 50, 40 | text: 'Daniel Laloush', 41 | style: { 42 | font: '36px monospace', 43 | fill: '#422115', 44 | }, 45 | }); 46 | heroText.setOrigin(0.5, 0); 47 | } 48 | } -------------------------------------------------------------------------------- /src/scenes/endGame.js: -------------------------------------------------------------------------------- 1 | import { GAME_HEIGHT, GAME_WIDTH } from '../config/const-variable'; 2 | import ApiGet from '../module/api'; 3 | 4 | // eslint-disable-next-line no-undef 5 | export default class EndGameScene extends Phaser.Scene { 6 | constructor() { 7 | super('EndGame'); 8 | } 9 | 10 | create() { 11 | this.userModel = this.sys.game.globals.userModel; 12 | 13 | this.add.image(GAME_WIDTH / 2, (GAME_HEIGHT / 2) - 100, 'endGame').setScrollFactor(0); 14 | 15 | this.replay = this.add.image(GAME_WIDTH / 2 - 125, (GAME_HEIGHT / 2) + 100, 'replay').setScrollFactor(0).setInteractive(); 16 | this.replay.on('pointerdown', () => { 17 | this.scene.start('Game'); 18 | }); 19 | 20 | this.menu = this.add.image(GAME_WIDTH / 2, (GAME_HEIGHT / 1.5) + 100, 'menu').setScrollFactor(0).setInteractive(); 21 | this.menu.on('pointerdown', () => { 22 | this.scene.sendToBack('Game'); 23 | this.scene.start('Title'); 24 | }); 25 | 26 | this.submit = this.add.image(GAME_WIDTH / 2 + 125, (GAME_HEIGHT / 2) + 100, 'submit').setScrollFactor(0).setInteractive(); 27 | this.submit.on('pointerdown', () => { 28 | ApiGet('POST', this.userModel.user, this.userModel.score) 29 | .then(() => { 30 | this.scene.sendToBack('Game'); 31 | this.scene.start('Scores'); 32 | }); 33 | }); 34 | this.input.on('pointerover', (event, gameObjects) => { 35 | gameObjects[0].setScale(1.1); 36 | }); 37 | 38 | this.input.on('pointerout', (event, gameObjects) => { 39 | gameObjects[0].setScale(1); 40 | }); 41 | } 42 | } -------------------------------------------------------------------------------- /src/scenes/title.js: -------------------------------------------------------------------------------- 1 | import { GAME_HEIGHT, GAME_WIDTH } from '../config/const-variable'; 2 | 3 | // eslint-disable-next-line no-undef 4 | export default class TitleScene extends Phaser.Scene { 5 | constructor() { 6 | super('Title'); 7 | } 8 | 9 | create() { 10 | this.add.image(GAME_WIDTH / 2, (GAME_HEIGHT / 2), 'sky'); 11 | this.add.image(GAME_WIDTH - 68, GAME_HEIGHT - 34, 'logo').setScale(0.3); 12 | 13 | this.soundModel = this.sys.game.globals.soundModel; 14 | if (this.soundModel.musicOn === true && this.soundModel.bgMusicPlaying === false) { 15 | this.bgMusic = this.sound.add('bgMusic', { volume: 0.5, loop: true }); 16 | this.bgMusic.play(); 17 | this.soundModel.bgMusicPlaying = true; 18 | this.sys.game.globals.bgMusic = this.bgMusic; 19 | } 20 | 21 | this.gameBtn = this.add.image(GAME_WIDTH / 2, (GAME_HEIGHT / 2) - 210, 'playGame').setInteractive(); 22 | this.gameBtn.on('pointerdown', () => { 23 | this.scene.start('User'); 24 | }); 25 | 26 | this.settingsBtn = this.add.image(GAME_WIDTH / 2, (GAME_HEIGHT / 2) - 100, 'settings').setInteractive(); 27 | this.settingsBtn.on('pointerdown', () => { 28 | this.scene.start('Options'); 29 | }); 30 | 31 | this.gameBtn = this.add.image(GAME_WIDTH / 2, (GAME_HEIGHT / 2) + 20, 'scores').setInteractive(); 32 | this.gameBtn.on('pointerdown', () => { 33 | this.scene.start('Scores'); 34 | }); 35 | 36 | this.settingsBtn = this.add.image(GAME_WIDTH / 2, (GAME_HEIGHT / 2) + 130, 'credits').setInteractive(); 37 | this.settingsBtn.on('pointerdown', () => { 38 | this.scene.start('Credits'); 39 | }); 40 | 41 | this.input.on('pointerover', (event, gameObjects) => { 42 | gameObjects[0].setScale(1.1); 43 | }); 44 | 45 | this.input.on('pointerout', (event, gameObjects) => { 46 | gameObjects[0].setScale(1); 47 | }); 48 | } 49 | } -------------------------------------------------------------------------------- /test/module.test.js: -------------------------------------------------------------------------------- 1 | import ApiGet from '../src/module/api'; 2 | import User from '../src/module/user'; 3 | import Sound from '../src/module/sound'; 4 | 5 | describe('test', () => { 6 | it('It Should return "Hello World!"', () => { 7 | const test = 'Hello World!'; 8 | expect(test).toBe('Hello World!'); 9 | }); 10 | }); 11 | 12 | describe('Test Api', () => { 13 | it('It Should return succeeded message', async () => { 14 | ApiGet('GET') 15 | .then(data => { 16 | expect(data).toEqual('Succeed'); 17 | }); 18 | }); 19 | 20 | it('It Should return err message', async () => { 21 | ApiGet('POST', 'VERRRRY LONG STRINGGGGGGGGGGGGGGG', 1000000000000) 22 | .then(data => { 23 | expect(data).toEqual('err'); 24 | }); 25 | }); 26 | }); 27 | 28 | describe('Test User Module', () => { 29 | const user = new User(); 30 | 31 | it('It Should Set & Return User Values', async () => { 32 | user.user = 'Test'; 33 | expect(user.user).toBe('Test'); 34 | }); 35 | 36 | it('It Should Set & Return Score Values', async () => { 37 | user.score = 100; 38 | expect(user.score).toBe(100); 39 | }); 40 | }); 41 | 42 | 43 | describe('Test Sound Module', () => { 44 | const sound = new Sound(); 45 | 46 | it('It Should Return soundOn Values', async () => { 47 | expect(sound.soundOn).toBe(true); 48 | }); 49 | 50 | it('It Should Set soundOn Values', async () => { 51 | sound.soundOn = false; 52 | expect(sound.soundOn).toBe(false); 53 | }); 54 | 55 | it('It Should Return musicOn Values', async () => { 56 | expect(sound.musicOn).toBe(true); 57 | }); 58 | 59 | it('It Should Set musicOn Values', async () => { 60 | sound.musicOn = false; 61 | expect(sound.musicOn).toBe(false); 62 | }); 63 | 64 | it('It Should Return bgMusicPlaying Values', async () => { 65 | expect(sound.bgMusicPlaying).toBe(false); 66 | }); 67 | 68 | it('It Should Set bgMusicPlaying Values', async () => { 69 | sound.bgMusicPlaying = true; 70 | expect(sound.bgMusicPlaying).toBe(true); 71 | }); 72 | }); 73 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "microverse-js-capstone", 3 | "version": "1.0.0", 4 | "description": "Microverse JavaScript Capstone Project", 5 | "private": true, 6 | "scripts": { 7 | "test": "jest", 8 | "w-jest": "jest --watch", 9 | "dev": "webpack --mode development", 10 | "server": "webpack-dev-server", 11 | "build": "webpack --mode production", 12 | "start": "./node_modules/webpack/bin/webpack.js -p --progress && node server.js" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git+https://github.com/Dandush03/Microverse-JS-Capstone.git" 17 | }, 18 | "author": "Daniel Laloush", 19 | "license": "MIT", 20 | "bugs": { 21 | "url": "https://github.com/Dandush03/Microverse-JS-Capstone/issues" 22 | }, 23 | "homepage": "https://github.com/Dandush03/Microverse-JS-Capstone#readme", 24 | "devDependencies": { 25 | "@babel/plugin-transform-runtime": "^7.9.6", 26 | "@babel/preset-env": "^7.9.6", 27 | "css-loader": "^3.5.2", 28 | "eslint": "^6.8.0", 29 | "eslint-config-airbnb-base": "^14.1.0", 30 | "eslint-plugin-import": "^2.20.2", 31 | "identity-obj-proxy": "^3.0.0", 32 | "jest": "^25.5.1", 33 | "sass": "^1.26.3", 34 | "sass-loader": "^8.0.2", 35 | "style-loader": "^1.1.4", 36 | "webpack": "^4.42.1", 37 | "webpack-cli": "^3.3.11", 38 | "webpack-dev-server": "^3.10.3" 39 | }, 40 | "dependencies": { 41 | "@fortawesome/fontawesome-free": "^5.13.0", 42 | "@fortawesome/fontawesome-svg-core": "^1.2.28", 43 | "@fortawesome/free-brands-svg-icons": "^5.13.0", 44 | "@fortawesome/free-regular-svg-icons": "^5.13.0", 45 | "@fortawesome/free-solid-svg-icons": "^5.13.0", 46 | "express": "^4.17.1", 47 | "file-loader": "^6.0.0", 48 | "phaser": "^3.23.0", 49 | "url-loader": "^4.1.0" 50 | }, 51 | "jest": { 52 | "moduleNameMapper": { 53 | "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/__mocks__/fileMock.js", 54 | "\\.(s?css|less)$": "identity-obj-proxy" 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | 84 | # Gatsby files 85 | .cache/ 86 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 87 | # https://nextjs.org/blog/next-9-1#public-directory-support 88 | # public 89 | 90 | # vuepress build output 91 | .vuepress/dist 92 | 93 | # Serverless directories 94 | .serverless/ 95 | 96 | # FuseBox cache 97 | .fusebox/ 98 | 99 | # DynamoDB Local files 100 | .dynamodb/ 101 | 102 | # TernJS port file 103 | .tern-port 104 | 105 | # Local Netlify folder 106 | .netlify 107 | 108 | # GIM Elements 109 | *.xcf -------------------------------------------------------------------------------- /src/scenes/option.js: -------------------------------------------------------------------------------- 1 | import { GAME_HEIGHT, GAME_WIDTH } from '../config/const-variable'; 2 | 3 | // eslint-disable-next-line no-undef 4 | export default class OptionsScene extends Phaser.Scene { 5 | constructor() { 6 | super('Options'); 7 | } 8 | 9 | create() { 10 | this.soundModel = this.sys.game.globals.soundModel; 11 | this.add.image(GAME_WIDTH / 2, (GAME_HEIGHT / 2), 'sky'); 12 | this.add.image(GAME_WIDTH - 68, GAME_HEIGHT - 34, 'logo').setScale(0.3); 13 | 14 | this.gameBtn = this.add.image(110, 50, 'back').setInteractive(); 15 | this.gameBtn.on('pointerdown', () => { 16 | this.scene.start('Title'); 17 | }); 18 | 19 | this.input.on('pointerover', (event, gameObjects) => { 20 | gameObjects[0].setScale(1.1); 21 | }); 22 | 23 | this.input.on('pointerout', (event, gameObjects) => { 24 | gameObjects[0].setScale(1); 25 | }); 26 | 27 | this.text = this.add.text((GAME_WIDTH / 2) - 100, (GAME_HEIGHT / 6), 'Options', { fontSize: 40 }); 28 | this.musicButton = this.add.image(((GAME_WIDTH / 2) - 50) - 100, (GAME_HEIGHT / 3), 'checkedBox'); 29 | this.musicText = this.add.text((GAME_WIDTH / 2) - 100, (GAME_HEIGHT / 3) - 15, 'Music Enabled', { fontSize: 24 }); 30 | 31 | this.soundButton = this.add.image(((GAME_WIDTH / 2) - 50) - 100, (GAME_HEIGHT / 2), 'checkedBox'); 32 | this.soundText = this.add.text((GAME_WIDTH / 2) - 100, (GAME_HEIGHT / 2) - 15, 'Sound Enabled', { fontSize: 24 }); 33 | 34 | this.musicButton.setInteractive(); 35 | this.soundButton.setInteractive(); 36 | 37 | this.musicButton.on('pointerdown', () => { 38 | this.soundModel.musicOn = !this.soundModel.musicOn; 39 | this.updateAudio(); 40 | }); 41 | 42 | 43 | this.soundButton.on('pointerdown', () => { 44 | this.soundModel.soundOn = !this.soundModel.soundOn; 45 | this.updateAudio(); 46 | }); 47 | 48 | this.updateAudio(); 49 | } 50 | 51 | updateAudio() { 52 | if (this.soundModel.musicOn === false) { 53 | this.musicButton.setTexture('box'); 54 | this.sys.game.globals.bgMusic.stop(); 55 | this.soundModel.bgMusicPlaying = false; 56 | } else { 57 | this.musicButton.setTexture('checkedBox'); 58 | if (this.soundModel.bgMusicPlaying === false) { 59 | this.sys.game.globals.bgMusic.play(); 60 | this.soundModel.bgMusicPlaying = true; 61 | } 62 | } 63 | 64 | if (this.soundModel.soundOn === false) { 65 | this.soundButton.setTexture('box'); 66 | } else { 67 | this.soundButton.setTexture('checkedBox'); 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /src/scenes/score.js: -------------------------------------------------------------------------------- 1 | import { GAME_HEIGHT, GAME_WIDTH } from '../config/const-variable'; 2 | import ApiGet from '../module/api'; 3 | 4 | 5 | // eslint-disable-next-line no-undef 6 | export default class ScoresScene extends Phaser.Scene { 7 | constructor() { 8 | super('Scores'); 9 | } 10 | 11 | create() { 12 | this.sys.canvas.style.cursor = 'progress'; 13 | let height = 50; 14 | let bgTime = 1; 15 | ApiGet('GET', 'Daniel', 114) 16 | .then(data => { 17 | data.sort((a, b) => b.score - a.score); 18 | Object.keys(data).forEach((score, index) => { 19 | if (height > GAME_HEIGHT * bgTime) { 20 | this.bg = this.add.image(GAME_WIDTH / 2, (GAME_HEIGHT / 2) + height - 50, 'sky'); 21 | bgTime += 1; 22 | if (bgTime % 2 === 0) { 23 | this.bg.rotation = 3.14159; 24 | } 25 | } 26 | 27 | this.img = this.add.image(GAME_WIDTH / 2, height, 'emptyTag'); 28 | 29 | this.lbl = this.make.text({ 30 | text: `${index + 1} - `, 31 | style: { 32 | fill: '#422115', 33 | }, 34 | }); 35 | this.lbl.x = this.img.x - (this.img.width / 2) + 15; 36 | this.lbl.y = height; 37 | 38 | this.display = this.make.text({ 39 | text: `${data[score].user} : ${data[score].score}`, 40 | style: { 41 | fill: '#422115', 42 | }, 43 | }); 44 | this.display.x = this.lbl.x + this.lbl.width; 45 | this.display.y = height; 46 | height += 100; 47 | 48 | if (index === data.length - 1) { 49 | this.logo = this.add.image(GAME_WIDTH - 68, GAME_HEIGHT - 34, 'logo').setScale(0.3).setScrollFactor(0); 50 | this.sys.canvas.style.cursor = 'default'; 51 | } 52 | }); 53 | }); 54 | 55 | this.add.image(GAME_WIDTH / 2, (GAME_HEIGHT / 2), 'sky'); 56 | 57 | this.gameBtn = this.add.image(110, 50, 'back').setInteractive(); 58 | this.gameBtn.on('pointerdown', () => { 59 | this.scene.start('Title'); 60 | }); 61 | 62 | this.input.on('pointerover', (event, gameObjects) => { 63 | gameObjects[0].setScale(1.1); 64 | }); 65 | 66 | this.input.on('pointerout', (event, gameObjects) => { 67 | gameObjects[0].setScale(1); 68 | }); 69 | 70 | this.input.on('wheel', (pointer, gameObjects, deltaX, deltaY) => { 71 | this.cameras.main.scrollY += deltaY * 10.5; 72 | if (this.cameras.main.scrollY <= 0) { 73 | this.cameras.main.scrollY = 0; 74 | } else if (this.cameras.main.scrollY >= height - GAME_HEIGHT) { 75 | this.cameras.main.scrollY = height - GAME_HEIGHT; 76 | } 77 | }); 78 | } 79 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Microverse-JS-Capstone 2 | # Daniel Review Gem (DRev) [![Awesome](https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg)](https://github.com/Dandush03/capstone-build-linter) 3 | [![License](https://img.shields.io/badge/License-MIT-green.svg)]() 4 | ![GitHub followers](https://img.shields.io/github/followers/Dandush03?label=Dandush03&style=social) 5 | ![Twitter URL](https://img.shields.io/twitter/url?label=d_laloush&style=social&url=https%3A%2F%2Ftwitter.com%2Fd_laloush) 6 | 7 | > This is a Microverse Capstone Project 8 | 9 | > My First JS Game 10 | 11 | ![Recordit GIF](game-play.gif) 12 | 13 | --- 14 | 15 | ## Table of Contents 16 | 17 | - [Live Link](#Live-Link) 18 | - [Instruction](#Instruction) 19 | - [Coming Soon](#Coming-Soon) 20 | - [Special](#Special) 21 | - [Built With](#Built-With) 22 | - [Support](#Support) 23 | - [Contributing](#Contributing) 24 | - [Acknowledgments](#Acknowledgments) 25 | - [License](#License) 26 | - [Author](#Authors) 27 | 28 | --- 29 | 30 | ## Live Link 31 | 32 | You can start playing right away, just click [here](https://dl-game.herokuapp.com/) and let it load 33 | 34 | --- 35 | 36 | ## Instruction 37 | 38 | This is a very basic game, you need to avoid all those facing that are bouncing on the moon surface, meanwhile, you have to collect as many stars as you can to get the higher score. 39 | 40 | When the game start you have only 3 option arrow Up, Left & Right 41 | 42 | --- 43 | 44 | ## Coming Soon 45 | 46 | There next maps and monsters are coming Soon, in my next release here are some feature you should be looking into: 47 | 48 | - [ ] Implementation of levels 49 | - [ ] New Maps 50 | - [ ] New Heros 51 | - [ ] New Specials Movements 52 | 53 | All that and more 54 | 55 | --- 56 | 57 | ## Special 58 | 59 | As far as now there is just one special movement. You can double jump when you're on top of a star :wink: 60 | 61 | --- 62 | 63 | ## Built With 64 | 65 | - HTML5 66 | - WebPack 67 | - ES6 68 | - Sass 69 | - Vim 70 | - GitHub 71 | - NPM Nodes 72 | 73 | --- 74 | 75 | ## Support 76 | 77 | Reach out to me at one of the following places! 78 | 79 | - LinkedIn at [Daniel Laloush](https://www.linkedin.com/in/daniel-laloush-0a7331a9) 80 | - Twitter at [@d_laloush](https://twitter.com/d_laloush) 81 | 82 | --- 83 | 84 | ## Contributing 85 | 86 | Contributions, issues, and feature requests are welcome! 87 | 88 | Feel free to check the [issues page](./issues/). 89 | --- 90 | 91 | ## Acknowledgments 92 | 93 | - Hat tip to anyone who's code was used 94 | - Thanks to Microverse for its Support! 95 | 96 | --- 97 | 98 | ## Author 99 | 100 | **Daniel Laloush** 101 | 102 | - Portfolio: [dlaloush.me](https://dlaloush.me) 103 | - LinkedIn: [Daniel Laloush](https://www.linkedin.com/in/daniel-laloush-0a7331a9) 104 | - Github: [@Dandush03](https://github.com/Dandush03) 105 | - Twitter: [@d_laloush](https://twitter.com/d_laloush) 106 | 107 | Give a ⭐️ if you like this project! 108 | -------------------------------------------------------------------------------- /src/scenes/user.js: -------------------------------------------------------------------------------- 1 | import { GAME_HEIGHT, GAME_WIDTH } from '../config/const-variable'; 2 | 3 | // eslint-disable-next-line no-undef 4 | export default class UserScene extends Phaser.Scene { 5 | constructor() { 6 | super('User'); 7 | } 8 | 9 | create() { 10 | this.add.image(GAME_WIDTH / 2, (GAME_HEIGHT / 2), 'sky'); 11 | this.add.image(GAME_WIDTH - 68, GAME_HEIGHT - 34, 'logo').setScale(0.3); 12 | 13 | this.gameBtn = this.add.image(110, 50, 'back').setInteractive(); 14 | this.gameBtn.on('pointerdown', () => { 15 | this.scene.start('Title'); 16 | }); 17 | 18 | this.gameBtn = this.add.image((GAME_WIDTH / 2), (GAME_HEIGHT / 1.5), 'submit').setInteractive(); 19 | this.gameBtn.on('pointerdown', () => { 20 | this.start(); 21 | }); 22 | 23 | this.input.on('pointerover', (event, gameObjects) => { 24 | gameObjects[0].setScale(1.1); 25 | }); 26 | 27 | this.input.on('pointerout', (event, gameObjects) => { 28 | gameObjects[0].setScale(1); 29 | }); 30 | 31 | this.lbl = this.make.text({ 32 | text: 'What\'s your name?', 33 | style: { 34 | font: '36px monospace', 35 | fill: '#422115', 36 | }, 37 | }); 38 | this.lbl.x = (GAME_WIDTH / 2) - (this.lbl.width / 2); 39 | this.lbl.y = (GAME_HEIGHT / 4); 40 | 41 | this.nameInput = this.make.text({ 42 | text: 'Yes, Click Here', 43 | style: { 44 | font: '40px monospace', 45 | fill: '#051a58', 46 | }, 47 | selected: false, 48 | }); 49 | this.nameInput.setFontStyle('bold'); 50 | this.nameInput.x = (GAME_WIDTH / 2) - (this.nameInput.width / 2); 51 | this.nameInput.y = (GAME_HEIGHT / 2.5); 52 | 53 | this.nameInput.setInteractive(); 54 | this.input.on('pointerdown', (event, gameObjects) => { 55 | if (gameObjects.length !== 0) { 56 | gameObjects[0].selected = true; 57 | this.nameInput.text = ''; 58 | } else { 59 | this.nameInput.selected = false; 60 | if (this.nameInput.text === '') { 61 | this.nameInput.text = 'Yes, Click Here'; 62 | this.nameInput.x = (GAME_WIDTH / 2) - (this.nameInput.width / 2); 63 | this.nameInput.y = (GAME_HEIGHT / 2.5); 64 | } 65 | } 66 | }); 67 | 68 | this.input.keyboard.on('keydown', (event) => { 69 | if (this.nameInput.selected === true) { 70 | if (event.keyCode >= 65 && event.keyCode <= 90) { 71 | this.nameInput.text += event.key; 72 | } else if (event.keyCode === 32) { 73 | this.nameInput.text += ' '; 74 | } else if (event.keyCode === 8) { 75 | this.nameInput.text = this.nameInput.text.slice(0, -1); 76 | } else if (event.keyCode === 13) { 77 | this.start(); 78 | } 79 | this.nameInput.x = (GAME_WIDTH / 2) - (this.nameInput.width / 2); 80 | this.nameInput.y = (GAME_HEIGHT / 2.5); 81 | } 82 | }); 83 | } 84 | 85 | start() { 86 | const { text } = this.nameInput; 87 | if (text === '' || text === 'Yes, Click Here' || text.length > 9) { 88 | // eslint-disable-next-line no-alert 89 | alert('Invalid Name: Name should have at More than 1 character and less than 9'); 90 | } else { 91 | this.sys.game.globals.userModel.user = this.nameInput.text; 92 | this.scene.start('Game'); 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /src/scenes/preload.js: -------------------------------------------------------------------------------- 1 | import { GAME_HEIGHT, GAME_WIDTH } from '../config/const-variable'; 2 | // eslint-disable-next-line no-undef 3 | export default class PreloadScene extends Phaser.Scene { 4 | constructor() { 5 | super('Preload'); 6 | } 7 | 8 | preload() { 9 | this.load.image('playGame', './assets/ui/play-game.png'); 10 | this.load.image('settings', './assets/ui/settings.png'); 11 | this.load.image('credits', './assets/ui/credits.png'); 12 | this.load.image('scores', './assets/ui/score.png'); 13 | this.load.image('back', './assets/ui/back.png'); 14 | this.load.image('checkedBox', './assets/ui/checked.png'); 15 | this.load.image('box', './assets/ui/unchecked.png'); 16 | this.load.image('emptyTag', './assets/ui/empty-tag.png'); 17 | this.load.image('sky', './assets/sky.png'); 18 | // 19 | // GAME 20 | // 21 | this.load.image('replay', './assets/game/replay.png'); 22 | this.load.image('submit', './assets/game/submit.png'); 23 | this.load.image('endGame', './assets/game/endgame.png'); 24 | this.load.image('stars', './assets/game/star.png'); 25 | this.load.image('ground', './assets/game/ground.png'); 26 | this.load.image('menu', './assets/game/menu.png'); 27 | this.load.image('star', './assets/game/star2.png'); 28 | this.load.image('bigStar', './assets/game/star3.png'); 29 | this.load.spritesheet('face', 'assets/game/metalface78x92.png', 30 | { frameWidth: 78, frameHeight: 92 }); 31 | this.load.spritesheet('heroRun', './assets/game/hero2.png', 32 | { frameWidth: 24, frameHeight: 25 }); 33 | this.load.spritesheet('heroStand', './assets/game/hero1.png', 34 | { frameWidth: 22, frameHeight: 25 }); 35 | 36 | this.load.audio('bgMusic', './assets/ui/bgMusic.mp3'); 37 | 38 | this.add.image(GAME_WIDTH / 2, GAME_HEIGHT / 2, 'logo'); 39 | // display progress bar 40 | const progressBar = this.add.graphics(); 41 | const progressBox = this.add.graphics(); 42 | progressBox.fillStyle(0x222222, 0.8); 43 | progressBox.fillRect(240, 270, 320, 50); 44 | 45 | const loadingText = this.make.text({ 46 | x: GAME_WIDTH / 2, 47 | y: GAME_HEIGHT / 2 - 50, 48 | text: 'Loading...', 49 | style: { 50 | font: '20px monospace', 51 | fill: '#ffffff', 52 | }, 53 | }); 54 | loadingText.setOrigin(0.5, 0.5); 55 | 56 | const percentText = this.make.text({ 57 | x: GAME_WIDTH / 2, 58 | y: GAME_HEIGHT / 2 - 5, 59 | text: '0%', 60 | style: { 61 | font: '18px monospace', 62 | fill: '#ffffff', 63 | }, 64 | }); 65 | percentText.setOrigin(0.5, 0.5); 66 | 67 | const assetText = this.make.text({ 68 | x: GAME_WIDTH / 2, 69 | y: GAME_HEIGHT / 2 + 50, 70 | text: '', 71 | style: { 72 | font: '18px monospace', 73 | fill: '#ffffff', 74 | }, 75 | }); 76 | assetText.setOrigin(0.5, 0.5); 77 | 78 | // update progress bar 79 | this.load.on('progress', (value) => { 80 | // eslint-disable-next-line radix 81 | percentText.setText(`${parseInt(value * 100)}%`); 82 | progressBar.clear(); 83 | progressBar.fillStyle(0xffffff, 1); 84 | progressBar.fillRect(250, 280, 300 * value, 30); 85 | }); 86 | 87 | // update file progress text 88 | this.load.on('fileprogress', (file) => { 89 | assetText.setText(`Loading asset: ${file.key}`); 90 | }); 91 | 92 | // remove progress bar when complete 93 | this.load.on('complete', () => { 94 | progressBar.destroy(); 95 | progressBox.destroy(); 96 | loadingText.destroy(); 97 | percentText.destroy(); 98 | assetText.destroy(); 99 | this.ready(); 100 | }); 101 | this.timedEvent = this.time.delayedCall(1000, this.ready, [], this); 102 | } 103 | 104 | init() { 105 | this.readyCount = 0; 106 | } 107 | 108 | ready() { 109 | this.readyCount += 1; 110 | if (this.readyCount === 2) { 111 | this.scene.start('Title'); 112 | } 113 | } 114 | } -------------------------------------------------------------------------------- /stylelint.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | "use strict" 3 | 4 | module.exports = { 5 | "extends": "stylelint-config-recommended", 6 | "rules": { 7 | "at-rule-empty-line-before": [ "always", { 8 | except: [ 9 | "blockless-after-same-name-blockless", 10 | "first-nested", 11 | ], 12 | ignore: ["after-comment"], 13 | } ], 14 | "at-rule-name-case": "lower", 15 | "at-rule-name-space-after": "always-single-line", 16 | "at-rule-semicolon-newline-after": "always", 17 | "block-closing-brace-empty-line-before": "never", 18 | "block-closing-brace-newline-after": "always", 19 | "block-closing-brace-newline-before": "always-multi-line", 20 | "block-closing-brace-space-before": "always-single-line", 21 | "block-opening-brace-newline-after": "always-multi-line", 22 | "block-opening-brace-space-after": "always-single-line", 23 | "block-opening-brace-space-before": "always", 24 | "color-hex-case": "lower", 25 | "color-hex-length": "short", 26 | "comment-empty-line-before": [ "always", { 27 | except: ["first-nested"], 28 | ignore: ["stylelint-commands"], 29 | } ], 30 | "comment-whitespace-inside": "always", 31 | "custom-property-empty-line-before": [ "always", { 32 | except: [ 33 | "after-custom-property", 34 | "first-nested", 35 | ], 36 | ignore: [ 37 | "after-comment", 38 | "inside-single-line-block", 39 | ], 40 | } ], 41 | "declaration-bang-space-after": "never", 42 | "declaration-bang-space-before": "always", 43 | "declaration-block-semicolon-newline-after": "always-multi-line", 44 | "declaration-block-semicolon-space-after": "always-single-line", 45 | "declaration-block-semicolon-space-before": "never", 46 | "declaration-block-single-line-max-declarations": 1, 47 | "declaration-block-trailing-semicolon": "always", 48 | "declaration-colon-newline-after": "always-multi-line", 49 | "declaration-colon-space-after": "always-single-line", 50 | "declaration-colon-space-before": "never", 51 | "declaration-empty-line-before": [ "always", { 52 | except: [ 53 | "after-declaration", 54 | "first-nested", 55 | ], 56 | ignore: [ 57 | "after-comment", 58 | "inside-single-line-block", 59 | ], 60 | } ], 61 | "function-comma-newline-after": "always-multi-line", 62 | "function-comma-space-after": "always-single-line", 63 | "function-comma-space-before": "never", 64 | "function-max-empty-lines": 0, 65 | "function-name-case": "lower", 66 | "function-parentheses-newline-inside": "always-multi-line", 67 | "function-parentheses-space-inside": "never-single-line", 68 | "function-whitespace-after": "always", 69 | "indentation": 2, 70 | "length-zero-no-unit": true, 71 | "max-empty-lines": 1, 72 | "media-feature-colon-space-after": "always", 73 | "media-feature-colon-space-before": "never", 74 | "media-feature-name-case": "lower", 75 | "media-feature-parentheses-space-inside": "never", 76 | "media-feature-range-operator-space-after": "always", 77 | "media-feature-range-operator-space-before": "always", 78 | "media-query-list-comma-newline-after": "always-multi-line", 79 | "media-query-list-comma-space-after": "always-single-line", 80 | "media-query-list-comma-space-before": "never", 81 | "no-eol-whitespace": true, 82 | "no-missing-end-of-source-newline": true, 83 | "number-leading-zero": "always", 84 | "number-no-trailing-zeros": true, 85 | "property-case": "lower", 86 | "rule-empty-line-before": [ "always-multi-line", { 87 | except: ["first-nested"], 88 | ignore: ["after-comment"], 89 | } ], 90 | "selector-attribute-brackets-space-inside": "never", 91 | "selector-attribute-operator-space-after": "never", 92 | "selector-attribute-operator-space-before": "never", 93 | "selector-combinator-space-after": "always", 94 | "selector-combinator-space-before": "always", 95 | "selector-descendant-combinator-no-non-space": true, 96 | "selector-list-comma-newline-after": "always", 97 | "selector-list-comma-space-before": "never", 98 | "selector-max-empty-lines": 0, 99 | "selector-pseudo-class-case": "lower", 100 | "selector-pseudo-class-parentheses-space-inside": "never", 101 | "selector-pseudo-element-case": "lower", 102 | "selector-pseudo-element-colon-notation": "double", 103 | "selector-type-case": "lower", 104 | "unit-case": "lower", 105 | "value-list-comma-newline-after": "always-multi-line", 106 | "value-list-comma-space-after": "always-single-line", 107 | "value-list-comma-space-before": "never", 108 | "value-list-max-empty-lines": 0, 109 | }, 110 | } 111 | -------------------------------------------------------------------------------- /src/scenes/game.js: -------------------------------------------------------------------------------- 1 | import { GAME_HEIGHT, GAME_WIDTH } from '../config/const-variable'; 2 | 3 | let player; 4 | let platforms; 5 | let face; 6 | let stars; 7 | let score; 8 | let scoreText; 9 | 10 | function collectStar(player, star) { 11 | star.disableBody(true, true); 12 | 13 | score += 10; 14 | scoreText.setText(`Score: ${score}`); 15 | } 16 | 17 | function destroyGame() { 18 | this.scene.pause(); 19 | this.sys.game.globals.userModel.score = score; 20 | this.scene.launch('EndGame'); 21 | } 22 | 23 | // eslint-disable-next-line no-undef 24 | export default class GameScene extends Phaser.Scene { 25 | constructor() { 26 | super('Game'); 27 | } 28 | 29 | create() { 30 | score = 0; 31 | this.cameras.main.setBounds(0, 0, GAME_WIDTH * 100, GAME_HEIGHT).setName('main'); 32 | platforms = this.physics.add.staticGroup(); 33 | 34 | // eslint-disable-next-line no-underscore-dangle 35 | const mainWidth = this.cameras.main._bounds.width; 36 | for (let width = 0; width < mainWidth; width += 2048) { 37 | platforms.create(width, GAME_HEIGHT, 'ground').refreshBody(); 38 | } 39 | 40 | this.anims.create({ 41 | key: 'right', 42 | frames: this.anims.generateFrameNumbers('heroRun', { start: 0, end: 2 }), 43 | frameRate: 10, 44 | repeat: -1, 45 | }); 46 | 47 | this.anims.create({ 48 | key: 'left', 49 | frames: this.anims.generateFrameNumbers('heroRun', { start: 3, end: 5 }), 50 | frameRate: 10, 51 | repeat: -1, 52 | }); 53 | 54 | this.anims.create({ 55 | key: 'standing', 56 | frames: this.anims.generateFrameNumbers('heroStand', { start: 0, end: 3 }), 57 | frameRate: 2, 58 | repeat: -1, 59 | }); 60 | 61 | 62 | player = this.physics.add.sprite(GAME_WIDTH / 8, GAME_HEIGHT / 2, 'hero').setScale(2); 63 | 64 | player.setBounce(0.3); 65 | player.setCollideWorldBounds(true); 66 | 67 | player.body.setSize(25, 20); 68 | this.Starfield(); 69 | this.Aliens(); 70 | this.Stars(); 71 | scoreText = this.add.text(16, 16, 'score: 0', { fontSize: '32px', fill: '#fff' }); 72 | this.physics.add.collider(player, platforms); 73 | this.add.image(GAME_WIDTH - 68, GAME_HEIGHT - 34, 'logo').setScale(0.3).setScrollFactor(0); 74 | } 75 | 76 | update() { 77 | const cursors = this.input.keyboard.createCursorKeys(); 78 | if (cursors.right.isDown) { 79 | player.setVelocityX(400); 80 | player.anims.play('right', true); 81 | } else if (cursors.left.isDown) { 82 | player.setVelocityX(-400); 83 | player.anims.play('left', true); 84 | } else { 85 | player.setVelocityX(0); 86 | player.anims.play('standing', true); 87 | } 88 | 89 | if (cursors.up.isDown && player.body.touching.down) { 90 | player.setVelocityY(GAME_HEIGHT * -1); 91 | player.anims.play('right', true); 92 | } 93 | 94 | this.cameras.main.scrollX = player.x - GAME_WIDTH / 2; 95 | scoreText.setScrollFactor(0, 0); 96 | } 97 | 98 | Starfield() { 99 | // Note the scrollFactor values which give them their 'parallax' effect 100 | 101 | const group = this.add.group({ key: 'star', frameQuantity: 2000 }); 102 | 103 | group.createMultiple({ key: 'bigStar', frameQuantity: 200 }); 104 | 105 | // eslint-disable-next-line no-undef 106 | const rect = new Phaser.Geom.Rectangle(0, 0, GAME_WIDTH * 100, 400); 107 | // eslint-disable-next-line no-undef 108 | Phaser.Actions.RandomRectangle(group.getChildren(), rect); 109 | 110 | group.children.iterate((child) => { 111 | let sf = Math.max(0.3, Math.random()); 112 | 113 | if (child.texture.key === 'bigStar') { 114 | sf = 0.2; 115 | } 116 | 117 | child.setScrollFactor(sf); 118 | }, this); 119 | } 120 | 121 | Stars() { 122 | // eslint-disable-next-line no-undef 123 | const rect = new Phaser.Geom.Rectangle(0, 300, GAME_WIDTH * 100, 150); 124 | stars = this.physics.add.group({ 125 | key: 'stars', 126 | repeat: 400, 127 | setXY: { x: 12, y: 50, stepX: 70 }, 128 | allowGravity: false, 129 | }); 130 | // eslint-disable-next-line no-undef 131 | Phaser.Actions.RandomRectangle(stars.getChildren(), rect); 132 | 133 | this.physics.add.collider(stars, platforms); 134 | this.physics.add.overlap(player, stars, collectStar, null, this); 135 | } 136 | 137 | Aliens() { 138 | // eslint-disable-next-line no-undef 139 | const rect = new Phaser.Geom.Rectangle(800, 300, GAME_WIDTH * 100, 150); 140 | 141 | const config = { 142 | key: 'metaleyes', 143 | frames: this.anims.generateFrameNumbers('face', { start: 0, end: 4 }), 144 | frameRate: 20, 145 | repeat: -1, 146 | }; 147 | 148 | this.anims.create(config); 149 | for (let i = 0; i < 32; i += 1) { 150 | // eslint-disable-next-line no-undef 151 | const x = Phaser.Math.Between(100, 30000); 152 | // eslint-disable-next-line no-undef 153 | const y = Phaser.Math.Between(100, 300); 154 | 155 | face = this.physics.add.sprite(x, y, 'face').play('metaleyes'); 156 | this.physics.add.collider(face, platforms); 157 | face.setBounce(1); 158 | face.setCollideWorldBounds(true); 159 | // eslint-disable-next-line no-undef 160 | face.setVelocity(Phaser.Math.Between(20, 60), Phaser.Math.Between(20, 60)); 161 | 162 | this.physics.add.overlap(player, face, destroyGame, null, this); 163 | // eslint-disable-next-line no-undef 164 | Phaser.Actions.RandomRectangle(face, rect); 165 | } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /dist/main.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, { enumerable: true, get: getter }); 40 | /******/ } 41 | /******/ }; 42 | /******/ 43 | /******/ // define __esModule on exports 44 | /******/ __webpack_require__.r = function(exports) { 45 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 46 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 47 | /******/ } 48 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 49 | /******/ }; 50 | /******/ 51 | /******/ // create a fake namespace object 52 | /******/ // mode & 1: value is a module id, require it 53 | /******/ // mode & 2: merge all properties of value into the ns 54 | /******/ // mode & 4: return value when already ns object 55 | /******/ // mode & 8|1: behave like require 56 | /******/ __webpack_require__.t = function(value, mode) { 57 | /******/ if(mode & 1) value = __webpack_require__(value); 58 | /******/ if(mode & 8) return value; 59 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 60 | /******/ var ns = Object.create(null); 61 | /******/ __webpack_require__.r(ns); 62 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 63 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 64 | /******/ return ns; 65 | /******/ }; 66 | /******/ 67 | /******/ // getDefaultExport function for compatibility with non-harmony modules 68 | /******/ __webpack_require__.n = function(module) { 69 | /******/ var getter = module && module.__esModule ? 70 | /******/ function getDefault() { return module['default']; } : 71 | /******/ function getModuleExports() { return module; }; 72 | /******/ __webpack_require__.d(getter, 'a', getter); 73 | /******/ return getter; 74 | /******/ }; 75 | /******/ 76 | /******/ // Object.prototype.hasOwnProperty.call 77 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 78 | /******/ 79 | /******/ // __webpack_public_path__ 80 | /******/ __webpack_require__.p = ""; 81 | /******/ 82 | /******/ 83 | /******/ // Load entry module and return exports 84 | /******/ return __webpack_require__(__webpack_require__.s = "./src/index.js"); 85 | /******/ }) 86 | /************************************************************************/ 87 | /******/ ({ 88 | 89 | /***/ "./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/stylesheet/main.scss": 90 | /*!***************************************************************************************************************!*\ 91 | !*** ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/stylesheet/main.scss ***! 92 | \***************************************************************************************************************/ 93 | /*! no static exports found */ 94 | /***/ (function(module, exports, __webpack_require__) { 95 | 96 | eval("// Imports\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\nexports = ___CSS_LOADER_API_IMPORT___(false);\n// Module\nexports.push([module.i, \"* {\\n box-sizing: border-box;\\n}\\n\\nbody {\\n display: flex;\\n height: 100vh;\\n justify-content: center;\\n margin: 0;\\n padding: 0;\\n width: 100vw;\\n}\\nbody > canvas {\\n width: 100vw;\\n}\", \"\"]);\n// Exports\nmodule.exports = exports;\n\n\n//# sourceURL=webpack:///./src/stylesheet/main.scss?./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js"); 97 | 98 | /***/ }), 99 | 100 | /***/ "./node_modules/css-loader/dist/runtime/api.js": 101 | /*!*****************************************************!*\ 102 | !*** ./node_modules/css-loader/dist/runtime/api.js ***! 103 | \*****************************************************/ 104 | /*! no static exports found */ 105 | /***/ (function(module, exports, __webpack_require__) { 106 | 107 | "use strict"; 108 | eval("\n\n/*\n MIT License http://www.opensource.org/licenses/mit-license.php\n Author Tobias Koppers @sokra\n*/\n// css base code, injected by the css-loader\n// eslint-disable-next-line func-names\nmodule.exports = function (useSourceMap) {\n var list = []; // return the list of modules as css string\n\n list.toString = function toString() {\n return this.map(function (item) {\n var content = cssWithMappingToString(item, useSourceMap);\n\n if (item[2]) {\n return \"@media \".concat(item[2], \" {\").concat(content, \"}\");\n }\n\n return content;\n }).join('');\n }; // import a list of modules into the list\n // eslint-disable-next-line func-names\n\n\n list.i = function (modules, mediaQuery, dedupe) {\n if (typeof modules === 'string') {\n // eslint-disable-next-line no-param-reassign\n modules = [[null, modules, '']];\n }\n\n var alreadyImportedModules = {};\n\n if (dedupe) {\n for (var i = 0; i < this.length; i++) {\n // eslint-disable-next-line prefer-destructuring\n var id = this[i][0];\n\n if (id != null) {\n alreadyImportedModules[id] = true;\n }\n }\n }\n\n for (var _i = 0; _i < modules.length; _i++) {\n var item = [].concat(modules[_i]);\n\n if (dedupe && alreadyImportedModules[item[0]]) {\n // eslint-disable-next-line no-continue\n continue;\n }\n\n if (mediaQuery) {\n if (!item[2]) {\n item[2] = mediaQuery;\n } else {\n item[2] = \"\".concat(mediaQuery, \" and \").concat(item[2]);\n }\n }\n\n list.push(item);\n }\n };\n\n return list;\n};\n\nfunction cssWithMappingToString(item, useSourceMap) {\n var content = item[1] || ''; // eslint-disable-next-line prefer-destructuring\n\n var cssMapping = item[3];\n\n if (!cssMapping) {\n return content;\n }\n\n if (useSourceMap && typeof btoa === 'function') {\n var sourceMapping = toComment(cssMapping);\n var sourceURLs = cssMapping.sources.map(function (source) {\n return \"/*# sourceURL=\".concat(cssMapping.sourceRoot || '').concat(source, \" */\");\n });\n return [content].concat(sourceURLs).concat([sourceMapping]).join('\\n');\n }\n\n return [content].join('\\n');\n} // Adapted from convert-source-map (MIT)\n\n\nfunction toComment(sourceMap) {\n // eslint-disable-next-line no-undef\n var base64 = btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap))));\n var data = \"sourceMappingURL=data:application/json;charset=utf-8;base64,\".concat(base64);\n return \"/*# \".concat(data, \" */\");\n}\n\n//# sourceURL=webpack:///./node_modules/css-loader/dist/runtime/api.js?"); 109 | 110 | /***/ }), 111 | 112 | /***/ "./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js": 113 | /*!****************************************************************************!*\ 114 | !*** ./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js ***! 115 | \****************************************************************************/ 116 | /*! no static exports found */ 117 | /***/ (function(module, exports, __webpack_require__) { 118 | 119 | "use strict"; 120 | eval("\n\nvar isOldIE = function isOldIE() {\n var memo;\n return function memorize() {\n if (typeof memo === 'undefined') {\n // Test for IE <= 9 as proposed by Browserhacks\n // @see http://browserhacks.com/#hack-e71d8692f65334173fee715c222cb805\n // Tests for existence of standard globals is to allow style-loader\n // to operate correctly into non-standard environments\n // @see https://github.com/webpack-contrib/style-loader/issues/177\n memo = Boolean(window && document && document.all && !window.atob);\n }\n\n return memo;\n };\n}();\n\nvar getTarget = function getTarget() {\n var memo = {};\n return function memorize(target) {\n if (typeof memo[target] === 'undefined') {\n var styleTarget = document.querySelector(target); // Special case to return head of iframe instead of iframe itself\n\n if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) {\n try {\n // This will throw an exception if access to iframe is blocked\n // due to cross-origin restrictions\n styleTarget = styleTarget.contentDocument.head;\n } catch (e) {\n // istanbul ignore next\n styleTarget = null;\n }\n }\n\n memo[target] = styleTarget;\n }\n\n return memo[target];\n };\n}();\n\nvar stylesInDom = [];\n\nfunction getIndexByIdentifier(identifier) {\n var result = -1;\n\n for (var i = 0; i < stylesInDom.length; i++) {\n if (stylesInDom[i].identifier === identifier) {\n result = i;\n break;\n }\n }\n\n return result;\n}\n\nfunction modulesToDom(list, options) {\n var idCountMap = {};\n var identifiers = [];\n\n for (var i = 0; i < list.length; i++) {\n var item = list[i];\n var id = options.base ? item[0] + options.base : item[0];\n var count = idCountMap[id] || 0;\n var identifier = \"\".concat(id, \" \").concat(count);\n idCountMap[id] = count + 1;\n var index = getIndexByIdentifier(identifier);\n var obj = {\n css: item[1],\n media: item[2],\n sourceMap: item[3]\n };\n\n if (index !== -1) {\n stylesInDom[index].references++;\n stylesInDom[index].updater(obj);\n } else {\n stylesInDom.push({\n identifier: identifier,\n updater: addStyle(obj, options),\n references: 1\n });\n }\n\n identifiers.push(identifier);\n }\n\n return identifiers;\n}\n\nfunction insertStyleElement(options) {\n var style = document.createElement('style');\n var attributes = options.attributes || {};\n\n if (typeof attributes.nonce === 'undefined') {\n var nonce = true ? __webpack_require__.nc : undefined;\n\n if (nonce) {\n attributes.nonce = nonce;\n }\n }\n\n Object.keys(attributes).forEach(function (key) {\n style.setAttribute(key, attributes[key]);\n });\n\n if (typeof options.insert === 'function') {\n options.insert(style);\n } else {\n var target = getTarget(options.insert || 'head');\n\n if (!target) {\n throw new Error(\"Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.\");\n }\n\n target.appendChild(style);\n }\n\n return style;\n}\n\nfunction removeStyleElement(style) {\n // istanbul ignore if\n if (style.parentNode === null) {\n return false;\n }\n\n style.parentNode.removeChild(style);\n}\n/* istanbul ignore next */\n\n\nvar replaceText = function replaceText() {\n var textStore = [];\n return function replace(index, replacement) {\n textStore[index] = replacement;\n return textStore.filter(Boolean).join('\\n');\n };\n}();\n\nfunction applyToSingletonTag(style, index, remove, obj) {\n var css = remove ? '' : obj.media ? \"@media \".concat(obj.media, \" {\").concat(obj.css, \"}\") : obj.css; // For old IE\n\n /* istanbul ignore if */\n\n if (style.styleSheet) {\n style.styleSheet.cssText = replaceText(index, css);\n } else {\n var cssNode = document.createTextNode(css);\n var childNodes = style.childNodes;\n\n if (childNodes[index]) {\n style.removeChild(childNodes[index]);\n }\n\n if (childNodes.length) {\n style.insertBefore(cssNode, childNodes[index]);\n } else {\n style.appendChild(cssNode);\n }\n }\n}\n\nfunction applyToTag(style, options, obj) {\n var css = obj.css;\n var media = obj.media;\n var sourceMap = obj.sourceMap;\n\n if (media) {\n style.setAttribute('media', media);\n } else {\n style.removeAttribute('media');\n }\n\n if (sourceMap && btoa) {\n css += \"\\n/*# sourceMappingURL=data:application/json;base64,\".concat(btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))), \" */\");\n } // For old IE\n\n /* istanbul ignore if */\n\n\n if (style.styleSheet) {\n style.styleSheet.cssText = css;\n } else {\n while (style.firstChild) {\n style.removeChild(style.firstChild);\n }\n\n style.appendChild(document.createTextNode(css));\n }\n}\n\nvar singleton = null;\nvar singletonCounter = 0;\n\nfunction addStyle(obj, options) {\n var style;\n var update;\n var remove;\n\n if (options.singleton) {\n var styleIndex = singletonCounter++;\n style = singleton || (singleton = insertStyleElement(options));\n update = applyToSingletonTag.bind(null, style, styleIndex, false);\n remove = applyToSingletonTag.bind(null, style, styleIndex, true);\n } else {\n style = insertStyleElement(options);\n update = applyToTag.bind(null, style, options);\n\n remove = function remove() {\n removeStyleElement(style);\n };\n }\n\n update(obj);\n return function updateStyle(newObj) {\n if (newObj) {\n if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap) {\n return;\n }\n\n update(obj = newObj);\n } else {\n remove();\n }\n };\n}\n\nmodule.exports = function (list, options) {\n options = options || {}; // Force single-tag solution on IE6-9, which has a hard limit on the # of