├── 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) [](https://github.com/Dandush03/capstone-build-linter)
3 | []()
4 | 
5 | 
6 |
7 | > This is a Microverse Capstone Project
8 |
9 | > My First JS Game
10 |
11 | 
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