├── .babelrc ├── media └── 04b03.font.png ├── example ├── media │ ├── fire01.png │ ├── spiker.png │ ├── bg_layer1.png │ ├── 04b03.font.png │ └── helicopter.png └── lib │ └── game │ ├── main.js │ ├── entities │ ├── bullets │ │ ├── BulletBombe.js │ │ └── Bullet.js │ └── characters │ │ ├── CharacterSpike.js │ │ ├── CharacterFlight.js │ │ └── Character.js │ ├── screens │ └── Arena.js │ └── levels │ └── level.js ├── .gitignore ├── index.js ├── example.js ├── index.html ├── lib ├── game │ └── main.js └── impactES6 │ └── index.js ├── package.json ├── LICENSE ├── webpack.config.js ├── README.md └── dist └── game.min.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"] 3 | } -------------------------------------------------------------------------------- /media/04b03.font.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brochard-tech/impactES6/HEAD/media/04b03.font.png -------------------------------------------------------------------------------- /example/media/fire01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brochard-tech/impactES6/HEAD/example/media/fire01.png -------------------------------------------------------------------------------- /example/media/spiker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brochard-tech/impactES6/HEAD/example/media/spiker.png -------------------------------------------------------------------------------- /example/media/bg_layer1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brochard-tech/impactES6/HEAD/example/media/bg_layer1.png -------------------------------------------------------------------------------- /example/media/04b03.font.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brochard-tech/impactES6/HEAD/example/media/04b03.font.png -------------------------------------------------------------------------------- /example/media/helicopter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brochard-tech/impactES6/HEAD/example/media/helicopter.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | node_modules/ 3 | lib/impact 4 | lib/weltmeister 5 | example/lib/impact 6 | example/lib/weltmeister 7 | npm-debug.log 8 | weltmeister.html -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // Import impact library 2 | import "lib/impact/impact"; 3 | 4 | // Merge features into new ImpactEngine 5 | ig.mergeES5(); 6 | window.ig = ig; 7 | 8 | // Import main game 9 | require('lib/game/main'); -------------------------------------------------------------------------------- /example/lib/game/main.js: -------------------------------------------------------------------------------- 1 | import Arena from "./screens/Arena"; 2 | 3 | // Method to require an impact library 4 | // Once it is loaded, it doesn't need to require it again 5 | ig.require('impact.debug.debug'); 6 | 7 | // Launch the game 8 | ig.main('#canvas', Arena, 60, 500, 500, 1); -------------------------------------------------------------------------------- /example.js: -------------------------------------------------------------------------------- 1 | // We redefine the requirecontext to be able to require all ES5 files presents in the example folder 2 | ig.requirecontext = require.context('example/lib/', true, /^((?![\\/]impactES6|weltmeister[\\/]).)*\.js$/); 3 | 4 | 5 | // Import impact library 6 | import "lib/impact/impact"; 7 | 8 | // Merge features into new ImpactEngine 9 | ig.mergeES5(); 10 | window.ig = ig; 11 | 12 | require('example/lib/game/main'); -------------------------------------------------------------------------------- /example/lib/game/entities/bullets/BulletBombe.js: -------------------------------------------------------------------------------- 1 | ig.require('game.entities.bullets.bullet'); 2 | 3 | 4 | export default class BulletBombe extends ig.EntityBullet { 5 | /* LIFECYCLE */ 6 | } 7 | 8 | ig.bindProperties(BulletBombe, { 9 | animSheet : new ig.AnimationSheet('example/media/fire01.png', 14, 32), 10 | size : {x: 14, y: 32}, 11 | vel : {x: 0, y: 300}, 12 | amount : 40 13 | }); -------------------------------------------------------------------------------- /example/lib/game/entities/characters/CharacterSpike.js: -------------------------------------------------------------------------------- 1 | import Character from "./Character"; 2 | 3 | 4 | export default class CharacterSpike extends Character { 5 | /* LIFECYCLE */ 6 | init (x, y, settings) 7 | { 8 | super.init(x, y, settings); 9 | 10 | // Animations 11 | this.addAnim('idle', 1, [0]); 12 | this.addAnim('walk', 0.2, [1, 2]); 13 | } 14 | } 15 | 16 | 17 | ig.bindProperties(CharacterSpike, { 18 | animSheet : new ig.AnimationSheet('example/media/spiker.png', 30, 40), 19 | size : {x: 30, y: 40}, 20 | type : ig.Entity.TYPE.B, 21 | checkAgainst : ig.Entity.TYPE.A 22 | }); -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Impact Game 6 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /lib/game/main.js: -------------------------------------------------------------------------------- 1 | // Method to require an impact library 2 | // Once it is loaded, it doesn't need to require it again 3 | ig.require('impact.game'); 4 | ig.require('impact.debug.debug'); 5 | 6 | 7 | export default class MyGame extends ig.Game { 8 | init () 9 | { 10 | // Custom actions at initialization 11 | } 12 | 13 | update () 14 | { 15 | // Update all entities and backgroundMaps 16 | super.update(); 17 | 18 | // Add your own, additional update code here 19 | } 20 | 21 | draw () 22 | { 23 | // Draw all entities and backgroundMaps 24 | super.draw(); 25 | 26 | // Add your own drawing code here 27 | var x = ig.system.width / 2, 28 | y = ig.system.height / 2; 29 | 30 | this.font.draw('It Works!', x, y, ig.Font.ALIGN.CENTER); 31 | } 32 | } 33 | 34 | // Declare properties 35 | ig.bindProperties(MyGame, { 36 | font : new ig.Font('media/04b03.font.png') 37 | }); 38 | 39 | 40 | ig.main('#canvas', MyGame, 60, 320, 240, 2); -------------------------------------------------------------------------------- /example/lib/game/entities/characters/CharacterFlight.js: -------------------------------------------------------------------------------- 1 | import Character from "./Character"; 2 | import BulletBombe from "./../bullets/BulletBombe"; 3 | 4 | 5 | export default class CharacterFlight extends Character { 6 | /* LIFECYCLE */ 7 | init (x, y, settings) 8 | { 9 | super.init(x, y, settings); 10 | 11 | this.addAnim('idle', 1, [0]); 12 | } 13 | 14 | update () 15 | { 16 | super.update(); 17 | } 18 | 19 | 20 | /* METHOD */ 21 | fire () 22 | { 23 | if (super.fire()) { 24 | ig.game.spawnEntity(BulletBombe, this.pos.x + (this.size.x / 2), this.pos.y + this.size.y, { owner: this }); 25 | } 26 | } 27 | } 28 | 29 | ig.bindProperties(CharacterFlight, { 30 | animSheet : new ig.AnimationSheet('example/media/helicopter.png', 43, 36), 31 | size : {x: 43, y: 36}, 32 | type : ig.Entity.TYPE.A, 33 | checkAgainst : ig.Entity.TYPE.B, 34 | gravityFactor : 0, 35 | zIndex : 1, 36 | speed : 300 37 | }); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "impactes6", 3 | "version": "0.3.0", 4 | "description": "This project allow you tu use ES6 with ImpactJS", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "./node_modules/.bin/webpack -p --config webpack.config.js --progress --profile --colors", 8 | "build-dev": "./node_modules/.bin/webpack -d --config webpack.config.js --watch --progress --profile --colors", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/myvertigo/impactES6.git" 14 | }, 15 | "author": "Christophe Brochard (http://www.myvertigo.fr)", 16 | "license": "ISC", 17 | "bugs": { 18 | "url": "https://github.com/myvertigo/impactES6/issues" 19 | }, 20 | "homepage": "https://github.com/myvertigo/impactES6#readme", 21 | "dependencies": { 22 | "imports-loader": "^0.6.5", 23 | "jquery": "^3.1.0" 24 | }, 25 | "devDependencies": { 26 | "babel-loader": "^6.2.5", 27 | "babel-preset-es2015": "^6.14.0", 28 | "webpack": "^1.13.2" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 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 | -------------------------------------------------------------------------------- /example/lib/game/entities/bullets/Bullet.js: -------------------------------------------------------------------------------- 1 | ig.module( 2 | 'game.entities.bullets.bullet' 3 | 4 | ).requires( 5 | 'impact.entity' 6 | 7 | ).defines(function () { 8 | 9 | ig.EntityBullet = ig.Entity.extend({ 10 | /* ATTRIBUTES */ 11 | amount: 10, 12 | owner : null, 13 | 14 | 15 | /* LIFECYCLE */ 16 | init: function (x, y, settings) 17 | { 18 | this.parent(x, y, settings); 19 | 20 | if (this.owner) { 21 | this.type = this.owner.type; 22 | this.checkAgainst = (this.type === ig.Entity.TYPE.A) ? ig.Entity.TYPE.B : ig.Entity.TYPE.A; 23 | } 24 | 25 | if (this.animSheet) { 26 | this.addAnim('idle', 1, [0]); 27 | } 28 | }, 29 | 30 | update: function () 31 | { 32 | this.parent(); 33 | 34 | if (this.pos.x < 0 || this.pos.y < 0 || this.pos.x > ig.system.width || this.pos.y > ig.system.height) { 35 | this.kill(); 36 | } 37 | 38 | return 4; 39 | }, 40 | 41 | check: function (other) 42 | { 43 | other.receiveDamage(this.amount); 44 | this.kill(); 45 | } 46 | }); 47 | 48 | }); -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | 4 | module.exports = { 5 | // Entry file JS 6 | entry: { 7 | game : './index.js', 8 | example : './example.js' 9 | }, 10 | 11 | // File minified 12 | output: { 13 | path: path.join(__dirname, 'dist'), 14 | filename: '[name].min.js' 15 | }, 16 | 17 | // Set shorcut to js files 18 | resolve: { 19 | root: path.resolve(__dirname), 20 | alias: { 21 | ig: 'lib/impactES6' 22 | }, 23 | extensions: ['', '.js'] 24 | }, 25 | 26 | plugins: [ 27 | // Create global variables 28 | new webpack.ProvidePlugin({ 29 | ig: 'ig', 30 | $: 'jquery', 31 | jQuery: 'jquery', 32 | 'window.jQuery': 'jquery' 33 | }) 34 | ], 35 | 36 | module: { 37 | // Babel ES6 Loader 38 | loaders: [ 39 | { 40 | test: /\.js$/, 41 | loader: 'imports?this=>window', 42 | exclude: '/node_modules/' 43 | }, 44 | 45 | { 46 | test: /\.js$/, 47 | loader: 'babel-loader', 48 | exclude: /node_modules/, 49 | query: { 50 | presets: ['es2015'] 51 | } 52 | } 53 | ] 54 | } 55 | }; -------------------------------------------------------------------------------- /example/lib/game/entities/characters/Character.js: -------------------------------------------------------------------------------- 1 | ig.require('impact.entity'); 2 | 3 | 4 | export default class Character extends ig.Entity { 5 | /* LIFECYCLE */ 6 | update () 7 | { 8 | super.update(); 9 | 10 | if (this.currentAnim) { 11 | this.updateAnimation(); 12 | } 13 | } 14 | 15 | check () 16 | { 17 | this.kill(); 18 | } 19 | 20 | 21 | /* METHODS */ 22 | updateAnimation () 23 | { 24 | this.currentAnim.flip.x = this.flip; 25 | } 26 | 27 | setDirection (speedType, x, y) 28 | { 29 | if (speedType !== "vel" && speedType !== "accel") { 30 | return null; 31 | } 32 | 33 | this[speedType].y = (y || 0) * this.speed; 34 | this[speedType].x = (x || 0) * this.speed; 35 | } 36 | 37 | setVel (x, y) 38 | { 39 | this.setDirection('vel', x, y); 40 | } 41 | 42 | setAccel (x, y) 43 | { 44 | if (!x && !y && !this.accel.x && !this.accel.y) { 45 | return null; 46 | } 47 | 48 | this.setDirection('accel', x, y); 49 | } 50 | 51 | fire () 52 | { 53 | if (this._killed) { 54 | return false; 55 | } 56 | 57 | if (!this.timerWeaponWait) { 58 | this.timerWeaponWait = new ig.Timer(this.timeWeaponWait / 100); 59 | return true; 60 | 61 | } else if (this.timerWeaponWait.delta() > 0) { 62 | this.timerWeaponWait = null; 63 | return true; 64 | } 65 | 66 | return false; 67 | } 68 | } 69 | 70 | ig.bindProperties(Character, { 71 | zIndex : 0, 72 | speed : 100, 73 | health : 200, 74 | timeWeaponWait : 200, 75 | gravityFactor : 0 76 | }); -------------------------------------------------------------------------------- /example/lib/game/screens/Arena.js: -------------------------------------------------------------------------------- 1 | import CharacterFlight from "./../entities/characters/CharacterFlight"; 2 | import CharacterSpike from "./../entities/characters/CharacterSpike"; 3 | 4 | ig.require('impact.game'); 5 | 6 | 7 | export default class Arena extends ig.Game { 8 | /* LIFECYCLE */ 9 | init () 10 | { 11 | // Bind inputs for player 12 | ig.input.bind(ig.KEY.UP_ARROW, 'up'); 13 | ig.input.bind(ig.KEY.RIGHT_ARROW, 'right'); 14 | ig.input.bind(ig.KEY.LEFT_ARROW, 'left'); 15 | ig.input.bind(ig.KEY.DOWN_ARROW, 'down'); 16 | ig.input.bind(ig.KEY.SPACE, 'fire'); 17 | 18 | this.player = ig.game.spawnEntity(CharacterFlight, 0, 0); 19 | this.spike = ig.game.spawnEntity(CharacterSpike, 50, ig.system.height - 100); 20 | ig.game.spawnEntity(CharacterSpike, 200, ig.system.height - 100, { size: {x: 70, y: 70} }); 21 | } 22 | 23 | update () 24 | { 25 | super.update(); 26 | 27 | if (this.player) { 28 | this.updateInputs(); 29 | } 30 | } 31 | 32 | draw () 33 | { 34 | super.draw(); 35 | 36 | var x = ig.system.width / 2, 37 | y = ig.system.height / 2; 38 | 39 | this.font.draw('It Works!', x, y, ig.Font.ALIGN.CENTER); 40 | } 41 | 42 | 43 | /* METHODS */ 44 | updateInputs () 45 | { 46 | var left = ig.input.state('left'); 47 | var right = ig.input.state('right'); 48 | var up = ig.input.state('up'); 49 | var down = ig.input.state('down'); 50 | var x = 0; 51 | var y = 0; 52 | 53 | if (left) { x--; } 54 | if (right) { x++; } 55 | if (down) { y++; } 56 | if (up) { y--; } 57 | 58 | this.player.setVel(x, y); 59 | 60 | if (ig.input.pressed('fire')) { 61 | this.player.fire(); 62 | } 63 | } 64 | } 65 | 66 | ig.bindProperties(Arena, { 67 | gravity : 300, 68 | player : null, 69 | font : new ig.Font('media/04b03.font.png') 70 | }); -------------------------------------------------------------------------------- /example/lib/game/levels/level.js: -------------------------------------------------------------------------------- 1 | ig.module( 'game.levels.level' ) 2 | .requires( 'impact.image' ) 3 | .defines(function(){ 4 | LevelLevel=/*JSON[*/{ 5 | "entities": [], 6 | "layer": [ 7 | { 8 | "name": "tiles", 9 | "width": 16, 10 | "height": 10, 11 | "linkWithCollision": false, 12 | "visible": 1, 13 | "tilesetName": "media/tiles/ground.png", 14 | "repeat": false, 15 | "preRender": false, 16 | "distance": "1", 17 | "tilesize": 64, 18 | "foreground": false, 19 | "data": [ 20 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 21 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 22 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 23 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 24 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 25 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 26 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 27 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 28 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 29 | [97,9,9,9,9,9,9,9,9,9,9,9,9,9,9,89] 30 | ] 31 | }, 32 | { 33 | "name": "collision", 34 | "width": 32, 35 | "height": 20, 36 | "linkWithCollision": false, 37 | "visible": 1, 38 | "tilesetName": "", 39 | "repeat": false, 40 | "preRender": false, 41 | "distance": 1, 42 | "tilesize": 32, 43 | "foreground": false, 44 | "data": [ 45 | [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], 46 | [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], 47 | [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], 48 | [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], 49 | [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], 50 | [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], 51 | [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], 52 | [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], 53 | [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], 54 | [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], 55 | [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], 56 | [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], 57 | [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], 58 | [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], 59 | [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], 60 | [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], 61 | [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], 62 | [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], 63 | [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], 64 | [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1] 65 | ] 66 | } 67 | ] 68 | }/*]JSON*/; 69 | LevelLevelResources=[new ig.Image('media/tiles/ground.png')]; 70 | }); -------------------------------------------------------------------------------- /lib/impactES6/index.js: -------------------------------------------------------------------------------- 1 | var igES6 = module.exports = { 2 | /** 3 | * This variable is at true when igES6 has all method of impact library 4 | */ 5 | _importES5: false, 6 | 7 | /** 8 | * Data provided by ig.module, ig.requires and ig.defines before _importES5 at true 9 | */ 10 | _storedData: {modules: [], requires: [], defines: []}, 11 | 12 | /** 13 | * List of all modules ES5 loaded 14 | */ 15 | modules: {}, 16 | 17 | /** 18 | * Context folder of all library (needed for dynamic require) 19 | */ 20 | requirecontext: require.context('lib/', true, /^((?![\\/]impactES6|weltmeister[\\/]).)*\.js$/), 21 | 22 | /** 23 | * Define a new module (support ES5) 24 | * @param name 25 | * @returns Object 26 | */ 27 | module: function (name) 28 | { 29 | if (!name) { 30 | return this; 31 | 32 | } 33 | 34 | if (!this._importES5) { 35 | this._storedData.modules.push(name); 36 | 37 | } else if (!this.modules[name]) { 38 | this.modules[name] = true; 39 | 40 | } 41 | 42 | return this; 43 | }, 44 | 45 | /** 46 | * Requires all module for the current module (support ES5) 47 | * @returns Object 48 | */ 49 | requires: function () 50 | { 51 | var args = Array.from(arguments); 52 | 53 | if (!this._importES5) { 54 | this._storedData.requires.push(args); 55 | return this; 56 | } 57 | 58 | args.map((arg) => { 59 | if (arg === "dom.ready") { 60 | this._ready = true; 61 | 62 | } else { 63 | this.require(arg); 64 | 65 | } 66 | }); 67 | 68 | return this; 69 | }, 70 | 71 | /** 72 | * Require a module 73 | * @param moduleName 74 | */ 75 | require: function (moduleName) 76 | { 77 | if (!this.modules[moduleName] && moduleName !== "impact.impact") { 78 | let path = "./" + moduleName.split('.').join('/') + '.js'; 79 | this.requirecontext(path); 80 | } 81 | }, 82 | 83 | /** 84 | * Define a module (ig.module must be defined before) (support ES5) 85 | * @param define 86 | */ 87 | defines: function (define) 88 | { 89 | if (!this._importES5) { 90 | this._storedData.defines.push(define); 91 | 92 | } else { 93 | define(); 94 | 95 | } 96 | }, 97 | 98 | /** 99 | * Merge all storedData provided by old module before _importES5 100 | */ 101 | mergeES5: function () 102 | { 103 | for (var propName in window.ig) { 104 | if (!this.hasOwnProperty(propName) && window.ig.hasOwnProperty(propName)) { 105 | this[propName] = window.ig[propName]; 106 | } 107 | } 108 | 109 | this.setVendorAttribute = window.ig.setVendorAttribute; 110 | this.getVendorAttribute = window.ig.getVendorAttribute; 111 | this.normalizeVendorAttribute = window.ig.normalizeVendorAttribute; 112 | 113 | this._importES5 = true; 114 | 115 | this._storedData.modules.map(x => this.module(x)); 116 | this._storedData.requires.map(x => this.requires.apply(this, x)); 117 | this._storedData.defines.map(x => this.defines(x)); 118 | }, 119 | 120 | /** 121 | * Bind props to ES6 currentClass 122 | * @param currentClass 123 | * @param props 124 | * @returns {*} 125 | */ 126 | bindProperties: function (currentClass, props) 127 | { 128 | for (var propname in props) { 129 | currentClass.prototype[propname] = props[propname]; 130 | } 131 | 132 | return currentClass; 133 | }, 134 | 135 | /** 136 | * Override of ImpactJS 137 | * @returns {boolean} 138 | * @private 139 | */ 140 | _DOMReady: function() 141 | { 142 | return !!this._ready; 143 | }, 144 | 145 | /** 146 | * Same as ImpactJS 147 | * @param element 148 | * @param attribute 149 | * @param value 150 | */ 151 | setVendorAttribute: (element, attribute, value) => { 152 | window.ig.setVendorAttribute(element, attribute, value); 153 | }, 154 | 155 | /** 156 | * Same as ImpactJS 157 | * @param element 158 | * @param attribute 159 | * @returns {*} 160 | */ 161 | getVendorAttribute: (element, attribute) => { 162 | return window.ig.getVendorAttribute(element, attribute); 163 | }, 164 | 165 | /** 166 | * Same as ImpactJS 167 | * @param element 168 | * @param attribute 169 | */ 170 | normalizeVendorAttribute: (element, attribute) => { 171 | window.ig.normalizeVendorAttribute(element, attribute); 172 | } 173 | }; 174 | 175 | module.export = igES6; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # impactES6 2 | 3 | ### NEW UPDATE : **Version BETA 0.3** 4 | 5 | #### What's new in 0.3 Version 6 | - Is it now possible to have a project with both old script and ES6 Scripts. Note : To avoid most common error, please read the chapter about "Use Strict mode" 7 | - Preloading image run now correctly 8 | 9 | This project allow you tu use ES6 with ImpactJS. 10 | 11 | > **Note about current version** 12 | 13 | > - Impact Library support : **Version 1.24** 14 | > - If you encouter any bugs or issues, please report it into the issues page 15 | 16 | 17 | ## Overview 18 | 19 | #### ES6 20 | 21 | ImpactJS is an excellent javascript game framework with lots of features. But there is actually no support with ES6. 22 | ES6 is a new way to write javascript code and it is so much better than ES5. [Click here for more informations about ES6 features][1] 23 | 24 | 25 | #### Webpack 26 | 27 | This project use webpack to minify and uglify your all game into a single file. [Click here for more informations about Webpack][2] 28 | 29 | 30 | #### Node and Npm 31 | 32 | Npm ("Module Package Manager") is a tool for manage your project dependency. To have Npm in your shell, you must install **Node** 33 | [by clicking here][3] 34 | 35 | #### Use strict mode 36 | 37 | In ES6, all scripts are in *use strict* mode. In this mode, you **can't** create a global variable : 38 | ```javascript 39 | EntityPlayer = ig.Entity.extend(...) // Will throw an error because EntityPlayer doesn't exist 40 | ``` 41 | To avoid this error, you **must** bind your entity with "ig" variable like this : 42 | ```javascript 43 | ig.EntityPlayer = ig.Entity.extend(...) // GOOD ! 44 | ``` 45 | In fact, in *use strict* mode, a function that is not an object can't have a reference to a *this* and it doesn't not also 46 | reference to *window* object. 47 | 48 | 49 | ## Installation 50 | 51 | ##### **1)** Copy this project into your local environment. 52 | 53 | ##### **2)** Install package with npm 54 | ``` 55 | npm install 56 | ``` 57 | 58 | ##### **3)** Install ImpactJS into the project 59 | The ImpactJS folder must be at the root of this project. In other terms : **game** and **impact** folders should be into the lib directory with "impactES6" folder. 60 | 61 | ##### **4)** Make your game ! 62 | The project is now configured and you can develop your game with ES6 ! 63 | 64 | ##### **5)** Build your game into a single file 65 | To build your games into a single file, use the shell and type this command into the root directory of your project 66 | ``` 67 | npm run build 68 | ``` 69 | 70 | If your are in a development environnement, you can use : 71 | ``` 72 | npm run build-dev 73 | ``` 74 | This command has a watcher and it will build your game when a file has changed. 75 | 76 | 77 | ## Usage 78 | 79 | ### Import an old script 80 | ```javascript 81 | ig.require('game.entities.fire'); // You need to require it juste once. It will be loaded for all your project 82 | ``` 83 | 84 | ### Import a new script 85 | ```javascript 86 | import EntityPlayer from "lib/game/entities/player"; 87 | ``` 88 | 89 | ### Create an entity 90 | ```javascript 91 | export default class EntityPlayer extend ig.Entity { 92 | 93 | init (x, y, settings) 94 | { 95 | super.init(x, y, settings); 96 | ... 97 | } 98 | 99 | fire () 100 | { 101 | ig.game.spawnEntity(EntityFire, this.pos.x + (this.size.x / 2), this.pos.y + this.size.y, { owner: this }); 102 | } 103 | 104 | } 105 | ``` 106 | 107 | ### Default properties 108 | Default properties is a new way to declare your properties **before** the new object was created. 109 | For example, in ES5 Script, you have : 110 | ```javascript 111 | ig.EntityPlayer = ig.Entity.extend({ 112 | animSheet: new ig.AnimationSheet('media/player.png', 10, 10), 113 | size : {x: 10, y: 10}, 114 | speed: 300, 115 | 116 | init: function (x, y, settings) { 117 | ... 118 | } 119 | }); 120 | ``` 121 | 122 | In ES6, you can't define variable except into a function, so, when it is created. But ImpactES6 has a function which 123 | allow you to define properties. Like this : 124 | ```javascript 125 | export default class EntityPlayer extend ig.Entity { 126 | init (x, y, settings) 127 | { 128 | ... 129 | } 130 | } 131 | 132 | ig.bindProperties(EntityPlayer, { 133 | animSheet : new ig.AnimationSheet('media/player.png', 10, 10), 134 | size : {x: 10, y: 10}, 135 | speed : 300 136 | }); 137 | ``` 138 | 139 | ### jQuery 140 | jQuery is added by default on the project. You can call "$" or "jQuery" without do anything. But if you want to add 141 | plugin into jQuery, you have to use *imports-loader* and import your plugin like this : 142 | ```javascript 143 | import "imports?$=jquery,this=>window!velocity-animate"; 144 | ``` 145 | It is a query string which means that you import global jQuery into the script and you define the window object like global variable. 146 | Like *ig.require*, import it once and it will be loaded into all your project. 147 | 148 | 149 | ## Examples 150 | 151 | You can see a dummy example into the folder, juste load the index.html in your browser and you will see. 152 | 153 | 154 | 155 | 156 | 157 | [1]: https://babeljs.io/docs/learn-es2015/ 158 | [2]: https://webpack.github.io/docs/what-is-webpack.html 159 | [3]: https://docs.npmjs.com/getting-started/installing-node 160 | -------------------------------------------------------------------------------- /dist/game.min.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 | /******/ exports: {}, 15 | /******/ id: moduleId, 16 | /******/ loaded: false 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.loaded = 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 | /******/ // __webpack_public_path__ 37 | /******/ __webpack_require__.p = ""; 38 | /******/ 39 | /******/ // Load entry module and return exports 40 | /******/ return __webpack_require__(0); 41 | /******/ }) 42 | /************************************************************************/ 43 | /******/ ([ 44 | /* 0 */ 45 | /*!******************!*\ 46 | !*** ./index.js ***! 47 | \******************/ 48 | /***/ function(module, exports, __webpack_require__) { 49 | 50 | /* WEBPACK VAR INJECTION */(function(ig) {/*** IMPORTS FROM imports-loader ***/ 51 | (function() { 52 | 53 | "use strict"; 54 | 55 | __webpack_require__(/*! lib/impact/impact */ 18); 56 | 57 | // Merge features into new ImpactEngine 58 | ig.mergeES5(); // Import impact library 59 | 60 | window.ig = ig; 61 | 62 | // Import main game 63 | __webpack_require__(/*! lib/game/main */ 4); 64 | }.call(window)); 65 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(/*! ig */ 1))) 66 | 67 | /***/ }, 68 | /* 1 */ 69 | /*!********************************!*\ 70 | !*** ./lib/impactES6/index.js ***! 71 | \********************************/ 72 | /***/ function(module, exports, __webpack_require__) { 73 | 74 | /* WEBPACK VAR INJECTION */(function(module) {/*** IMPORTS FROM imports-loader ***/ 75 | (function() { 76 | 77 | "use strict"; 78 | 79 | var igES6 = module.exports = { 80 | /** 81 | * This variable is at true when igES6 has all method of impact library 82 | */ 83 | _importES5: false, 84 | 85 | /** 86 | * Data provided by ig.module, ig.requires and ig.defines before _importES5 at true 87 | */ 88 | _storedData: { modules: [], requires: [], defines: [] }, 89 | 90 | /** 91 | * List of all modules ES5 loaded 92 | */ 93 | modules: {}, 94 | 95 | /** 96 | * Context folder of all library (needed for dynamic require) 97 | */ 98 | requirecontext: __webpack_require__(/*! lib/ */ 3), 99 | 100 | /** 101 | * Define a new module (support ES5) 102 | * @param name 103 | * @returns Object 104 | */ 105 | module: function module(name) { 106 | if (!name) { 107 | return this; 108 | } 109 | 110 | if (!this._importES5) { 111 | this._storedData.modules.push(name); 112 | } else if (!this.modules[name]) { 113 | this.modules[name] = true; 114 | } 115 | 116 | return this; 117 | }, 118 | 119 | /** 120 | * Requires all module for the current module (support ES5) 121 | * @returns Object 122 | */ 123 | requires: function requires() { 124 | var _this = this; 125 | 126 | var args = Array.from(arguments); 127 | 128 | if (!this._importES5) { 129 | this._storedData.requires.push(args); 130 | return this; 131 | } 132 | 133 | args.map(function (arg) { 134 | if (arg === "dom.ready") { 135 | _this._ready = true; 136 | } else { 137 | _this.require(arg); 138 | } 139 | }); 140 | 141 | return this; 142 | }, 143 | 144 | /** 145 | * Require a module 146 | * @param moduleName 147 | */ 148 | require: function require(moduleName) { 149 | if (!this.modules[moduleName] && moduleName !== "impact.impact") { 150 | var path = "./" + moduleName.split('.').join('/') + '.js'; 151 | this.requirecontext(path); 152 | } 153 | }, 154 | 155 | /** 156 | * Define a module (ig.module must be defined before) (support ES5) 157 | * @param define 158 | */ 159 | defines: function defines(define) { 160 | if (!this._importES5) { 161 | this._storedData.defines.push(define); 162 | } else { 163 | define(); 164 | } 165 | }, 166 | 167 | /** 168 | * Merge all storedData provided by old module before _importES5 169 | */ 170 | mergeES5: function mergeES5() { 171 | var _this2 = this; 172 | 173 | for (var propName in window.ig) { 174 | if (!this.hasOwnProperty(propName) && window.ig.hasOwnProperty(propName)) { 175 | this[propName] = window.ig[propName]; 176 | } 177 | } 178 | 179 | this.setVendorAttribute = window.ig.setVendorAttribute; 180 | this.getVendorAttribute = window.ig.getVendorAttribute; 181 | this.normalizeVendorAttribute = window.ig.normalizeVendorAttribute; 182 | 183 | this._importES5 = true; 184 | 185 | this._storedData.modules.map(function (x) { 186 | return _this2.module(x); 187 | }); 188 | this._storedData.requires.map(function (x) { 189 | return _this2.requires.apply(_this2, x); 190 | }); 191 | this._storedData.defines.map(function (x) { 192 | return _this2.defines(x); 193 | }); 194 | }, 195 | 196 | /** 197 | * Bind props to ES6 currentClass 198 | * @param currentClass 199 | * @param props 200 | * @returns {*} 201 | */ 202 | bindProperties: function bindProperties(currentClass, props) { 203 | for (var propname in props) { 204 | currentClass.prototype[propname] = props[propname]; 205 | } 206 | 207 | return currentClass; 208 | }, 209 | 210 | /** 211 | * Override of ImpactJS 212 | * @returns {boolean} 213 | * @private 214 | */ 215 | _DOMReady: function _DOMReady() { 216 | return !!this._ready; 217 | }, 218 | 219 | /** 220 | * Same as ImpactJS 221 | * @param element 222 | * @param attribute 223 | * @param value 224 | */ 225 | setVendorAttribute: function setVendorAttribute(element, attribute, value) { 226 | window.ig.setVendorAttribute(element, attribute, value); 227 | }, 228 | 229 | /** 230 | * Same as ImpactJS 231 | * @param element 232 | * @param attribute 233 | * @returns {*} 234 | */ 235 | getVendorAttribute: function getVendorAttribute(element, attribute) { 236 | return window.ig.getVendorAttribute(element, attribute); 237 | }, 238 | 239 | /** 240 | * Same as ImpactJS 241 | * @param element 242 | * @param attribute 243 | */ 244 | normalizeVendorAttribute: function normalizeVendorAttribute(element, attribute) { 245 | window.ig.normalizeVendorAttribute(element, attribute); 246 | } 247 | }; 248 | 249 | module.export = igES6; 250 | }.call(window)); 251 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(/*! ./../../~/webpack/buildin/module.js */ 2)(module))) 252 | 253 | /***/ }, 254 | /* 2 */ 255 | /*!***********************************!*\ 256 | !*** (webpack)/buildin/module.js ***! 257 | \***********************************/ 258 | /***/ function(module, exports) { 259 | 260 | /*** IMPORTS FROM imports-loader ***/ 261 | (function() { 262 | 263 | module.exports = function(module) { 264 | if(!module.webpackPolyfill) { 265 | module.deprecate = function() {}; 266 | module.paths = []; 267 | // module.parent = undefined by default 268 | module.children = []; 269 | module.webpackPolyfill = 1; 270 | } 271 | return module; 272 | } 273 | 274 | }.call(window)); 275 | 276 | /***/ }, 277 | /* 3 */ 278 | /*!***********************************************************!*\ 279 | !*** ./lib ^((?![\\/]impactES6|weltmeister[\\/]).)*\.js$ ***! 280 | \***********************************************************/ 281 | /***/ function(module, exports, __webpack_require__) { 282 | 283 | var map = { 284 | "./game/main.js": 4, 285 | "./impact/animation.js": 5, 286 | "./impact/background-map.js": 6, 287 | "./impact/collision-map.js": 7, 288 | "./impact/debug/debug.js": 8, 289 | "./impact/debug/entities-panel.js": 9, 290 | "./impact/debug/graph-panel.js": 10, 291 | "./impact/debug/maps-panel.js": 11, 292 | "./impact/debug/menu.js": 12, 293 | "./impact/entity-pool.js": 13, 294 | "./impact/entity.js": 14, 295 | "./impact/font.js": 15, 296 | "./impact/game.js": 16, 297 | "./impact/image.js": 17, 298 | "./impact/impact.js": 18, 299 | "./impact/input.js": 19, 300 | "./impact/loader.js": 20, 301 | "./impact/map.js": 21, 302 | "./impact/sound.js": 22, 303 | "./impact/system.js": 23, 304 | "./impact/timer.js": 24 305 | }; 306 | function webpackContext(req) { 307 | return __webpack_require__(webpackContextResolve(req)); 308 | }; 309 | function webpackContextResolve(req) { 310 | return map[req] || (function() { throw new Error("Cannot find module '" + req + "'.") }()); 311 | }; 312 | webpackContext.keys = function webpackContextKeys() { 313 | return Object.keys(map); 314 | }; 315 | webpackContext.resolve = webpackContextResolve; 316 | module.exports = webpackContext; 317 | webpackContext.id = 3; 318 | 319 | 320 | /***/ }, 321 | /* 4 */ 322 | /*!**************************!*\ 323 | !*** ./lib/game/main.js ***! 324 | \**************************/ 325 | /***/ function(module, exports, __webpack_require__) { 326 | 327 | /* WEBPACK VAR INJECTION */(function(ig) {/*** IMPORTS FROM imports-loader ***/ 328 | (function() { 329 | 330 | 'use strict'; 331 | 332 | Object.defineProperty(exports, "__esModule", { 333 | value: true 334 | }); 335 | 336 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 337 | 338 | var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; 339 | 340 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 341 | 342 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 343 | 344 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 345 | 346 | // Method to require an impact library 347 | // Once it is loaded, it doesn't need to require it again 348 | ig.require('impact.game'); 349 | ig.require('impact.debug.debug'); 350 | 351 | var MyGame = function (_ig$Game) { 352 | _inherits(MyGame, _ig$Game); 353 | 354 | function MyGame() { 355 | _classCallCheck(this, MyGame); 356 | 357 | return _possibleConstructorReturn(this, (MyGame.__proto__ || Object.getPrototypeOf(MyGame)).apply(this, arguments)); 358 | } 359 | 360 | _createClass(MyGame, [{ 361 | key: 'init', 362 | value: function init() { 363 | // Custom actions at initialization 364 | } 365 | }, { 366 | key: 'update', 367 | value: function update() { 368 | // Update all entities and backgroundMaps 369 | _get(MyGame.prototype.__proto__ || Object.getPrototypeOf(MyGame.prototype), 'update', this).call(this); 370 | 371 | // Add your own, additional update code here 372 | } 373 | }, { 374 | key: 'draw', 375 | value: function draw() { 376 | // Draw all entities and backgroundMaps 377 | _get(MyGame.prototype.__proto__ || Object.getPrototypeOf(MyGame.prototype), 'draw', this).call(this); 378 | 379 | // Add your own drawing code here 380 | var x = ig.system.width / 2, 381 | y = ig.system.height / 2; 382 | 383 | this.font.draw('It Works!', x, y, ig.Font.ALIGN.CENTER); 384 | } 385 | }]); 386 | 387 | return MyGame; 388 | }(ig.Game); 389 | 390 | // Declare properties 391 | 392 | 393 | exports.default = MyGame; 394 | ig.bindProperties(MyGame, { 395 | font: new ig.Font('media/04b03.font.png') 396 | }); 397 | 398 | ig.main('#canvas', MyGame, 60, 320, 240, 2); 399 | }.call(window)); 400 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(/*! ig */ 1))) 401 | 402 | /***/ }, 403 | /* 5 */ 404 | /*!*********************************!*\ 405 | !*** ./lib/impact/animation.js ***! 406 | \*********************************/ 407 | /***/ function(module, exports, __webpack_require__) { 408 | 409 | /* WEBPACK VAR INJECTION */(function(ig) {/*** IMPORTS FROM imports-loader ***/ 410 | (function() { 411 | 412 | 'use strict'; 413 | 414 | ig.module('impact.animation').requires('impact.timer', 'impact.image').defines(function () { 415 | "use strict"; 416 | 417 | ig.AnimationSheet = ig.Class.extend({ 418 | width: 8, 419 | height: 8, 420 | image: null, 421 | 422 | init: function init(path, width, height) { 423 | this.width = width; 424 | this.height = height; 425 | 426 | this.image = new ig.Image(path); 427 | } 428 | }); 429 | 430 | ig.Animation = ig.Class.extend({ 431 | sheet: null, 432 | timer: null, 433 | 434 | sequence: [], 435 | flip: { x: false, y: false }, 436 | pivot: { x: 0, y: 0 }, 437 | 438 | frame: 0, 439 | tile: 0, 440 | loopCount: 0, 441 | alpha: 1, 442 | angle: 0, 443 | 444 | init: function init(sheet, frameTime, sequence, stop) { 445 | this.sheet = sheet; 446 | this.pivot = { x: sheet.width / 2, y: sheet.height / 2 }; 447 | this.timer = new ig.Timer(); 448 | 449 | this.frameTime = frameTime; 450 | this.sequence = sequence; 451 | this.stop = !!stop; 452 | this.tile = this.sequence[0]; 453 | }, 454 | 455 | rewind: function rewind() { 456 | this.timer.set(); 457 | this.loopCount = 0; 458 | this.frame = 0; 459 | this.tile = this.sequence[0]; 460 | return this; 461 | }, 462 | 463 | gotoFrame: function gotoFrame(f) { 464 | // Offset the timer by one tenth of a millisecond to make sure we 465 | // jump to the correct frame and circumvent rounding errors 466 | this.timer.set(this.frameTime * -f - 0.0001); 467 | this.update(); 468 | }, 469 | 470 | gotoRandomFrame: function gotoRandomFrame() { 471 | this.gotoFrame(Math.floor(Math.random() * this.sequence.length)); 472 | }, 473 | 474 | update: function update() { 475 | var frameTotal = Math.floor(this.timer.delta() / this.frameTime); 476 | this.loopCount = Math.floor(frameTotal / this.sequence.length); 477 | if (this.stop && this.loopCount > 0) { 478 | this.frame = this.sequence.length - 1; 479 | } else { 480 | this.frame = frameTotal % this.sequence.length; 481 | } 482 | this.tile = this.sequence[this.frame]; 483 | }, 484 | 485 | draw: function draw(targetX, targetY) { 486 | var bbsize = Math.max(this.sheet.width, this.sheet.height); 487 | 488 | // On screen? 489 | if (targetX > ig.system.width || targetY > ig.system.height || targetX + bbsize < 0 || targetY + bbsize < 0) { 490 | return; 491 | } 492 | 493 | if (this.alpha != 1) { 494 | ig.system.context.globalAlpha = this.alpha; 495 | } 496 | 497 | if (this.angle == 0) { 498 | this.sheet.image.drawTile(targetX, targetY, this.tile, this.sheet.width, this.sheet.height, this.flip.x, this.flip.y); 499 | } else { 500 | ig.system.context.save(); 501 | ig.system.context.translate(ig.system.getDrawPos(targetX + this.pivot.x), ig.system.getDrawPos(targetY + this.pivot.y)); 502 | ig.system.context.rotate(this.angle); 503 | this.sheet.image.drawTile(-this.pivot.x, -this.pivot.y, this.tile, this.sheet.width, this.sheet.height, this.flip.x, this.flip.y); 504 | ig.system.context.restore(); 505 | } 506 | 507 | if (this.alpha != 1) { 508 | ig.system.context.globalAlpha = 1; 509 | } 510 | } 511 | }); 512 | }); 513 | }.call(window)); 514 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(/*! ig */ 1))) 515 | 516 | /***/ }, 517 | /* 6 */ 518 | /*!**************************************!*\ 519 | !*** ./lib/impact/background-map.js ***! 520 | \**************************************/ 521 | /***/ function(module, exports, __webpack_require__) { 522 | 523 | /* WEBPACK VAR INJECTION */(function(ig) {/*** IMPORTS FROM imports-loader ***/ 524 | (function() { 525 | 526 | 'use strict'; 527 | 528 | ig.module('impact.background-map').requires('impact.map', 'impact.image').defines(function () { 529 | "use strict"; 530 | 531 | ig.BackgroundMap = ig.Map.extend({ 532 | tiles: null, 533 | scroll: { x: 0, y: 0 }, 534 | distance: 1, 535 | repeat: false, 536 | tilesetName: '', 537 | foreground: false, 538 | enabled: true, 539 | 540 | preRender: false, 541 | preRenderedChunks: null, 542 | chunkSize: 512, 543 | debugChunks: false, 544 | 545 | anims: {}, 546 | 547 | init: function init(tilesize, data, tileset) { 548 | this.parent(tilesize, data); 549 | this.setTileset(tileset); 550 | }, 551 | 552 | setTileset: function setTileset(tileset) { 553 | this.tilesetName = tileset instanceof ig.Image ? tileset.path : tileset; 554 | this.tiles = new ig.Image(this.tilesetName); 555 | this.preRenderedChunks = null; 556 | }, 557 | 558 | setScreenPos: function setScreenPos(x, y) { 559 | this.scroll.x = x / this.distance; 560 | this.scroll.y = y / this.distance; 561 | }, 562 | 563 | preRenderMapToChunks: function preRenderMapToChunks() { 564 | var totalWidth = this.width * this.tilesize * ig.system.scale, 565 | totalHeight = this.height * this.tilesize * ig.system.scale; 566 | 567 | // If this layer is smaller than the chunkSize, adjust the chunkSize 568 | // accordingly, so we don't have as much overdraw 569 | this.chunkSize = Math.min(Math.max(totalWidth, totalHeight), this.chunkSize); 570 | 571 | var chunkCols = Math.ceil(totalWidth / this.chunkSize), 572 | chunkRows = Math.ceil(totalHeight / this.chunkSize); 573 | 574 | this.preRenderedChunks = []; 575 | for (var y = 0; y < chunkRows; y++) { 576 | this.preRenderedChunks[y] = []; 577 | 578 | for (var x = 0; x < chunkCols; x++) { 579 | 580 | var chunkWidth = x == chunkCols - 1 ? totalWidth - x * this.chunkSize : this.chunkSize; 581 | 582 | var chunkHeight = y == chunkRows - 1 ? totalHeight - y * this.chunkSize : this.chunkSize; 583 | 584 | this.preRenderedChunks[y][x] = this.preRenderChunk(x, y, chunkWidth, chunkHeight); 585 | } 586 | } 587 | }, 588 | 589 | preRenderChunk: function preRenderChunk(cx, cy, w, h) { 590 | var tw = w / this.tilesize / ig.system.scale + 1, 591 | th = h / this.tilesize / ig.system.scale + 1; 592 | 593 | var nx = cx * this.chunkSize / ig.system.scale % this.tilesize, 594 | ny = cy * this.chunkSize / ig.system.scale % this.tilesize; 595 | 596 | var tx = Math.floor(cx * this.chunkSize / this.tilesize / ig.system.scale), 597 | ty = Math.floor(cy * this.chunkSize / this.tilesize / ig.system.scale); 598 | 599 | var chunk = ig.$new('canvas'); 600 | chunk.width = w; 601 | chunk.height = h; 602 | chunk.retinaResolutionEnabled = false; // Opt out for Ejecta 603 | 604 | var chunkContext = chunk.getContext('2d'); 605 | ig.System.scaleMode(chunk, chunkContext); 606 | 607 | var screenContext = ig.system.context; 608 | ig.system.context = chunkContext; 609 | 610 | for (var x = 0; x < tw; x++) { 611 | for (var y = 0; y < th; y++) { 612 | if (x + tx < this.width && y + ty < this.height) { 613 | var tile = this.data[y + ty][x + tx]; 614 | if (tile) { 615 | this.tiles.drawTile(x * this.tilesize - nx, y * this.tilesize - ny, tile - 1, this.tilesize); 616 | } 617 | } 618 | } 619 | } 620 | ig.system.context = screenContext; 621 | 622 | return chunk; 623 | }, 624 | 625 | draw: function draw() { 626 | if (!this.tiles.loaded || !this.enabled) { 627 | return; 628 | } 629 | 630 | if (this.preRender) { 631 | this.drawPreRendered(); 632 | } else { 633 | this.drawTiled(); 634 | } 635 | }, 636 | 637 | drawPreRendered: function drawPreRendered() { 638 | if (!this.preRenderedChunks) { 639 | this.preRenderMapToChunks(); 640 | } 641 | 642 | var dx = ig.system.getDrawPos(this.scroll.x), 643 | dy = ig.system.getDrawPos(this.scroll.y); 644 | 645 | if (this.repeat) { 646 | var w = this.width * this.tilesize * ig.system.scale; 647 | dx = (dx % w + w) % w; 648 | 649 | var h = this.height * this.tilesize * ig.system.scale; 650 | dy = (dy % h + h) % h; 651 | } 652 | 653 | var minChunkX = Math.max(Math.floor(dx / this.chunkSize), 0), 654 | minChunkY = Math.max(Math.floor(dy / this.chunkSize), 0), 655 | maxChunkX = Math.ceil((dx + ig.system.realWidth) / this.chunkSize), 656 | maxChunkY = Math.ceil((dy + ig.system.realHeight) / this.chunkSize), 657 | maxRealChunkX = this.preRenderedChunks[0].length, 658 | maxRealChunkY = this.preRenderedChunks.length; 659 | 660 | if (!this.repeat) { 661 | maxChunkX = Math.min(maxChunkX, maxRealChunkX); 662 | maxChunkY = Math.min(maxChunkY, maxRealChunkY); 663 | } 664 | 665 | var nudgeY = 0; 666 | for (var cy = minChunkY; cy < maxChunkY; cy++) { 667 | 668 | var nudgeX = 0; 669 | for (var cx = minChunkX; cx < maxChunkX; cx++) { 670 | var chunk = this.preRenderedChunks[cy % maxRealChunkY][cx % maxRealChunkX]; 671 | 672 | var x = -dx + cx * this.chunkSize - nudgeX; 673 | var y = -dy + cy * this.chunkSize - nudgeY; 674 | ig.system.context.drawImage(chunk, x, y); 675 | ig.Image.drawCount++; 676 | 677 | if (this.debugChunks) { 678 | ig.system.context.strokeStyle = '#f0f'; 679 | ig.system.context.strokeRect(x, y, this.chunkSize, this.chunkSize); 680 | } 681 | 682 | // If we repeat in X and this chunk's width wasn't the full chunk size 683 | // and the screen is not already filled, we need to draw anohter chunk 684 | // AND nudge it to be flush with the last chunk 685 | if (this.repeat && chunk.width < this.chunkSize && x + chunk.width < ig.system.realWidth) { 686 | nudgeX += this.chunkSize - chunk.width; 687 | maxChunkX++; 688 | } 689 | } 690 | 691 | // Same as above, but for Y 692 | if (this.repeat && chunk.height < this.chunkSize && y + chunk.height < ig.system.realHeight) { 693 | nudgeY += this.chunkSize - chunk.height; 694 | maxChunkY++; 695 | } 696 | } 697 | }, 698 | 699 | drawTiled: function drawTiled() { 700 | var tile = 0, 701 | anim = null, 702 | tileOffsetX = (this.scroll.x / this.tilesize).toInt(), 703 | tileOffsetY = (this.scroll.y / this.tilesize).toInt(), 704 | pxOffsetX = this.scroll.x % this.tilesize, 705 | pxOffsetY = this.scroll.y % this.tilesize, 706 | pxMinX = -pxOffsetX - this.tilesize, 707 | pxMinY = -pxOffsetY - this.tilesize, 708 | pxMaxX = ig.system.width + this.tilesize - pxOffsetX, 709 | pxMaxY = ig.system.height + this.tilesize - pxOffsetY; 710 | 711 | // FIXME: could be sped up for non-repeated maps: restrict the for loops 712 | // to the map size instead of to the screen size and skip the 'repeat' 713 | // checks inside the loop. 714 | 715 | for (var mapY = -1, pxY = pxMinY; pxY < pxMaxY; mapY++, pxY += this.tilesize) { 716 | var tileY = mapY + tileOffsetY; 717 | 718 | // Repeat Y? 719 | if (tileY >= this.height || tileY < 0) { 720 | if (!this.repeat) { 721 | continue; 722 | } 723 | tileY = (tileY % this.height + this.height) % this.height; 724 | } 725 | 726 | for (var mapX = -1, pxX = pxMinX; pxX < pxMaxX; mapX++, pxX += this.tilesize) { 727 | var tileX = mapX + tileOffsetX; 728 | 729 | // Repeat X? 730 | if (tileX >= this.width || tileX < 0) { 731 | if (!this.repeat) { 732 | continue; 733 | } 734 | tileX = (tileX % this.width + this.width) % this.width; 735 | } 736 | 737 | // Draw! 738 | if (tile = this.data[tileY][tileX]) { 739 | if (anim = this.anims[tile - 1]) { 740 | anim.draw(pxX, pxY); 741 | } else { 742 | this.tiles.drawTile(pxX, pxY, tile - 1, this.tilesize); 743 | } 744 | } 745 | } // end for x 746 | } // end for y 747 | } 748 | }); 749 | }); 750 | }.call(window)); 751 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(/*! ig */ 1))) 752 | 753 | /***/ }, 754 | /* 7 */ 755 | /*!*************************************!*\ 756 | !*** ./lib/impact/collision-map.js ***! 757 | \*************************************/ 758 | /***/ function(module, exports, __webpack_require__) { 759 | 760 | /* WEBPACK VAR INJECTION */(function(ig) {/*** IMPORTS FROM imports-loader ***/ 761 | (function() { 762 | 763 | 'use strict'; 764 | 765 | ig.module('impact.collision-map').requires('impact.map').defines(function () { 766 | "use strict"; 767 | 768 | ig.CollisionMap = ig.Map.extend({ 769 | 770 | lastSlope: 1, 771 | tiledef: null, 772 | 773 | init: function init(tilesize, data, tiledef) { 774 | this.parent(tilesize, data); 775 | this.tiledef = tiledef || ig.CollisionMap.defaultTileDef; 776 | 777 | for (var t in this.tiledef) { 778 | if (t | 0 > this.lastSlope) { 779 | this.lastSlope = t | 0; 780 | } 781 | } 782 | }, 783 | 784 | trace: function trace(x, y, vx, vy, objectWidth, objectHeight) { 785 | // Set up the trace-result 786 | var res = { 787 | collision: { x: false, y: false, slope: false }, 788 | pos: { x: x, y: y }, 789 | tile: { x: 0, y: 0 } 790 | }; 791 | 792 | // Break the trace down into smaller steps if necessary 793 | var steps = Math.ceil(Math.max(Math.abs(vx), Math.abs(vy)) / this.tilesize); 794 | if (steps > 1) { 795 | var sx = vx / steps; 796 | var sy = vy / steps; 797 | 798 | for (var i = 0; i < steps && (sx || sy); i++) { 799 | this._traceStep(res, x, y, sx, sy, objectWidth, objectHeight, vx, vy, i); 800 | 801 | x = res.pos.x; 802 | y = res.pos.y; 803 | if (res.collision.x) { 804 | sx = 0;vx = 0; 805 | } 806 | if (res.collision.y) { 807 | sy = 0;vy = 0; 808 | } 809 | if (res.collision.slope) { 810 | break; 811 | } 812 | } 813 | } 814 | 815 | // Just one step 816 | else { 817 | this._traceStep(res, x, y, vx, vy, objectWidth, objectHeight, vx, vy, 0); 818 | } 819 | 820 | return res; 821 | }, 822 | 823 | _traceStep: function _traceStep(res, x, y, vx, vy, width, height, rvx, rvy, step) { 824 | 825 | res.pos.x += vx; 826 | res.pos.y += vy; 827 | 828 | var t = 0; 829 | 830 | // Horizontal collision (walls) 831 | if (vx) { 832 | var pxOffsetX = vx > 0 ? width : 0; 833 | var tileOffsetX = vx < 0 ? this.tilesize : 0; 834 | 835 | var firstTileY = Math.max(Math.floor(y / this.tilesize), 0); 836 | var lastTileY = Math.min(Math.ceil((y + height) / this.tilesize), this.height); 837 | var tileX = Math.floor((res.pos.x + pxOffsetX) / this.tilesize); 838 | 839 | // We need to test the new tile position as well as the current one, as we 840 | // could still collide with the current tile if it's a line def. 841 | // We can skip this test if this is not the first step or the new tile position 842 | // is the same as the current one. 843 | var prevTileX = Math.floor((x + pxOffsetX) / this.tilesize); 844 | if (step > 0 || tileX == prevTileX || prevTileX < 0 || prevTileX >= this.width) { 845 | prevTileX = -1; 846 | } 847 | 848 | // Still inside this collision map? 849 | if (tileX >= 0 && tileX < this.width) { 850 | for (var tileY = firstTileY; tileY < lastTileY; tileY++) { 851 | if (prevTileX != -1) { 852 | t = this.data[tileY][prevTileX]; 853 | if (t > 1 && t <= this.lastSlope && this._checkTileDef(res, t, x, y, rvx, rvy, width, height, prevTileX, tileY)) { 854 | break; 855 | } 856 | } 857 | 858 | t = this.data[tileY][tileX]; 859 | if (t == 1 || t > this.lastSlope || // fully solid tile? 860 | t > 1 && this._checkTileDef(res, t, x, y, rvx, rvy, width, height, tileX, tileY) // slope? 861 | ) { 862 | if (t > 1 && t <= this.lastSlope && res.collision.slope) { 863 | break; 864 | } 865 | 866 | // full tile collision! 867 | res.collision.x = true; 868 | res.tile.x = t; 869 | x = res.pos.x = tileX * this.tilesize - pxOffsetX + tileOffsetX; 870 | rvx = 0; 871 | break; 872 | } 873 | } 874 | } 875 | } 876 | 877 | // Vertical collision (floor, ceiling) 878 | if (vy) { 879 | var pxOffsetY = vy > 0 ? height : 0; 880 | var tileOffsetY = vy < 0 ? this.tilesize : 0; 881 | 882 | var firstTileX = Math.max(Math.floor(res.pos.x / this.tilesize), 0); 883 | var lastTileX = Math.min(Math.ceil((res.pos.x + width) / this.tilesize), this.width); 884 | var tileY = Math.floor((res.pos.y + pxOffsetY) / this.tilesize); 885 | 886 | var prevTileY = Math.floor((y + pxOffsetY) / this.tilesize); 887 | if (step > 0 || tileY == prevTileY || prevTileY < 0 || prevTileY >= this.height) { 888 | prevTileY = -1; 889 | } 890 | 891 | // Still inside this collision map? 892 | if (tileY >= 0 && tileY < this.height) { 893 | for (var tileX = firstTileX; tileX < lastTileX; tileX++) { 894 | if (prevTileY != -1) { 895 | t = this.data[prevTileY][tileX]; 896 | if (t > 1 && t <= this.lastSlope && this._checkTileDef(res, t, x, y, rvx, rvy, width, height, tileX, prevTileY)) { 897 | break; 898 | } 899 | } 900 | 901 | t = this.data[tileY][tileX]; 902 | if (t == 1 || t > this.lastSlope || // fully solid tile? 903 | t > 1 && this._checkTileDef(res, t, x, y, rvx, rvy, width, height, tileX, tileY) // slope? 904 | ) { 905 | if (t > 1 && t <= this.lastSlope && res.collision.slope) { 906 | break; 907 | } 908 | 909 | // full tile collision! 910 | res.collision.y = true; 911 | res.tile.y = t; 912 | res.pos.y = tileY * this.tilesize - pxOffsetY + tileOffsetY; 913 | break; 914 | } 915 | } 916 | } 917 | } 918 | 919 | // res is changed in place, nothing to return 920 | }, 921 | 922 | _checkTileDef: function _checkTileDef(res, t, x, y, vx, vy, width, height, tileX, tileY) { 923 | var def = this.tiledef[t]; 924 | if (!def) { 925 | return false; 926 | } 927 | 928 | var lx = (tileX + def[0]) * this.tilesize, 929 | ly = (tileY + def[1]) * this.tilesize, 930 | lvx = (def[2] - def[0]) * this.tilesize, 931 | lvy = (def[3] - def[1]) * this.tilesize, 932 | solid = def[4]; 933 | 934 | // Find the box corner to test, relative to the line 935 | var tx = x + vx + (lvy < 0 ? width : 0) - lx, 936 | ty = y + vy + (lvx > 0 ? height : 0) - ly; 937 | 938 | // Is the box corner behind the line? 939 | if (lvx * ty - lvy * tx > 0) { 940 | 941 | // Lines are only solid from one side - find the dot product of 942 | // line normal and movement vector and dismiss if wrong side 943 | if (vx * -lvy + vy * lvx < 0) { 944 | return solid; 945 | } 946 | 947 | // Find the line normal 948 | var length = Math.sqrt(lvx * lvx + lvy * lvy); 949 | var nx = lvy / length, 950 | ny = -lvx / length; 951 | 952 | // Project out of the line 953 | var proj = tx * nx + ty * ny; 954 | var px = nx * proj, 955 | py = ny * proj; 956 | 957 | // If we project further out than we moved in, then this is a full 958 | // tile collision for solid tiles. 959 | // For non-solid tiles, make sure we were in front of the line. 960 | if (px * px + py * py >= vx * vx + vy * vy) { 961 | return solid || lvx * (ty - vy) - lvy * (tx - vx) < 0.5; 962 | } 963 | 964 | res.pos.x = x + vx - px; 965 | res.pos.y = y + vy - py; 966 | res.collision.slope = { x: lvx, y: lvy, nx: nx, ny: ny }; 967 | return true; 968 | } 969 | 970 | return false; 971 | } 972 | }); 973 | 974 | // Default Slope Tile definition. Each tile is defined by an array of 5 vars: 975 | // - 4 for the line in tile coordinates (0 -- 1) 976 | // - 1 specifing whether the tile is 'filled' behind the line or not 977 | // [ x1, y1, x2, y2, solid ] 978 | 979 | // Defining 'half', 'one third' and 'two thirds' as vars makes it a bit 980 | // easier to read... I hope. 981 | var H = 1 / 2, 982 | N = 1 / 3, 983 | M = 2 / 3, 984 | SOLID = true, 985 | NON_SOLID = false; 986 | 987 | ig.CollisionMap.defaultTileDef = { 988 | /* 15 NE */5: [0, 1, 1, M, SOLID], 6: [0, M, 1, N, SOLID], 7: [0, N, 1, 0, SOLID], 989 | /* 22 NE */3: [0, 1, 1, H, SOLID], 4: [0, H, 1, 0, SOLID], 990 | /* 45 NE */2: [0, 1, 1, 0, SOLID], 991 | /* 67 NE */10: [H, 1, 1, 0, SOLID], 21: [0, 1, H, 0, SOLID], 992 | /* 75 NE */32: [M, 1, 1, 0, SOLID], 43: [N, 1, M, 0, SOLID], 54: [0, 1, N, 0, SOLID], 993 | 994 | /* 15 SE */27: [0, 0, 1, N, SOLID], 28: [0, N, 1, M, SOLID], 29: [0, M, 1, 1, SOLID], 995 | /* 22 SE */25: [0, 0, 1, H, SOLID], 26: [0, H, 1, 1, SOLID], 996 | /* 45 SE */24: [0, 0, 1, 1, SOLID], 997 | /* 67 SE */11: [0, 0, H, 1, SOLID], 22: [H, 0, 1, 1, SOLID], 998 | /* 75 SE */33: [0, 0, N, 1, SOLID], 44: [N, 0, M, 1, SOLID], 55: [M, 0, 1, 1, SOLID], 999 | 1000 | /* 15 NW */16: [1, N, 0, 0, SOLID], 17: [1, M, 0, N, SOLID], 18: [1, 1, 0, M, SOLID], 1001 | /* 22 NW */14: [1, H, 0, 0, SOLID], 15: [1, 1, 0, H, SOLID], 1002 | /* 45 NW */13: [1, 1, 0, 0, SOLID], 1003 | /* 67 NW */8: [H, 1, 0, 0, SOLID], 19: [1, 1, H, 0, SOLID], 1004 | /* 75 NW */30: [N, 1, 0, 0, SOLID], 41: [M, 1, N, 0, SOLID], 52: [1, 1, M, 0, SOLID], 1005 | 1006 | /* 15 SW */38: [1, M, 0, 1, SOLID], 39: [1, N, 0, M, SOLID], 40: [1, 0, 0, N, SOLID], 1007 | /* 22 SW */36: [1, H, 0, 1, SOLID], 37: [1, 0, 0, H, SOLID], 1008 | /* 45 SW */35: [1, 0, 0, 1, SOLID], 1009 | /* 67 SW */9: [1, 0, H, 1, SOLID], 20: [H, 0, 0, 1, SOLID], 1010 | /* 75 SW */31: [1, 0, M, 1, SOLID], 42: [M, 0, N, 1, SOLID], 53: [N, 0, 0, 1, SOLID], 1011 | 1012 | /* Go N */12: [0, 0, 1, 0, NON_SOLID], 1013 | /* Go S */23: [1, 1, 0, 1, NON_SOLID], 1014 | /* Go E */34: [1, 0, 1, 1, NON_SOLID], 1015 | /* Go W */45: [0, 1, 0, 0, NON_SOLID] 1016 | 1017 | // Now that was fun! 1018 | }; 1019 | 1020 | // Static Dummy CollisionMap; never collides 1021 | ig.CollisionMap.staticNoCollision = { trace: function trace(x, y, vx, vy) { 1022 | return { 1023 | collision: { x: false, y: false, slope: false }, 1024 | pos: { x: x + vx, y: y + vy }, 1025 | tile: { x: 0, y: 0 } 1026 | }; 1027 | } }; 1028 | }); 1029 | }.call(window)); 1030 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(/*! ig */ 1))) 1031 | 1032 | /***/ }, 1033 | /* 8 */ 1034 | /*!***********************************!*\ 1035 | !*** ./lib/impact/debug/debug.js ***! 1036 | \***********************************/ 1037 | /***/ function(module, exports, __webpack_require__) { 1038 | 1039 | /* WEBPACK VAR INJECTION */(function(ig) {/*** IMPORTS FROM imports-loader ***/ 1040 | (function() { 1041 | 1042 | 'use strict'; 1043 | 1044 | ig.module('impact.debug.debug').requires('impact.debug.entities-panel', 'impact.debug.maps-panel', 'impact.debug.graph-panel').defines(function () {}); 1045 | }.call(window)); 1046 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(/*! ig */ 1))) 1047 | 1048 | /***/ }, 1049 | /* 9 */ 1050 | /*!********************************************!*\ 1051 | !*** ./lib/impact/debug/entities-panel.js ***! 1052 | \********************************************/ 1053 | /***/ function(module, exports, __webpack_require__) { 1054 | 1055 | /* WEBPACK VAR INJECTION */(function(ig) {/*** IMPORTS FROM imports-loader ***/ 1056 | (function() { 1057 | 1058 | 'use strict'; 1059 | 1060 | var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; }; 1061 | 1062 | ig.module('impact.debug.entities-panel').requires('impact.debug.menu', 'impact.entity').defines(function () { 1063 | "use strict"; 1064 | 1065 | ig.Entity.inject({ 1066 | colors: { 1067 | names: '#fff', 1068 | velocities: '#0f0', 1069 | boxes: '#f00' 1070 | }, 1071 | 1072 | draw: function draw() { 1073 | this.parent(); 1074 | 1075 | // Collision Boxes 1076 | if (ig.Entity._debugShowBoxes) { 1077 | ig.system.context.strokeStyle = this.colors.boxes; 1078 | ig.system.context.lineWidth = 1.0; 1079 | ig.system.context.strokeRect(ig.system.getDrawPos(this.pos.x.round() - ig.game.screen.x) - 0.5, ig.system.getDrawPos(this.pos.y.round() - ig.game.screen.y) - 0.5, this.size.x * ig.system.scale, this.size.y * ig.system.scale); 1080 | } 1081 | 1082 | // Velocities 1083 | if (ig.Entity._debugShowVelocities) { 1084 | var x = this.pos.x + this.size.x / 2; 1085 | var y = this.pos.y + this.size.y / 2; 1086 | 1087 | this._debugDrawLine(this.colors.velocities, x, y, x + this.vel.x, y + this.vel.y); 1088 | } 1089 | 1090 | // Names & Targets 1091 | if (ig.Entity._debugShowNames) { 1092 | if (this.name) { 1093 | ig.system.context.fillStyle = this.colors.names; 1094 | ig.system.context.fillText(this.name, ig.system.getDrawPos(this.pos.x - ig.game.screen.x), ig.system.getDrawPos(this.pos.y - ig.game.screen.y)); 1095 | } 1096 | 1097 | if (_typeof(this.target) == 'object') { 1098 | for (var t in this.target) { 1099 | var ent = ig.game.getEntityByName(this.target[t]); 1100 | if (ent) { 1101 | this._debugDrawLine(this.colors.names, this.pos.x + this.size.x / 2, this.pos.y + this.size.y / 2, ent.pos.x + ent.size.x / 2, ent.pos.y + ent.size.y / 2); 1102 | } 1103 | } 1104 | } 1105 | } 1106 | }, 1107 | 1108 | _debugDrawLine: function _debugDrawLine(color, sx, sy, dx, dy) { 1109 | ig.system.context.strokeStyle = color; 1110 | ig.system.context.lineWidth = 1.0; 1111 | 1112 | ig.system.context.beginPath(); 1113 | ig.system.context.moveTo(ig.system.getDrawPos(sx - ig.game.screen.x), ig.system.getDrawPos(sy - ig.game.screen.y)); 1114 | ig.system.context.lineTo(ig.system.getDrawPos(dx - ig.game.screen.x), ig.system.getDrawPos(dy - ig.game.screen.y)); 1115 | ig.system.context.stroke(); 1116 | ig.system.context.closePath(); 1117 | } 1118 | }); 1119 | 1120 | ig.Entity._debugEnableChecks = true; 1121 | ig.Entity._debugShowBoxes = false; 1122 | ig.Entity._debugShowVelocities = false; 1123 | ig.Entity._debugShowNames = false; 1124 | 1125 | ig.Entity.oldCheckPair = ig.Entity.checkPair; 1126 | ig.Entity.checkPair = function (a, b) { 1127 | if (!ig.Entity._debugEnableChecks) { 1128 | return; 1129 | } 1130 | ig.Entity.oldCheckPair(a, b); 1131 | }; 1132 | 1133 | ig.debug.addPanel({ 1134 | type: ig.DebugPanel, 1135 | name: 'entities', 1136 | label: 'Entities', 1137 | options: [{ 1138 | name: 'Checks & Collisions', 1139 | object: ig.Entity, 1140 | property: '_debugEnableChecks' 1141 | }, { 1142 | name: 'Show Collision Boxes', 1143 | object: ig.Entity, 1144 | property: '_debugShowBoxes' 1145 | }, { 1146 | name: 'Show Velocities', 1147 | object: ig.Entity, 1148 | property: '_debugShowVelocities' 1149 | }, { 1150 | name: 'Show Names & Targets', 1151 | object: ig.Entity, 1152 | property: '_debugShowNames' 1153 | }] 1154 | }); 1155 | }); 1156 | }.call(window)); 1157 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(/*! ig */ 1))) 1158 | 1159 | /***/ }, 1160 | /* 10 */ 1161 | /*!*****************************************!*\ 1162 | !*** ./lib/impact/debug/graph-panel.js ***! 1163 | \*****************************************/ 1164 | /***/ function(module, exports, __webpack_require__) { 1165 | 1166 | /* WEBPACK VAR INJECTION */(function(ig) {/*** IMPORTS FROM imports-loader ***/ 1167 | (function() { 1168 | 1169 | 'use strict'; 1170 | 1171 | ig.module('impact.debug.graph-panel').requires('impact.debug.menu', 'impact.system', 'impact.game', 'impact.image').defines(function () { 1172 | "use strict"; 1173 | 1174 | ig.Game.inject({ 1175 | draw: function draw() { 1176 | ig.graph.beginClock('draw'); 1177 | this.parent(); 1178 | ig.graph.endClock('draw'); 1179 | }, 1180 | 1181 | update: function update() { 1182 | ig.graph.beginClock('update'); 1183 | this.parent(); 1184 | ig.graph.endClock('update'); 1185 | }, 1186 | 1187 | checkEntities: function checkEntities() { 1188 | ig.graph.beginClock('checks'); 1189 | this.parent(); 1190 | ig.graph.endClock('checks'); 1191 | } 1192 | }); 1193 | 1194 | ig.DebugGraphPanel = ig.DebugPanel.extend({ 1195 | clocks: {}, 1196 | marks: [], 1197 | textY: 0, 1198 | height: 128, 1199 | ms: 64, 1200 | timeBeforeRun: 0, 1201 | 1202 | init: function init(name, label) { 1203 | this.parent(name, label); 1204 | 1205 | this.mark16ms = (this.height - this.height / this.ms * 16).round(); 1206 | this.mark33ms = (this.height - this.height / this.ms * 33).round(); 1207 | this.msHeight = this.height / this.ms; 1208 | 1209 | this.graph = ig.$new('canvas'); 1210 | this.graph.width = window.innerWidth; 1211 | this.graph.height = this.height; 1212 | this.container.appendChild(this.graph); 1213 | this.ctx = this.graph.getContext('2d'); 1214 | 1215 | this.ctx.fillStyle = '#444'; 1216 | this.ctx.fillRect(0, this.mark16ms, this.graph.width, 1); 1217 | this.ctx.fillRect(0, this.mark33ms, this.graph.width, 1); 1218 | 1219 | this.addGraphMark('16ms', this.mark16ms); 1220 | this.addGraphMark('33ms', this.mark33ms); 1221 | 1222 | this.addClock('draw', 'Draw', '#13baff'); 1223 | this.addClock('update', 'Entity Update', '#bb0fff'); 1224 | this.addClock('checks', 'Entity Checks & Collisions', '#a2e908'); 1225 | this.addClock('lag', 'System Lag', '#f26900'); 1226 | 1227 | ig.mark = this.mark.bind(this); 1228 | ig.graph = this; 1229 | }, 1230 | 1231 | addGraphMark: function addGraphMark(name, height) { 1232 | var span = ig.$new('span'); 1233 | span.className = 'ig_debug_graph_mark'; 1234 | span.textContent = name; 1235 | span.style.top = height.round() + 'px'; 1236 | this.container.appendChild(span); 1237 | }, 1238 | 1239 | addClock: function addClock(name, description, color) { 1240 | var mark = ig.$new('span'); 1241 | mark.className = 'ig_debug_legend_color'; 1242 | mark.style.backgroundColor = color; 1243 | 1244 | var number = ig.$new('span'); 1245 | number.className = 'ig_debug_legend_number'; 1246 | number.appendChild(document.createTextNode('0')); 1247 | 1248 | var legend = ig.$new('span'); 1249 | legend.className = 'ig_debug_legend'; 1250 | legend.appendChild(mark); 1251 | legend.appendChild(document.createTextNode(description + ' (')); 1252 | legend.appendChild(number); 1253 | legend.appendChild(document.createTextNode('ms)')); 1254 | 1255 | this.container.appendChild(legend); 1256 | 1257 | this.clocks[name] = { 1258 | description: description, 1259 | color: color, 1260 | current: 0, 1261 | start: Date.now(), 1262 | avg: 0, 1263 | html: number 1264 | }; 1265 | }, 1266 | 1267 | beginClock: function beginClock(name, offset) { 1268 | this.clocks[name].start = Date.now() + (offset || 0); 1269 | }, 1270 | 1271 | endClock: function endClock(name) { 1272 | var c = this.clocks[name]; 1273 | c.current = Math.round(Date.now() - c.start); 1274 | c.avg = c.avg * 0.8 + c.current * 0.2; 1275 | }, 1276 | 1277 | mark: function mark(msg, color) { 1278 | if (this.active) { 1279 | this.marks.push({ msg: msg, color: color || '#fff' }); 1280 | } 1281 | }, 1282 | 1283 | beforeRun: function beforeRun() { 1284 | this.endClock('lag'); 1285 | this.timeBeforeRun = Date.now(); 1286 | }, 1287 | 1288 | afterRun: function afterRun() { 1289 | var frameTime = Date.now() - this.timeBeforeRun; 1290 | var nextFrameDue = 1000 / ig.system.fps - frameTime; 1291 | this.beginClock('lag', Math.max(nextFrameDue, 0)); 1292 | 1293 | var x = this.graph.width - 1; 1294 | var y = this.height; 1295 | 1296 | this.ctx.drawImage(this.graph, -1, 0); 1297 | 1298 | this.ctx.fillStyle = '#000'; 1299 | this.ctx.fillRect(x, 0, 1, this.height); 1300 | 1301 | this.ctx.fillStyle = '#444'; 1302 | this.ctx.fillRect(x, this.mark16ms, 1, 1); 1303 | 1304 | this.ctx.fillStyle = '#444'; 1305 | this.ctx.fillRect(x, this.mark33ms, 1, 1); 1306 | 1307 | for (var ci in this.clocks) { 1308 | var c = this.clocks[ci]; 1309 | c.html.textContent = c.avg.toFixed(2); 1310 | 1311 | if (c.color && c.current > 0) { 1312 | this.ctx.fillStyle = c.color; 1313 | var h = c.current * this.msHeight; 1314 | y -= h; 1315 | this.ctx.fillRect(x, y, 1, h); 1316 | c.current = 0; 1317 | } 1318 | } 1319 | 1320 | this.ctx.textAlign = 'right'; 1321 | this.ctx.textBaseline = 'top'; 1322 | this.ctx.globalAlpha = 0.5; 1323 | 1324 | for (var i = 0; i < this.marks.length; i++) { 1325 | var m = this.marks[i]; 1326 | this.ctx.fillStyle = m.color; 1327 | this.ctx.fillRect(x, 0, 1, this.height); 1328 | if (m.msg) { 1329 | this.ctx.fillText(m.msg, x - 1, this.textY); 1330 | this.textY = (this.textY + 8) % 32; 1331 | } 1332 | } 1333 | this.ctx.globalAlpha = 1; 1334 | this.marks = []; 1335 | } 1336 | }); 1337 | 1338 | ig.debug.addPanel({ 1339 | type: ig.DebugGraphPanel, 1340 | name: 'graph', 1341 | label: 'Performance' 1342 | }); 1343 | }); 1344 | }.call(window)); 1345 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(/*! ig */ 1))) 1346 | 1347 | /***/ }, 1348 | /* 11 */ 1349 | /*!****************************************!*\ 1350 | !*** ./lib/impact/debug/maps-panel.js ***! 1351 | \****************************************/ 1352 | /***/ function(module, exports, __webpack_require__) { 1353 | 1354 | /* WEBPACK VAR INJECTION */(function(ig) {/*** IMPORTS FROM imports-loader ***/ 1355 | (function() { 1356 | 1357 | 'use strict'; 1358 | 1359 | ig.module('impact.debug.maps-panel').requires('impact.debug.menu', 'impact.game', 'impact.background-map').defines(function () { 1360 | "use strict"; 1361 | 1362 | ig.Game.inject({ 1363 | loadLevel: function loadLevel(data) { 1364 | this.parent(data); 1365 | ig.debug.panels.maps.load(this); 1366 | } 1367 | }); 1368 | 1369 | ig.DebugMapsPanel = ig.DebugPanel.extend({ 1370 | maps: [], 1371 | mapScreens: [], 1372 | 1373 | init: function init(name, label) { 1374 | this.parent(name, label); 1375 | this.load(); 1376 | }, 1377 | 1378 | load: function load(game) { 1379 | this.options = []; 1380 | this.panels = []; 1381 | 1382 | if (!game || !game.backgroundMaps.length) { 1383 | this.container.innerHTML = 'No Maps Loaded'; 1384 | return; 1385 | } 1386 | 1387 | this.maps = game.backgroundMaps; 1388 | this.mapScreens = []; 1389 | this.container.innerHTML = ''; 1390 | 1391 | for (var m = 0; m < this.maps.length; m++) { 1392 | var map = this.maps[m]; 1393 | 1394 | var subPanel = new ig.DebugPanel(m, 'Layer ' + m); 1395 | 1396 | var head = new ig.$new('strong'); 1397 | head.textContent = m + ': ' + map.tiles.path; 1398 | subPanel.container.appendChild(head); 1399 | 1400 | subPanel.addOption(new ig.DebugOption('Enabled', map, 'enabled')); 1401 | subPanel.addOption(new ig.DebugOption('Pre Rendered', map, 'preRender')); 1402 | subPanel.addOption(new ig.DebugOption('Show Chunks', map, 'debugChunks')); 1403 | 1404 | this.generateMiniMap(subPanel, map, m); 1405 | this.addPanel(subPanel); 1406 | } 1407 | }, 1408 | 1409 | generateMiniMap: function generateMiniMap(panel, map, id) { 1410 | var s = ig.system.scale; // we'll need this a lot 1411 | 1412 | // resize the tileset, so that one tile is 's' pixels wide and high 1413 | var ts = ig.$new('canvas'); 1414 | var tsctx = ts.getContext('2d'); 1415 | 1416 | var w = map.tiles.width * s; 1417 | var h = map.tiles.height * s; 1418 | var ws = w / map.tilesize; 1419 | var hs = h / map.tilesize; 1420 | ts.width = ws; 1421 | ts.height = hs; 1422 | tsctx.drawImage(map.tiles.data, 0, 0, w, h, 0, 0, ws, hs); 1423 | 1424 | // create the minimap canvas 1425 | var mapCanvas = ig.$new('canvas'); 1426 | mapCanvas.width = map.width * s; 1427 | mapCanvas.height = map.height * s; 1428 | var ctx = mapCanvas.getContext('2d'); 1429 | 1430 | if (ig.game.clearColor) { 1431 | ctx.fillStyle = ig.game.clearColor; 1432 | ctx.fillRect(0, 0, w, h); 1433 | } 1434 | 1435 | // draw the map 1436 | var tile = 0; 1437 | for (var x = 0; x < map.width; x++) { 1438 | for (var y = 0; y < map.height; y++) { 1439 | if (tile = map.data[y][x]) { 1440 | ctx.drawImage(ts, Math.floor((tile - 1) * s % ws), Math.floor((tile - 1) * s / ws) * s, s, s, x * s, y * s, s, s); 1441 | } 1442 | } 1443 | } 1444 | 1445 | var mapContainer = ig.$new('div'); 1446 | mapContainer.className = 'ig_debug_map_container'; 1447 | mapContainer.style.width = map.width * s + 'px'; 1448 | mapContainer.style.height = map.height * s + 'px'; 1449 | 1450 | var mapScreen = ig.$new('div'); 1451 | mapScreen.className = 'ig_debug_map_screen'; 1452 | mapScreen.style.width = ig.system.width / map.tilesize * s - 2 + 'px'; 1453 | mapScreen.style.height = ig.system.height / map.tilesize * s - 2 + 'px'; 1454 | this.mapScreens[id] = mapScreen; 1455 | 1456 | mapContainer.appendChild(mapCanvas); 1457 | mapContainer.appendChild(mapScreen); 1458 | panel.container.appendChild(mapContainer); 1459 | }, 1460 | 1461 | afterRun: function afterRun() { 1462 | // Update the screen position DIV for each mini-map 1463 | var s = ig.system.scale; 1464 | for (var m = 0; m < this.maps.length; m++) { 1465 | var map = this.maps[m]; 1466 | var screen = this.mapScreens[m]; 1467 | 1468 | if (!map || !screen) { 1469 | // Quick sanity check 1470 | continue; 1471 | } 1472 | 1473 | var x = map.scroll.x / map.tilesize; 1474 | var y = map.scroll.y / map.tilesize; 1475 | 1476 | if (map.repeat) { 1477 | x %= map.width; 1478 | y %= map.height; 1479 | } 1480 | 1481 | screen.style.left = x * s + 'px'; 1482 | screen.style.top = y * s + 'px'; 1483 | } 1484 | } 1485 | }); 1486 | 1487 | ig.debug.addPanel({ 1488 | type: ig.DebugMapsPanel, 1489 | name: 'maps', 1490 | label: 'Background Maps' 1491 | }); 1492 | }); 1493 | }.call(window)); 1494 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(/*! ig */ 1))) 1495 | 1496 | /***/ }, 1497 | /* 12 */ 1498 | /*!**********************************!*\ 1499 | !*** ./lib/impact/debug/menu.js ***! 1500 | \**********************************/ 1501 | /***/ function(module, exports, __webpack_require__) { 1502 | 1503 | /* WEBPACK VAR INJECTION */(function(ig) {/*** IMPORTS FROM imports-loader ***/ 1504 | (function() { 1505 | 1506 | 'use strict'; 1507 | 1508 | ig.module('impact.debug.menu').requires('dom.ready', 'impact.system').defines(function () { 1509 | "use strict"; 1510 | 1511 | ig.System.inject({ 1512 | run: function run() { 1513 | ig.debug.beforeRun(); 1514 | this.parent(); 1515 | ig.debug.afterRun(); 1516 | }, 1517 | 1518 | setGameNow: function setGameNow(gameClass) { 1519 | this.parent(gameClass); 1520 | ig.debug.ready(); 1521 | } 1522 | }); 1523 | 1524 | ig.Debug = ig.Class.extend({ 1525 | options: {}, 1526 | panels: {}, 1527 | numbers: {}, 1528 | container: null, 1529 | panelMenu: null, 1530 | activePanel: null, 1531 | 1532 | debugTime: 0, 1533 | debugTickAvg: 0.016, 1534 | debugRealTime: Date.now(), 1535 | 1536 | init: function init() { 1537 | // Inject the Stylesheet 1538 | var style = ig.$new('link'); 1539 | style.rel = 'stylesheet'; 1540 | style.type = 'text/css'; 1541 | style.href = ig.prefix + 'lib/impact/debug/debug.css'; 1542 | ig.$('body')[0].appendChild(style); 1543 | 1544 | // Create the Debug Container 1545 | this.container = ig.$new('div'); 1546 | this.container.className = 'ig_debug'; 1547 | ig.$('body')[0].appendChild(this.container); 1548 | 1549 | // Create and add the Menu Container 1550 | this.panelMenu = ig.$new('div'); 1551 | this.panelMenu.innerHTML = '
Impact.Debug:
'; 1552 | this.panelMenu.className = 'ig_debug_panel_menu'; 1553 | 1554 | this.container.appendChild(this.panelMenu); 1555 | 1556 | // Create and add the Stats Container 1557 | this.numberContainer = ig.$new('div'); 1558 | this.numberContainer.className = 'ig_debug_stats'; 1559 | this.panelMenu.appendChild(this.numberContainer); 1560 | 1561 | // Set ig.log(), ig.assert() and ig.show() 1562 | if (window.console && window.console.log && window.console.assert) { 1563 | // Can't use .bind() on native functions in IE9 :/ 1564 | ig.log = console.log.bind ? console.log.bind(console) : console.log; 1565 | ig.assert = console.assert.bind ? console.assert.bind(console) : console.assert; 1566 | } 1567 | ig.show = this.showNumber.bind(this); 1568 | }, 1569 | 1570 | addNumber: function addNumber(name, width) { 1571 | var number = ig.$new('span'); 1572 | this.numberContainer.appendChild(number); 1573 | this.numberContainer.appendChild(document.createTextNode(name)); 1574 | 1575 | this.numbers[name] = number; 1576 | }, 1577 | 1578 | showNumber: function showNumber(name, number, width) { 1579 | if (!this.numbers[name]) { 1580 | this.addNumber(name, width); 1581 | } 1582 | this.numbers[name].textContent = number; 1583 | }, 1584 | 1585 | addPanel: function addPanel(panelDef) { 1586 | // Create the panel and options 1587 | var panel = new panelDef.type(panelDef.name, panelDef.label); 1588 | if (panelDef.options) { 1589 | for (var i = 0; i < panelDef.options.length; i++) { 1590 | var opt = panelDef.options[i]; 1591 | panel.addOption(new ig.DebugOption(opt.name, opt.object, opt.property)); 1592 | } 1593 | } 1594 | 1595 | this.panels[panel.name] = panel; 1596 | panel.container.style.display = 'none'; 1597 | this.container.appendChild(panel.container); 1598 | 1599 | // Create the menu item 1600 | var menuItem = ig.$new('div'); 1601 | menuItem.className = 'ig_debug_menu_item'; 1602 | menuItem.textContent = panel.label; 1603 | menuItem.addEventListener('click', function (ev) { 1604 | this.togglePanel(panel); 1605 | }.bind(this), false); 1606 | panel.menuItem = menuItem; 1607 | 1608 | // Insert menu item in alphabetical order into the menu 1609 | var inserted = false; 1610 | for (var i = 1; i < this.panelMenu.childNodes.length; i++) { 1611 | var cn = this.panelMenu.childNodes[i]; 1612 | if (cn.textContent > panel.label) { 1613 | this.panelMenu.insertBefore(menuItem, cn); 1614 | inserted = true; 1615 | break; 1616 | } 1617 | } 1618 | if (!inserted) { 1619 | // Not inserted? Append at the end! 1620 | this.panelMenu.appendChild(menuItem); 1621 | } 1622 | }, 1623 | 1624 | showPanel: function showPanel(name) { 1625 | this.togglePanel(this.panels[name]); 1626 | }, 1627 | 1628 | togglePanel: function togglePanel(panel) { 1629 | if (panel != this.activePanel && this.activePanel) { 1630 | this.activePanel.toggle(false); 1631 | this.activePanel.menuItem.className = 'ig_debug_menu_item'; 1632 | this.activePanel = null; 1633 | } 1634 | 1635 | var dsp = panel.container.style.display; 1636 | var active = dsp != 'block'; 1637 | panel.toggle(active); 1638 | panel.menuItem.className = 'ig_debug_menu_item' + (active ? ' active' : ''); 1639 | 1640 | if (active) { 1641 | this.activePanel = panel; 1642 | } 1643 | }, 1644 | 1645 | ready: function ready() { 1646 | for (var p in this.panels) { 1647 | this.panels[p].ready(); 1648 | } 1649 | }, 1650 | 1651 | beforeRun: function beforeRun() { 1652 | var timeBeforeRun = Date.now(); 1653 | this.debugTickAvg = this.debugTickAvg * 0.8 + (timeBeforeRun - this.debugRealTime) * 0.2; 1654 | this.debugRealTime = timeBeforeRun; 1655 | 1656 | if (this.activePanel) { 1657 | this.activePanel.beforeRun(); 1658 | } 1659 | }, 1660 | 1661 | afterRun: function afterRun() { 1662 | var frameTime = Date.now() - this.debugRealTime; 1663 | var nextFrameDue = 1000 / ig.system.fps - frameTime; 1664 | 1665 | this.debugTime = this.debugTime * 0.8 + frameTime * 0.2; 1666 | 1667 | if (this.activePanel) { 1668 | this.activePanel.afterRun(); 1669 | } 1670 | 1671 | this.showNumber('ms', this.debugTime.toFixed(2)); 1672 | this.showNumber('fps', Math.round(1000 / this.debugTickAvg)); 1673 | this.showNumber('draws', ig.Image.drawCount); 1674 | if (ig.game && ig.game.entities) { 1675 | this.showNumber('entities', ig.game.entities.length); 1676 | } 1677 | ig.Image.drawCount = 0; 1678 | } 1679 | }); 1680 | 1681 | ig.DebugPanel = ig.Class.extend({ 1682 | active: false, 1683 | container: null, 1684 | options: [], 1685 | panels: [], 1686 | label: '', 1687 | name: '', 1688 | 1689 | init: function init(name, label) { 1690 | this.name = name; 1691 | this.label = label; 1692 | this.container = ig.$new('div'); 1693 | this.container.className = 'ig_debug_panel ' + this.name; 1694 | }, 1695 | 1696 | toggle: function toggle(active) { 1697 | this.active = active; 1698 | this.container.style.display = active ? 'block' : 'none'; 1699 | }, 1700 | 1701 | addPanel: function addPanel(panel) { 1702 | this.panels.push(panel); 1703 | this.container.appendChild(panel.container); 1704 | }, 1705 | 1706 | addOption: function addOption(option) { 1707 | this.options.push(option); 1708 | this.container.appendChild(option.container); 1709 | }, 1710 | 1711 | ready: function ready() {}, 1712 | beforeRun: function beforeRun() {}, 1713 | afterRun: function afterRun() {} 1714 | }); 1715 | 1716 | ig.DebugOption = ig.Class.extend({ 1717 | name: '', 1718 | labelName: '', 1719 | className: 'ig_debug_option', 1720 | label: null, 1721 | mark: null, 1722 | container: null, 1723 | active: false, 1724 | 1725 | colors: { 1726 | enabled: '#fff', 1727 | disabled: '#444' 1728 | }, 1729 | 1730 | init: function init(name, object, property) { 1731 | this.name = name; 1732 | this.object = object; 1733 | this.property = property; 1734 | 1735 | this.active = this.object[this.property]; 1736 | 1737 | this.container = ig.$new('div'); 1738 | this.container.className = 'ig_debug_option'; 1739 | 1740 | this.label = ig.$new('span'); 1741 | this.label.className = 'ig_debug_label'; 1742 | this.label.textContent = this.name; 1743 | 1744 | this.mark = ig.$new('span'); 1745 | this.mark.className = 'ig_debug_label_mark'; 1746 | 1747 | this.container.appendChild(this.mark); 1748 | this.container.appendChild(this.label); 1749 | this.container.addEventListener('click', this.click.bind(this), false); 1750 | 1751 | this.setLabel(); 1752 | }, 1753 | 1754 | setLabel: function setLabel() { 1755 | this.mark.style.backgroundColor = this.active ? this.colors.enabled : this.colors.disabled; 1756 | }, 1757 | 1758 | click: function click(ev) { 1759 | this.active = !this.active; 1760 | this.object[this.property] = this.active; 1761 | this.setLabel(); 1762 | 1763 | ev.stopPropagation(); 1764 | ev.preventDefault(); 1765 | return false; 1766 | } 1767 | }); 1768 | 1769 | // Create the debug instance! 1770 | ig.debug = new ig.Debug(); 1771 | }); 1772 | }.call(window)); 1773 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(/*! ig */ 1))) 1774 | 1775 | /***/ }, 1776 | /* 13 */ 1777 | /*!***********************************!*\ 1778 | !*** ./lib/impact/entity-pool.js ***! 1779 | \***********************************/ 1780 | /***/ function(module, exports, __webpack_require__) { 1781 | 1782 | /* WEBPACK VAR INJECTION */(function(ig) {/*** IMPORTS FROM imports-loader ***/ 1783 | (function() { 1784 | 1785 | 'use strict'; 1786 | 1787 | ig.module('impact.entity-pool').requires('impact.game').defines(function () { 1788 | "use strict"; 1789 | 1790 | ig.EntityPool = { 1791 | pools: {}, 1792 | 1793 | mixin: { 1794 | staticInstantiate: function staticInstantiate(x, y, settings) { 1795 | return ig.EntityPool.getFromPool(this.classId, x, y, settings); 1796 | }, 1797 | 1798 | erase: function erase() { 1799 | ig.EntityPool.putInPool(this); 1800 | } 1801 | }, 1802 | 1803 | enableFor: function enableFor(Class) { 1804 | Class.inject(this.mixin); 1805 | }, 1806 | 1807 | getFromPool: function getFromPool(classId, x, y, settings) { 1808 | var pool = this.pools[classId]; 1809 | if (!pool || !pool.length) { 1810 | return null; 1811 | } 1812 | 1813 | var instance = pool.pop(); 1814 | instance.reset(x, y, settings); 1815 | return instance; 1816 | }, 1817 | 1818 | putInPool: function putInPool(instance) { 1819 | if (!this.pools[instance.classId]) { 1820 | this.pools[instance.classId] = [instance]; 1821 | } else { 1822 | this.pools[instance.classId].push(instance); 1823 | } 1824 | }, 1825 | 1826 | drainPool: function drainPool(classId) { 1827 | delete this.pools[classId]; 1828 | }, 1829 | 1830 | drainAllPools: function drainAllPools() { 1831 | this.pools = {}; 1832 | } 1833 | }; 1834 | 1835 | ig.Game.inject({ 1836 | loadLevel: function loadLevel(data) { 1837 | ig.EntityPool.drainAllPools(); 1838 | this.parent(data); 1839 | } 1840 | }); 1841 | }); 1842 | }.call(window)); 1843 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(/*! ig */ 1))) 1844 | 1845 | /***/ }, 1846 | /* 14 */ 1847 | /*!******************************!*\ 1848 | !*** ./lib/impact/entity.js ***! 1849 | \******************************/ 1850 | /***/ function(module, exports, __webpack_require__) { 1851 | 1852 | /* WEBPACK VAR INJECTION */(function(ig) {/*** IMPORTS FROM imports-loader ***/ 1853 | (function() { 1854 | 1855 | 'use strict'; 1856 | 1857 | ig.module('impact.entity').requires('impact.animation', 'impact.impact').defines(function () { 1858 | "use strict"; 1859 | 1860 | ig.Entity = ig.Class.extend({ 1861 | id: 0, 1862 | settings: {}, 1863 | 1864 | size: { x: 16, y: 16 }, 1865 | offset: { x: 0, y: 0 }, 1866 | 1867 | pos: { x: 0, y: 0 }, 1868 | last: { x: 0, y: 0 }, 1869 | vel: { x: 0, y: 0 }, 1870 | accel: { x: 0, y: 0 }, 1871 | friction: { x: 0, y: 0 }, 1872 | maxVel: { x: 100, y: 100 }, 1873 | zIndex: 0, 1874 | gravityFactor: 1, 1875 | standing: false, 1876 | bounciness: 0, 1877 | minBounceVelocity: 40, 1878 | __id: null, 1879 | 1880 | anims: {}, 1881 | animSheet: null, 1882 | currentAnim: null, 1883 | health: 10, 1884 | 1885 | type: 0, // TYPE.NONE 1886 | checkAgainst: 0, // TYPE.NONE 1887 | collides: 0, // COLLIDES.NEVER 1888 | 1889 | _killed: false, 1890 | 1891 | slopeStanding: { min: 44 .toRad(), max: 136 .toRad() }, 1892 | 1893 | init: function init(x, y, settings) { 1894 | ; 1895 | this.id = ++ig.Entity._lastId; 1896 | this.pos.x = this.last.x = x; 1897 | this.pos.y = this.last.y = y; 1898 | 1899 | ig.merge(this, settings); 1900 | }, 1901 | 1902 | reset: function reset(x, y, settings) { 1903 | var proto = this.constructor.prototype; 1904 | this.pos.x = x; 1905 | this.pos.y = y; 1906 | this.last.x = x; 1907 | this.last.y = y; 1908 | this.vel.x = proto.vel.x; 1909 | this.vel.y = proto.vel.y; 1910 | this.accel.x = proto.accel.x; 1911 | this.accel.y = proto.accel.y; 1912 | this.health = proto.health; 1913 | this._killed = proto._killed; 1914 | this.standing = proto.standing; 1915 | 1916 | this.type = proto.type; 1917 | this.checkAgainst = proto.checkAgainst; 1918 | this.collides = proto.collides; 1919 | 1920 | ig.merge(this, settings); 1921 | }, 1922 | 1923 | addAnim: function addAnim(name, frameTime, sequence, stop) { 1924 | if (!this.animSheet) { 1925 | throw 'No animSheet to add the animation ' + name + ' to.'; 1926 | } 1927 | var a = new ig.Animation(this.animSheet, frameTime, sequence, stop); 1928 | this.anims[name] = a; 1929 | if (!this.currentAnim) { 1930 | this.currentAnim = a; 1931 | } 1932 | 1933 | return a; 1934 | }, 1935 | 1936 | update: function update() { 1937 | this.last.x = this.pos.x; 1938 | this.last.y = this.pos.y; 1939 | this.vel.y += ig.game.gravity * ig.system.tick * this.gravityFactor; 1940 | 1941 | this.vel.x = this.getNewVelocity(this.vel.x, this.accel.x, this.friction.x, this.maxVel.x); 1942 | this.vel.y = this.getNewVelocity(this.vel.y, this.accel.y, this.friction.y, this.maxVel.y); 1943 | //console.log(this.__id, this.vel); 1944 | // movement & collision 1945 | var mx = this.vel.x * ig.system.tick; 1946 | var my = this.vel.y * ig.system.tick; 1947 | var res = ig.game.collisionMap.trace(this.pos.x, this.pos.y, mx, my, this.size.x, this.size.y); 1948 | //console.log(this.__id, mx, my); 1949 | this.handleMovementTrace(res); 1950 | 1951 | if (this.currentAnim) { 1952 | this.currentAnim.update(); 1953 | } 1954 | }, 1955 | 1956 | getNewVelocity: function getNewVelocity(vel, accel, friction, max) { 1957 | if (accel) { 1958 | return (vel + accel * ig.system.tick).limit(-max, max); 1959 | } else if (friction) { 1960 | var delta = friction * ig.system.tick; 1961 | 1962 | if (vel - delta > 0) { 1963 | return vel - delta; 1964 | } else if (vel + delta < 0) { 1965 | return vel + delta; 1966 | } else { 1967 | return 0; 1968 | } 1969 | } 1970 | 1971 | return vel.limit(-max, max); 1972 | }, 1973 | 1974 | handleMovementTrace: function handleMovementTrace(res) { 1975 | this.standing = false; 1976 | 1977 | if (res.collision.y) { 1978 | if (this.bounciness > 0 && Math.abs(this.vel.y) > this.minBounceVelocity) { 1979 | this.vel.y *= -this.bounciness; 1980 | } else { 1981 | if (this.vel.y > 0) { 1982 | this.standing = true; 1983 | } 1984 | this.vel.y = 0; 1985 | } 1986 | } 1987 | if (res.collision.x) { 1988 | if (this.bounciness > 0 && Math.abs(this.vel.x) > this.minBounceVelocity) { 1989 | this.vel.x *= -this.bounciness; 1990 | } else { 1991 | this.vel.x = 0; 1992 | } 1993 | } 1994 | if (res.collision.slope) { 1995 | var s = res.collision.slope; 1996 | 1997 | if (this.bounciness > 0) { 1998 | var proj = this.vel.x * s.nx + this.vel.y * s.ny; 1999 | 2000 | this.vel.x = (this.vel.x - s.nx * proj * 2) * this.bounciness; 2001 | this.vel.y = (this.vel.y - s.ny * proj * 2) * this.bounciness; 2002 | } else { 2003 | var lengthSquared = s.x * s.x + s.y * s.y; 2004 | var dot = (this.vel.x * s.x + this.vel.y * s.y) / lengthSquared; 2005 | 2006 | this.vel.x = s.x * dot; 2007 | this.vel.y = s.y * dot; 2008 | 2009 | var angle = Math.atan2(s.x, s.y); 2010 | if (angle > this.slopeStanding.min && angle < this.slopeStanding.max) { 2011 | this.standing = true; 2012 | } 2013 | } 2014 | } 2015 | 2016 | this.pos = res.pos; 2017 | }, 2018 | 2019 | draw: function draw() { 2020 | if (this.currentAnim) { 2021 | this.currentAnim.draw(this.pos.x - this.offset.x - ig.game._rscreen.x, this.pos.y - this.offset.y - ig.game._rscreen.y); 2022 | } 2023 | }, 2024 | 2025 | kill: function kill() { 2026 | ig.game.removeEntity(this); 2027 | }, 2028 | 2029 | receiveDamage: function receiveDamage(amount, from) { 2030 | this.health -= amount; 2031 | if (this.health <= 0) { 2032 | this.kill(); 2033 | } 2034 | }, 2035 | 2036 | touches: function touches(other) { 2037 | return !(this.pos.x >= other.pos.x + other.size.x || this.pos.x + this.size.x <= other.pos.x || this.pos.y >= other.pos.y + other.size.y || this.pos.y + this.size.y <= other.pos.y); 2038 | }, 2039 | 2040 | distanceTo: function distanceTo(other) { 2041 | var xd = this.pos.x + this.size.x / 2 - (other.pos.x + other.size.x / 2); 2042 | var yd = this.pos.y + this.size.y / 2 - (other.pos.y + other.size.y / 2); 2043 | return Math.sqrt(xd * xd + yd * yd); 2044 | }, 2045 | 2046 | angleTo: function angleTo(other) { 2047 | return Math.atan2(other.pos.y + other.size.y / 2 - (this.pos.y + this.size.y / 2), other.pos.x + other.size.x / 2 - (this.pos.x + this.size.x / 2)); 2048 | }, 2049 | 2050 | check: function check(other) {}, 2051 | collideWith: function collideWith(other, axis) {}, 2052 | ready: function ready() {}, 2053 | erase: function erase() {} 2054 | }); 2055 | 2056 | // Last used entity id; incremented with each spawned entity 2057 | 2058 | ig.Entity._lastId = 0; 2059 | 2060 | // Collision Types - Determine if and how entities collide with each other 2061 | 2062 | // In ACTIVE vs. LITE or FIXED vs. ANY collisions, only the "weak" entity moves, 2063 | // while the other one stays fixed. In ACTIVE vs. ACTIVE and ACTIVE vs. PASSIVE 2064 | // collisions, both entities are moved. LITE or PASSIVE entities don't collide 2065 | // with other LITE or PASSIVE entities at all. The behaiviour for FIXED vs. 2066 | // FIXED collisions is undefined. 2067 | 2068 | ig.Entity.COLLIDES = { 2069 | NEVER: 0, 2070 | LITE: 1, 2071 | PASSIVE: 2, 2072 | ACTIVE: 4, 2073 | FIXED: 8 2074 | }; 2075 | 2076 | // Entity Types - used for checks 2077 | 2078 | ig.Entity.TYPE = { 2079 | NONE: 0, 2080 | A: 1, 2081 | B: 2, 2082 | BOTH: 3 2083 | }; 2084 | 2085 | ig.Entity.checkPair = function (a, b) { 2086 | 2087 | // Do these entities want checks? 2088 | if (a.checkAgainst & b.type) { 2089 | a.check(b); 2090 | } 2091 | 2092 | if (b.checkAgainst & a.type) { 2093 | b.check(a); 2094 | } 2095 | 2096 | // If this pair allows collision, solve it! At least one entity must 2097 | // collide ACTIVE or FIXED, while the other one must not collide NEVER. 2098 | if (a.collides && b.collides && a.collides + b.collides > ig.Entity.COLLIDES.ACTIVE) { 2099 | ig.Entity.solveCollision(a, b); 2100 | } 2101 | }; 2102 | 2103 | ig.Entity.solveCollision = function (a, b) { 2104 | 2105 | // If one entity is FIXED, or the other entity is LITE, the weak 2106 | // (FIXED/NON-LITE) entity won't move in collision response 2107 | var weak = null; 2108 | if (a.collides == ig.Entity.COLLIDES.LITE || b.collides == ig.Entity.COLLIDES.FIXED) { 2109 | weak = a; 2110 | } else if (b.collides == ig.Entity.COLLIDES.LITE || a.collides == ig.Entity.COLLIDES.FIXED) { 2111 | weak = b; 2112 | } 2113 | 2114 | // Did they already overlap on the X-axis in the last frame? If so, 2115 | // this must be a vertical collision! 2116 | if (a.last.x + a.size.x > b.last.x && a.last.x < b.last.x + b.size.x) { 2117 | // Which one is on top? 2118 | if (a.last.y < b.last.y) { 2119 | ig.Entity.seperateOnYAxis(a, b, weak); 2120 | } else { 2121 | ig.Entity.seperateOnYAxis(b, a, weak); 2122 | } 2123 | a.collideWith(b, 'y'); 2124 | b.collideWith(a, 'y'); 2125 | } 2126 | 2127 | // Horizontal collision 2128 | else if (a.last.y + a.size.y > b.last.y && a.last.y < b.last.y + b.size.y) { 2129 | // Which one is on the left? 2130 | if (a.last.x < b.last.x) { 2131 | ig.Entity.seperateOnXAxis(a, b, weak); 2132 | } else { 2133 | ig.Entity.seperateOnXAxis(b, a, weak); 2134 | } 2135 | a.collideWith(b, 'x'); 2136 | b.collideWith(a, 'x'); 2137 | } 2138 | }; 2139 | 2140 | // FIXME: This is a mess. Instead of doing all the movements here, the entities 2141 | // should get notified of the collision (with all details) and resolve it 2142 | // themselfs. 2143 | 2144 | ig.Entity.seperateOnXAxis = function (left, right, weak) { 2145 | var nudge = left.pos.x + left.size.x - right.pos.x; 2146 | 2147 | // We have a weak entity, so just move this one 2148 | if (weak) { 2149 | var strong = left === weak ? right : left; 2150 | weak.vel.x = -weak.vel.x * weak.bounciness + strong.vel.x; 2151 | 2152 | var resWeak = ig.game.collisionMap.trace(weak.pos.x, weak.pos.y, weak == left ? -nudge : nudge, 0, weak.size.x, weak.size.y); 2153 | weak.pos.x = resWeak.pos.x; 2154 | } 2155 | 2156 | // Normal collision - both move 2157 | else { 2158 | var v2 = (left.vel.x - right.vel.x) / 2; 2159 | left.vel.x = -v2; 2160 | right.vel.x = v2; 2161 | 2162 | var resLeft = ig.game.collisionMap.trace(left.pos.x, left.pos.y, -nudge / 2, 0, left.size.x, left.size.y); 2163 | left.pos.x = Math.floor(resLeft.pos.x); 2164 | 2165 | var resRight = ig.game.collisionMap.trace(right.pos.x, right.pos.y, nudge / 2, 0, right.size.x, right.size.y); 2166 | right.pos.x = Math.ceil(resRight.pos.x); 2167 | } 2168 | }; 2169 | 2170 | ig.Entity.seperateOnYAxis = function (top, bottom, weak) { 2171 | var nudge = top.pos.y + top.size.y - bottom.pos.y; 2172 | 2173 | // We have a weak entity, so just move this one 2174 | if (weak) { 2175 | var strong = top === weak ? bottom : top; 2176 | weak.vel.y = -weak.vel.y * weak.bounciness + strong.vel.y; 2177 | 2178 | // Riding on a platform? 2179 | var nudgeX = 0; 2180 | if (weak == top && Math.abs(weak.vel.y - strong.vel.y) < weak.minBounceVelocity) { 2181 | weak.standing = true; 2182 | nudgeX = strong.vel.x * ig.system.tick; 2183 | } 2184 | 2185 | var resWeak = ig.game.collisionMap.trace(weak.pos.x, weak.pos.y, nudgeX, weak == top ? -nudge : nudge, weak.size.x, weak.size.y); 2186 | weak.pos.y = resWeak.pos.y; 2187 | weak.pos.x = resWeak.pos.x; 2188 | } 2189 | 2190 | // Bottom entity is standing - just bounce the top one 2191 | else if (ig.game.gravity && (bottom.standing || top.vel.y > 0)) { 2192 | var resTop = ig.game.collisionMap.trace(top.pos.x, top.pos.y, 0, -(top.pos.y + top.size.y - bottom.pos.y), top.size.x, top.size.y); 2193 | top.pos.y = resTop.pos.y; 2194 | 2195 | if (top.bounciness > 0 && top.vel.y > top.minBounceVelocity) { 2196 | top.vel.y *= -top.bounciness; 2197 | } else { 2198 | top.standing = true; 2199 | top.vel.y = 0; 2200 | } 2201 | } 2202 | 2203 | // Normal collision - both move 2204 | else { 2205 | var v2 = (top.vel.y - bottom.vel.y) / 2; 2206 | top.vel.y = -v2; 2207 | bottom.vel.y = v2; 2208 | 2209 | var nudgeX = bottom.vel.x * ig.system.tick; 2210 | var resTop = ig.game.collisionMap.trace(top.pos.x, top.pos.y, nudgeX, -nudge / 2, top.size.x, top.size.y); 2211 | top.pos.y = resTop.pos.y; 2212 | 2213 | var resBottom = ig.game.collisionMap.trace(bottom.pos.x, bottom.pos.y, 0, nudge / 2, bottom.size.x, bottom.size.y); 2214 | bottom.pos.y = resBottom.pos.y; 2215 | } 2216 | }; 2217 | }); 2218 | }.call(window)); 2219 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(/*! ig */ 1))) 2220 | 2221 | /***/ }, 2222 | /* 15 */ 2223 | /*!****************************!*\ 2224 | !*** ./lib/impact/font.js ***! 2225 | \****************************/ 2226 | /***/ function(module, exports, __webpack_require__) { 2227 | 2228 | /* WEBPACK VAR INJECTION */(function(ig) {/*** IMPORTS FROM imports-loader ***/ 2229 | (function() { 2230 | 2231 | 'use strict'; 2232 | 2233 | ig.module('impact.font').requires('impact.image').defines(function () { 2234 | "use strict"; 2235 | 2236 | ig.Font = ig.Image.extend({ 2237 | widthMap: [], 2238 | indices: [], 2239 | firstChar: 32, 2240 | alpha: 1, 2241 | letterSpacing: 1, 2242 | lineSpacing: 0, 2243 | 2244 | onload: function onload(ev) { 2245 | this._loadMetrics(this.data); 2246 | this.parent(ev); 2247 | }, 2248 | 2249 | widthForString: function widthForString(text) { 2250 | // Multiline? 2251 | if (text.indexOf('\n') !== -1) { 2252 | var lines = text.split('\n'); 2253 | var width = 0; 2254 | for (var i = 0; i < lines.length; i++) { 2255 | width = Math.max(width, this._widthForLine(lines[i])); 2256 | } 2257 | return width; 2258 | } else { 2259 | return this._widthForLine(text); 2260 | } 2261 | }, 2262 | 2263 | _widthForLine: function _widthForLine(text) { 2264 | var width = 0; 2265 | for (var i = 0; i < text.length; i++) { 2266 | width += this.widthMap[text.charCodeAt(i) - this.firstChar] + this.letterSpacing; 2267 | } 2268 | return width; 2269 | }, 2270 | 2271 | heightForString: function heightForString(text) { 2272 | return text.split('\n').length * (this.height + this.lineSpacing); 2273 | }, 2274 | 2275 | draw: function draw(text, x, y, align) { 2276 | if (typeof text != 'string') { 2277 | text = text.toString(); 2278 | } 2279 | 2280 | // Multiline? 2281 | if (text.indexOf('\n') !== -1) { 2282 | var lines = text.split('\n'); 2283 | var lineHeight = this.height + this.lineSpacing; 2284 | for (var i = 0; i < lines.length; i++) { 2285 | this.draw(lines[i], x, y + i * lineHeight, align); 2286 | } 2287 | return; 2288 | } 2289 | 2290 | if (align == ig.Font.ALIGN.RIGHT || align == ig.Font.ALIGN.CENTER) { 2291 | var width = this._widthForLine(text); 2292 | x -= align == ig.Font.ALIGN.CENTER ? width / 2 : width; 2293 | } 2294 | 2295 | if (this.alpha !== 1) { 2296 | ig.system.context.globalAlpha = this.alpha; 2297 | } 2298 | 2299 | for (var i = 0; i < text.length; i++) { 2300 | var c = text.charCodeAt(i); 2301 | x += this._drawChar(c - this.firstChar, x, y); 2302 | } 2303 | 2304 | if (this.alpha !== 1) { 2305 | ig.system.context.globalAlpha = 1; 2306 | } 2307 | ig.Image.drawCount += text.length; 2308 | }, 2309 | 2310 | _drawChar: function _drawChar(c, targetX, targetY) { 2311 | if (!this.loaded || c < 0 || c >= this.indices.length) { 2312 | return 0; 2313 | } 2314 | 2315 | var scale = ig.system.scale; 2316 | 2317 | var charX = this.indices[c] * scale; 2318 | var charY = 0; 2319 | var charWidth = this.widthMap[c] * scale; 2320 | var charHeight = (this.height - 2) * scale; 2321 | 2322 | ig.system.context.drawImage(this.data, charX, charY, charWidth, charHeight, ig.system.getDrawPos(targetX), ig.system.getDrawPos(targetY), charWidth, charHeight); 2323 | 2324 | return this.widthMap[c] + this.letterSpacing; 2325 | }, 2326 | 2327 | _loadMetrics: function _loadMetrics(image) { 2328 | // Draw the bottommost line of this font image into an offscreen canvas 2329 | // and analyze it pixel by pixel. 2330 | // A run of non-transparent pixels represents a character and its width 2331 | 2332 | this.height = image.height - 1; 2333 | this.widthMap = []; 2334 | this.indices = []; 2335 | 2336 | var px = ig.getImagePixels(image, 0, image.height - 1, image.width, 1); 2337 | 2338 | var currentChar = 0; 2339 | var currentWidth = 0; 2340 | for (var x = 0; x < image.width; x++) { 2341 | var index = x * 4 + 3; // alpha component of this pixel 2342 | if (px.data[index] > 127) { 2343 | currentWidth++; 2344 | } else if (px.data[index] < 128 && currentWidth) { 2345 | this.widthMap.push(currentWidth); 2346 | this.indices.push(x - currentWidth); 2347 | currentChar++; 2348 | currentWidth = 0; 2349 | } 2350 | } 2351 | this.widthMap.push(currentWidth); 2352 | this.indices.push(x - currentWidth); 2353 | } 2354 | }); 2355 | 2356 | ig.Font.ALIGN = { 2357 | LEFT: 0, 2358 | RIGHT: 1, 2359 | CENTER: 2 2360 | }; 2361 | }); 2362 | }.call(window)); 2363 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(/*! ig */ 1))) 2364 | 2365 | /***/ }, 2366 | /* 16 */ 2367 | /*!****************************!*\ 2368 | !*** ./lib/impact/game.js ***! 2369 | \****************************/ 2370 | /***/ function(module, exports, __webpack_require__) { 2371 | 2372 | /* WEBPACK VAR INJECTION */(function(ig) {/*** IMPORTS FROM imports-loader ***/ 2373 | (function() { 2374 | 2375 | 'use strict'; 2376 | 2377 | ig.module('impact.game').requires('impact.impact', 'impact.entity', 'impact.collision-map', 'impact.background-map').defines(function () { 2378 | "use strict"; 2379 | 2380 | ig.Game = ig.Class.extend({ 2381 | 2382 | clearColor: '#000000', 2383 | gravity: 0, 2384 | screen: { x: 0, y: 0 }, 2385 | _rscreen: { x: 0, y: 0 }, 2386 | 2387 | entities: [], 2388 | 2389 | namedEntities: {}, 2390 | collisionMap: ig.CollisionMap.staticNoCollision, 2391 | backgroundMaps: [], 2392 | backgroundAnims: {}, 2393 | 2394 | autoSort: false, 2395 | sortBy: null, 2396 | 2397 | cellSize: 64, 2398 | 2399 | _deferredKill: [], 2400 | _levelToLoad: null, 2401 | _doSortEntities: false, 2402 | 2403 | staticInstantiate: function staticInstantiate() { 2404 | this.sortBy = this.sortBy || ig.Game.SORT.Z_INDEX; 2405 | ig.game = this; 2406 | return null; 2407 | }, 2408 | 2409 | loadLevel: function loadLevel(data) { 2410 | this.screen = { x: 0, y: 0 }; 2411 | 2412 | // Entities 2413 | this.entities = []; 2414 | this.namedEntities = {}; 2415 | for (var i = 0; i < data.entities.length; i++) { 2416 | var ent = data.entities[i]; 2417 | this.spawnEntity(ent.type, ent.x, ent.y, ent.settings); 2418 | } 2419 | this.sortEntities(); 2420 | 2421 | // Map Layer 2422 | this.collisionMap = ig.CollisionMap.staticNoCollision; 2423 | this.backgroundMaps = []; 2424 | for (var i = 0; i < data.layer.length; i++) { 2425 | var ld = data.layer[i]; 2426 | if (ld.name == 'collision') { 2427 | this.collisionMap = new ig.CollisionMap(ld.tilesize, ld.data); 2428 | } else { 2429 | var newMap = new ig.BackgroundMap(ld.tilesize, ld.data, ld.tilesetName); 2430 | newMap.anims = this.backgroundAnims[ld.tilesetName] || {}; 2431 | newMap.repeat = ld.repeat; 2432 | newMap.distance = ld.distance; 2433 | newMap.foreground = !!ld.foreground; 2434 | newMap.preRender = !!ld.preRender; 2435 | newMap.name = ld.name; 2436 | this.backgroundMaps.push(newMap); 2437 | } 2438 | } 2439 | 2440 | // Call post-init ready function on all entities 2441 | for (var i = 0; i < this.entities.length; i++) { 2442 | this.entities[i].ready(); 2443 | } 2444 | }, 2445 | 2446 | loadLevelDeferred: function loadLevelDeferred(data) { 2447 | this._levelToLoad = data; 2448 | }, 2449 | 2450 | getMapByName: function getMapByName(name) { 2451 | if (name == 'collision') { 2452 | return this.collisionMap; 2453 | } 2454 | 2455 | for (var i = 0; i < this.backgroundMaps.length; i++) { 2456 | if (this.backgroundMaps[i].name == name) { 2457 | return this.backgroundMaps[i]; 2458 | } 2459 | } 2460 | 2461 | return null; 2462 | }, 2463 | 2464 | getEntityByName: function getEntityByName(name) { 2465 | return this.namedEntities[name]; 2466 | }, 2467 | 2468 | getEntitiesByType: function getEntitiesByType(type) { 2469 | var entityClass = typeof type === 'string' ? ig.global[type] : type; 2470 | 2471 | var a = []; 2472 | for (var i = 0; i < this.entities.length; i++) { 2473 | var ent = this.entities[i]; 2474 | if (ent instanceof entityClass && !ent._killed) { 2475 | a.push(ent); 2476 | } 2477 | } 2478 | return a; 2479 | }, 2480 | 2481 | spawnEntity: function spawnEntity(type, x, y, settings) { 2482 | var entityClass = typeof type === 'string' ? ig.global[type] : type; 2483 | 2484 | if (!entityClass) { 2485 | throw "Can't spawn entity of type " + type; 2486 | } 2487 | var ent = new entityClass(x, y, settings || {}); 2488 | this.entities.push(ent); 2489 | if (ent.name) { 2490 | this.namedEntities[ent.name] = ent; 2491 | } 2492 | 2493 | return ent; 2494 | }, 2495 | 2496 | sortEntities: function sortEntities() { 2497 | this.entities.sort(this.sortBy); 2498 | }, 2499 | 2500 | sortEntitiesDeferred: function sortEntitiesDeferred() { 2501 | this._doSortEntities = true; 2502 | }, 2503 | 2504 | removeEntity: function removeEntity(ent) { 2505 | // Remove this entity from the named entities 2506 | if (ent.name) { 2507 | delete this.namedEntities[ent.name]; 2508 | } 2509 | 2510 | // We can not remove the entity from the entities[] array in the midst 2511 | // of an update cycle, so remember all killed entities and remove 2512 | // them later. 2513 | // Also make sure this entity doesn't collide anymore and won't get 2514 | // updated or checked 2515 | ent._killed = true; 2516 | ent.type = ig.Entity.TYPE.NONE; 2517 | ent.checkAgainst = ig.Entity.TYPE.NONE; 2518 | ent.collides = ig.Entity.COLLIDES.NEVER; 2519 | this._deferredKill.push(ent); 2520 | }, 2521 | 2522 | run: function run() { 2523 | this.update(); 2524 | this.draw(); 2525 | }, 2526 | 2527 | update: function update() { 2528 | // load new level? 2529 | if (this._levelToLoad) { 2530 | this.loadLevel(this._levelToLoad); 2531 | this._levelToLoad = null; 2532 | } 2533 | 2534 | // update entities 2535 | this.updateEntities(); 2536 | this.checkEntities(); 2537 | 2538 | // remove all killed entities 2539 | for (var i = 0; i < this._deferredKill.length; i++) { 2540 | this._deferredKill[i].erase(); 2541 | this.entities.erase(this._deferredKill[i]); 2542 | } 2543 | this._deferredKill = []; 2544 | 2545 | // sort entities? 2546 | if (this._doSortEntities || this.autoSort) { 2547 | this.sortEntities(); 2548 | this._doSortEntities = false; 2549 | } 2550 | 2551 | // update background animations 2552 | for (var tileset in this.backgroundAnims) { 2553 | var anims = this.backgroundAnims[tileset]; 2554 | for (var a in anims) { 2555 | anims[a].update(); 2556 | } 2557 | } 2558 | }, 2559 | 2560 | updateEntities: function updateEntities() { 2561 | for (var i = 0; i < this.entities.length; i++) { 2562 | var ent = this.entities[i]; 2563 | if (!ent._killed) { 2564 | ent.update(); 2565 | } 2566 | } 2567 | }, 2568 | 2569 | draw: function draw() { 2570 | if (this.clearColor) { 2571 | ig.system.clear(this.clearColor); 2572 | } 2573 | 2574 | // This is a bit of a circle jerk. Entities reference game._rscreen 2575 | // instead of game.screen when drawing themselfs in order to be 2576 | // "synchronized" to the rounded(?) screen position 2577 | this._rscreen.x = ig.system.getDrawPos(this.screen.x) / ig.system.scale; 2578 | this._rscreen.y = ig.system.getDrawPos(this.screen.y) / ig.system.scale; 2579 | 2580 | var mapIndex; 2581 | for (mapIndex = 0; mapIndex < this.backgroundMaps.length; mapIndex++) { 2582 | var map = this.backgroundMaps[mapIndex]; 2583 | if (map.foreground) { 2584 | // All foreground layers are drawn after the entities 2585 | break; 2586 | } 2587 | map.setScreenPos(this.screen.x, this.screen.y); 2588 | map.draw(); 2589 | } 2590 | 2591 | this.drawEntities(); 2592 | 2593 | for (mapIndex; mapIndex < this.backgroundMaps.length; mapIndex++) { 2594 | var map = this.backgroundMaps[mapIndex]; 2595 | map.setScreenPos(this.screen.x, this.screen.y); 2596 | map.draw(); 2597 | } 2598 | }, 2599 | 2600 | drawEntities: function drawEntities() { 2601 | for (var i = 0; i < this.entities.length; i++) { 2602 | this.entities[i].draw(); 2603 | } 2604 | }, 2605 | 2606 | checkEntities: function checkEntities() { 2607 | // Insert all entities into a spatial hash and check them against any 2608 | // other entity that already resides in the same cell. Entities that are 2609 | // bigger than a single cell, are inserted into each one they intersect 2610 | // with. 2611 | 2612 | // A list of entities, which the current one was already checked with, 2613 | // is maintained for each entity. 2614 | 2615 | var hash = {}; 2616 | for (var e = 0; e < this.entities.length; e++) { 2617 | var entity = this.entities[e]; 2618 | 2619 | // Skip entities that don't check, don't get checked and don't collide 2620 | if (entity.type == ig.Entity.TYPE.NONE && entity.checkAgainst == ig.Entity.TYPE.NONE && entity.collides == ig.Entity.COLLIDES.NEVER) { 2621 | continue; 2622 | } 2623 | 2624 | var checked = {}, 2625 | xmin = Math.floor(entity.pos.x / this.cellSize), 2626 | ymin = Math.floor(entity.pos.y / this.cellSize), 2627 | xmax = Math.floor((entity.pos.x + entity.size.x) / this.cellSize) + 1, 2628 | ymax = Math.floor((entity.pos.y + entity.size.y) / this.cellSize) + 1; 2629 | 2630 | for (var x = xmin; x < xmax; x++) { 2631 | for (var y = ymin; y < ymax; y++) { 2632 | 2633 | // Current cell is empty - create it and insert! 2634 | if (!hash[x]) { 2635 | hash[x] = {}; 2636 | hash[x][y] = [entity]; 2637 | } else if (!hash[x][y]) { 2638 | hash[x][y] = [entity]; 2639 | } 2640 | 2641 | // Check against each entity in this cell, then insert 2642 | else { 2643 | var cell = hash[x][y]; 2644 | for (var c = 0; c < cell.length; c++) { 2645 | 2646 | // Intersects and wasn't already checkd? 2647 | if (entity.touches(cell[c]) && !checked[cell[c].id]) { 2648 | checked[cell[c].id] = true; 2649 | ig.Entity.checkPair(entity, cell[c]); 2650 | } 2651 | } 2652 | cell.push(entity); 2653 | } 2654 | } // end for y size 2655 | } // end for x size 2656 | } // end for entities 2657 | } 2658 | }); 2659 | 2660 | ig.Game.SORT = { 2661 | Z_INDEX: function Z_INDEX(a, b) { 2662 | return a.zIndex - b.zIndex; 2663 | }, 2664 | POS_X: function POS_X(a, b) { 2665 | return a.pos.x + a.size.x - (b.pos.x + b.size.x); 2666 | }, 2667 | POS_Y: function POS_Y(a, b) { 2668 | return a.pos.y + a.size.y - (b.pos.y + b.size.y); 2669 | } 2670 | }; 2671 | }); 2672 | }.call(window)); 2673 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(/*! ig */ 1))) 2674 | 2675 | /***/ }, 2676 | /* 17 */ 2677 | /*!*****************************!*\ 2678 | !*** ./lib/impact/image.js ***! 2679 | \*****************************/ 2680 | /***/ function(module, exports, __webpack_require__) { 2681 | 2682 | /* WEBPACK VAR INJECTION */(function(ig) {/*** IMPORTS FROM imports-loader ***/ 2683 | (function() { 2684 | 2685 | 'use strict'; 2686 | 2687 | ig.module('impact.image').defines(function () { 2688 | "use strict"; 2689 | 2690 | ig.Image = ig.Class.extend({ 2691 | data: null, 2692 | width: 0, 2693 | height: 0, 2694 | loaded: false, 2695 | failed: false, 2696 | loadCallback: null, 2697 | path: '', 2698 | 2699 | staticInstantiate: function staticInstantiate(path) { 2700 | return ig.Image.cache[path] || null; 2701 | }, 2702 | 2703 | init: function init(path) { 2704 | this.path = path; 2705 | this.load(); 2706 | }, 2707 | 2708 | load: function load(loadCallback) { 2709 | if (this.loaded) { 2710 | if (loadCallback) { 2711 | loadCallback(this.path, true); 2712 | } 2713 | return; 2714 | } else if (!this.loaded && ig.ready) { 2715 | this.loadCallback = loadCallback || null; 2716 | 2717 | this.data = new Image(); 2718 | this.data.onload = this.onload.bind(this); 2719 | this.data.onerror = this.onerror.bind(this); 2720 | this.data.src = ig.prefix + this.path + ig.nocache; 2721 | } else { 2722 | ig.addResource(this); 2723 | } 2724 | 2725 | ig.Image.cache[this.path] = this; 2726 | }, 2727 | 2728 | reload: function reload() { 2729 | this.loaded = false; 2730 | this.data = new Image(); 2731 | this.data.onload = this.onload.bind(this); 2732 | this.data.src = this.path + '?' + Date.now(); 2733 | }, 2734 | 2735 | onload: function onload(event) { 2736 | this.width = this.data.width; 2737 | this.height = this.data.height; 2738 | this.loaded = true; 2739 | 2740 | if (ig.system.scale != 1) { 2741 | this.resize(ig.system.scale); 2742 | } 2743 | 2744 | if (this.loadCallback) { 2745 | this.loadCallback(this.path, true); 2746 | } 2747 | }, 2748 | 2749 | onerror: function onerror(event) { 2750 | this.failed = true; 2751 | 2752 | if (this.loadCallback) { 2753 | this.loadCallback(this.path, false); 2754 | } 2755 | }, 2756 | 2757 | resize: function resize(scale) { 2758 | // Nearest-Neighbor scaling 2759 | 2760 | // The original image is drawn into an offscreen canvas of the same size 2761 | // and copied into another offscreen canvas with the new size. 2762 | // The scaled offscreen canvas becomes the image (data) of this object. 2763 | 2764 | var origPixels = ig.getImagePixels(this.data, 0, 0, this.width, this.height); 2765 | 2766 | var widthScaled = this.width * scale; 2767 | var heightScaled = this.height * scale; 2768 | 2769 | var scaled = ig.$new('canvas'); 2770 | scaled.width = widthScaled; 2771 | scaled.height = heightScaled; 2772 | var scaledCtx = scaled.getContext('2d'); 2773 | var scaledPixels = scaledCtx.getImageData(0, 0, widthScaled, heightScaled); 2774 | 2775 | for (var y = 0; y < heightScaled; y++) { 2776 | for (var x = 0; x < widthScaled; x++) { 2777 | var index = (Math.floor(y / scale) * this.width + Math.floor(x / scale)) * 4; 2778 | var indexScaled = (y * widthScaled + x) * 4; 2779 | scaledPixels.data[indexScaled] = origPixels.data[index]; 2780 | scaledPixels.data[indexScaled + 1] = origPixels.data[index + 1]; 2781 | scaledPixels.data[indexScaled + 2] = origPixels.data[index + 2]; 2782 | scaledPixels.data[indexScaled + 3] = origPixels.data[index + 3]; 2783 | } 2784 | } 2785 | scaledCtx.putImageData(scaledPixels, 0, 0); 2786 | this.data = scaled; 2787 | }, 2788 | 2789 | draw: function draw(targetX, targetY, sourceX, sourceY, width, height) { 2790 | if (!this.loaded) { 2791 | return; 2792 | } 2793 | 2794 | var scale = ig.system.scale; 2795 | sourceX = sourceX ? sourceX * scale : 0; 2796 | sourceY = sourceY ? sourceY * scale : 0; 2797 | width = (width ? width : this.width) * scale; 2798 | height = (height ? height : this.height) * scale; 2799 | 2800 | ig.system.context.drawImage(this.data, sourceX, sourceY, width, height, ig.system.getDrawPos(targetX), ig.system.getDrawPos(targetY), width, height); 2801 | 2802 | ig.Image.drawCount++; 2803 | }, 2804 | 2805 | drawTile: function drawTile(targetX, targetY, tile, tileWidth, tileHeight, flipX, flipY) { 2806 | tileHeight = tileHeight ? tileHeight : tileWidth; 2807 | 2808 | if (!this.loaded || tileWidth > this.width || tileHeight > this.height) { 2809 | return; 2810 | } 2811 | 2812 | var scale = ig.system.scale; 2813 | var tileWidthScaled = Math.floor(tileWidth * scale); 2814 | var tileHeightScaled = Math.floor(tileHeight * scale); 2815 | 2816 | var scaleX = flipX ? -1 : 1; 2817 | var scaleY = flipY ? -1 : 1; 2818 | 2819 | if (flipX || flipY) { 2820 | ig.system.context.save(); 2821 | ig.system.context.scale(scaleX, scaleY); 2822 | } 2823 | ig.system.context.drawImage(this.data, Math.floor(tile * tileWidth) % this.width * scale, Math.floor(tile * tileWidth / this.width) * tileHeight * scale, tileWidthScaled, tileHeightScaled, ig.system.getDrawPos(targetX) * scaleX - (flipX ? tileWidthScaled : 0), ig.system.getDrawPos(targetY) * scaleY - (flipY ? tileHeightScaled : 0), tileWidthScaled, tileHeightScaled); 2824 | if (flipX || flipY) { 2825 | ig.system.context.restore(); 2826 | } 2827 | 2828 | ig.Image.drawCount++; 2829 | } 2830 | }); 2831 | 2832 | ig.Image.drawCount = 0; 2833 | ig.Image.cache = {}; 2834 | ig.Image.reloadCache = function () { 2835 | for (var path in ig.Image.cache) { 2836 | ig.Image.cache[path].reload(); 2837 | } 2838 | }; 2839 | }); 2840 | }.call(window)); 2841 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(/*! ig */ 1))) 2842 | 2843 | /***/ }, 2844 | /* 18 */ 2845 | /*!******************************!*\ 2846 | !*** ./lib/impact/impact.js ***! 2847 | \******************************/ 2848 | /***/ function(module, exports, __webpack_require__) { 2849 | 2850 | /* WEBPACK VAR INJECTION */(function(ig) {/*** IMPORTS FROM imports-loader ***/ 2851 | (function() { 2852 | 2853 | 'use strict'; 2854 | 2855 | var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; }; 2856 | 2857 | // ----------------------------------------------------------------------------- 2858 | // Impact Game Engine 1.24 2859 | // http://impactjs.com/ 2860 | // ----------------------------------------------------------------------------- 2861 | 2862 | 2863 | (function (window) { 2864 | "use strict"; 2865 | 2866 | // ----------------------------------------------------------------------------- 2867 | // Native Object extensions 2868 | 2869 | Number.prototype.map = function (istart, istop, ostart, ostop) { 2870 | return ostart + (ostop - ostart) * ((this - istart) / (istop - istart)); 2871 | }; 2872 | 2873 | Number.prototype.limit = function (min, max) { 2874 | return Math.min(max, Math.max(min, this)); 2875 | }; 2876 | 2877 | Number.prototype.round = function (precision) { 2878 | precision = Math.pow(10, precision || 0); 2879 | return Math.round(this * precision) / precision; 2880 | }; 2881 | 2882 | Number.prototype.floor = function () { 2883 | return Math.floor(this); 2884 | }; 2885 | 2886 | Number.prototype.ceil = function () { 2887 | return Math.ceil(this); 2888 | }; 2889 | 2890 | Number.prototype.toInt = function () { 2891 | return this | 0; 2892 | }; 2893 | 2894 | Number.prototype.toRad = function () { 2895 | return this / 180 * Math.PI; 2896 | }; 2897 | 2898 | Number.prototype.toDeg = function () { 2899 | return this * 180 / Math.PI; 2900 | }; 2901 | 2902 | Object.defineProperty(Array.prototype, 'erase', { value: function value(item) { 2903 | for (var i = this.length; i--;) { 2904 | if (this[i] === item) { 2905 | this.splice(i, 1); 2906 | } 2907 | } 2908 | return this; 2909 | } }); 2910 | 2911 | Object.defineProperty(Array.prototype, 'random', { value: function value(item) { 2912 | return this[Math.floor(Math.random() * this.length)]; 2913 | } }); 2914 | 2915 | Function.prototype.bind = Function.prototype.bind || function (oThis) { 2916 | if (typeof this !== "function") { 2917 | throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); 2918 | } 2919 | 2920 | var aArgs = Array.prototype.slice.call(arguments, 1), 2921 | fToBind = this, 2922 | fNOP = function fNOP() {}, 2923 | fBound = function fBound() { 2924 | return fToBind.apply(this instanceof fNOP && oThis ? this : oThis, aArgs.concat(Array.prototype.slice.call(arguments))); 2925 | }; 2926 | 2927 | fNOP.prototype = this.prototype; 2928 | fBound.prototype = new fNOP(); 2929 | 2930 | return fBound; 2931 | }; 2932 | 2933 | // ----------------------------------------------------------------------------- 2934 | // ig Namespace 2935 | 2936 | window.ig = { 2937 | game: null, 2938 | debug: null, 2939 | version: '1.24', 2940 | global: window, 2941 | modules: {}, 2942 | resources: [], 2943 | ready: false, 2944 | baked: false, 2945 | nocache: '', 2946 | ua: {}, 2947 | prefix: window.ImpactPrefix || '', 2948 | lib: 'lib/', 2949 | 2950 | _current: null, 2951 | _loadQueue: [], 2952 | _waitForOnload: 0, 2953 | 2954 | $: function $(selector) { 2955 | return selector.charAt(0) == '#' ? document.getElementById(selector.substr(1)) : document.getElementsByTagName(selector); 2956 | }, 2957 | 2958 | $new: function $new(name) { 2959 | return document.createElement(name); 2960 | }, 2961 | 2962 | copy: function copy(object) { 2963 | if (!object || (typeof object === 'undefined' ? 'undefined' : _typeof(object)) != 'object' || object instanceof HTMLElement || object instanceof ig.Class) { 2964 | return object; 2965 | } else if (object instanceof Array) { 2966 | var c = []; 2967 | for (var i = 0, l = object.length; i < l; i++) { 2968 | c[i] = ig.copy(object[i]); 2969 | } 2970 | return c; 2971 | } else { 2972 | var c = {}; 2973 | for (var i in object) { 2974 | c[i] = ig.copy(object[i]); 2975 | } 2976 | return c; 2977 | } 2978 | }, 2979 | 2980 | merge: function merge(original, extended) { 2981 | for (var key in extended) { 2982 | var ext = extended[key]; 2983 | if ((typeof ext === 'undefined' ? 'undefined' : _typeof(ext)) != 'object' || ext instanceof HTMLElement || ext instanceof ig.Class || ext === null) { 2984 | original[key] = ext; 2985 | } else { 2986 | if (!original[key] || _typeof(original[key]) != 'object') { 2987 | original[key] = ext instanceof Array ? [] : {}; 2988 | } 2989 | ig.merge(original[key], ext); 2990 | } 2991 | } 2992 | return original; 2993 | }, 2994 | 2995 | ksort: function ksort(obj) { 2996 | if (!obj || (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) != 'object') { 2997 | return []; 2998 | } 2999 | 3000 | var keys = [], 3001 | values = []; 3002 | for (var i in obj) { 3003 | keys.push(i); 3004 | } 3005 | 3006 | keys.sort(); 3007 | for (var i = 0; i < keys.length; i++) { 3008 | values.push(obj[keys[i]]); 3009 | } 3010 | 3011 | return values; 3012 | }, 3013 | 3014 | // Ah, yes. I love vendor prefixes. So much fun! 3015 | setVendorAttribute: function setVendorAttribute(el, attr, val) { 3016 | var uc = attr.charAt(0).toUpperCase() + attr.substr(1); 3017 | el[attr] = el['ms' + uc] = el['moz' + uc] = el['webkit' + uc] = el['o' + uc] = val; 3018 | }, 3019 | 3020 | getVendorAttribute: function getVendorAttribute(el, attr) { 3021 | var uc = attr.charAt(0).toUpperCase() + attr.substr(1); 3022 | return el[attr] || el['ms' + uc] || el['moz' + uc] || el['webkit' + uc] || el['o' + uc]; 3023 | }, 3024 | 3025 | normalizeVendorAttribute: function normalizeVendorAttribute(el, attr) { 3026 | var prefixedVal = ig.getVendorAttribute(el, attr); 3027 | if (!el[attr] && prefixedVal) { 3028 | el[attr] = prefixedVal; 3029 | } 3030 | }, 3031 | 3032 | // This function normalizes getImageData to extract the real, actual 3033 | // pixels from an image. The naive method recently failed on retina 3034 | // devices with a backgingStoreRatio != 1 3035 | getImagePixels: function getImagePixels(image, x, y, width, height) { 3036 | var canvas = ig.$new('canvas'); 3037 | canvas.width = image.width; 3038 | canvas.height = image.height; 3039 | var ctx = canvas.getContext('2d'); 3040 | 3041 | // Try to draw pixels as accurately as possible 3042 | ig.System.SCALE.CRISP(canvas, ctx); 3043 | 3044 | var ratio = ig.getVendorAttribute(ctx, 'backingStorePixelRatio') || 1; 3045 | ig.normalizeVendorAttribute(ctx, 'getImageDataHD'); 3046 | 3047 | var realWidth = image.width / ratio, 3048 | realHeight = image.height / ratio; 3049 | 3050 | canvas.width = Math.ceil(realWidth); 3051 | canvas.height = Math.ceil(realHeight); 3052 | 3053 | ctx.drawImage(image, 0, 0, realWidth, realHeight); 3054 | 3055 | return ratio === 1 ? ctx.getImageData(x, y, width, height) : ctx.getImageDataHD(x, y, width, height); 3056 | }, 3057 | 3058 | module: function module(name) { 3059 | if (ig._current) { 3060 | throw "Module '" + ig._current.name + "' defines nothing"; 3061 | } 3062 | if (ig.modules[name] && ig.modules[name].body) { 3063 | throw "Module '" + name + "' is already defined"; 3064 | } 3065 | 3066 | ig._current = { name: name, requires: [], loaded: false, body: null }; 3067 | ig.modules[name] = ig._current; 3068 | ig._loadQueue.push(ig._current); 3069 | return ig; 3070 | }, 3071 | 3072 | requires: function requires() { 3073 | ig._current.requires = Array.prototype.slice.call(arguments); 3074 | return ig; 3075 | }, 3076 | 3077 | defines: function defines(body) { 3078 | ig._current.body = body; 3079 | ig._current = null; 3080 | ig._initDOMReady(); 3081 | }, 3082 | 3083 | addResource: function addResource(resource) { 3084 | ig.resources.push(resource); 3085 | }, 3086 | 3087 | setNocache: function setNocache(set) { 3088 | ig.nocache = set ? '?' + Date.now() : ''; 3089 | }, 3090 | 3091 | // Stubs for ig.Debug 3092 | log: function log() {}, 3093 | assert: function assert(condition, msg) {}, 3094 | show: function show(name, number) {}, 3095 | mark: function mark(msg, color) {}, 3096 | 3097 | _loadScript: function _loadScript(name, requiredFrom) { 3098 | ig.modules[name] = { name: name, requires: [], loaded: false, body: null }; 3099 | ig._waitForOnload++; 3100 | 3101 | var path = ig.prefix + ig.lib + name.replace(/\./g, '/') + '.js' + ig.nocache; 3102 | var script = ig.$new('script'); 3103 | script.type = 'text/javascript'; 3104 | script.src = path; 3105 | script.onload = function () { 3106 | ig._waitForOnload--; 3107 | ig._execModules(); 3108 | }; 3109 | script.onerror = function () { 3110 | throw 'Failed to load module ' + name + ' at ' + path + ' ' + 'required from ' + requiredFrom; 3111 | }; 3112 | ig.$('head')[0].appendChild(script); 3113 | }, 3114 | 3115 | _execModules: function _execModules() { 3116 | var modulesLoaded = false; 3117 | for (var i = 0; i < ig._loadQueue.length; i++) { 3118 | var m = ig._loadQueue[i]; 3119 | var dependenciesLoaded = true; 3120 | 3121 | for (var j = 0; j < m.requires.length; j++) { 3122 | var name = m.requires[j]; 3123 | if (!ig.modules[name]) { 3124 | dependenciesLoaded = false; 3125 | ig._loadScript(name, m.name); 3126 | } else if (!ig.modules[name].loaded) { 3127 | dependenciesLoaded = false; 3128 | } 3129 | } 3130 | 3131 | if (dependenciesLoaded && m.body) { 3132 | ig._loadQueue.splice(i, 1); 3133 | m.loaded = true; 3134 | m.body(); 3135 | modulesLoaded = true; 3136 | i--; 3137 | } 3138 | } 3139 | 3140 | if (modulesLoaded) { 3141 | ig._execModules(); 3142 | } 3143 | 3144 | // No modules executed, no more files to load but loadQueue not empty? 3145 | // Must be some unresolved dependencies! 3146 | else if (!ig.baked && ig._waitForOnload == 0 && ig._loadQueue.length != 0) { 3147 | var unresolved = []; 3148 | for (var i = 0; i < ig._loadQueue.length; i++) { 3149 | 3150 | // Which dependencies aren't loaded? 3151 | var unloaded = []; 3152 | var requires = ig._loadQueue[i].requires; 3153 | for (var j = 0; j < requires.length; j++) { 3154 | var m = ig.modules[requires[j]]; 3155 | if (!m || !m.loaded) { 3156 | unloaded.push(requires[j]); 3157 | } 3158 | } 3159 | unresolved.push(ig._loadQueue[i].name + ' (requires: ' + unloaded.join(', ') + ')'); 3160 | } 3161 | 3162 | throw "Unresolved (or circular?) dependencies. " + "Most likely there's a name/path mismatch for one of the listed modules " + "or a previous syntax error prevents a module from loading:\n" + unresolved.join('\n'); 3163 | } 3164 | }, 3165 | 3166 | _DOMReady: function _DOMReady() { 3167 | if (!ig.modules['dom.ready'].loaded) { 3168 | if (!document.body) { 3169 | return setTimeout(ig._DOMReady, 13); 3170 | } 3171 | ig.modules['dom.ready'].loaded = true; 3172 | ig._waitForOnload--; 3173 | ig._execModules(); 3174 | } 3175 | return 0; 3176 | }, 3177 | 3178 | _boot: function _boot() { 3179 | if (document.location.href.match(/\?nocache/)) { 3180 | ig.setNocache(true); 3181 | } 3182 | 3183 | // Probe user agent string 3184 | ig.ua.pixelRatio = window.devicePixelRatio || 1; 3185 | ig.ua.viewport = { 3186 | width: window.innerWidth, 3187 | height: window.innerHeight 3188 | }; 3189 | ig.ua.screen = { 3190 | width: window.screen.availWidth * ig.ua.pixelRatio, 3191 | height: window.screen.availHeight * ig.ua.pixelRatio 3192 | }; 3193 | 3194 | ig.ua.iPhone = /iPhone/i.test(navigator.userAgent); 3195 | ig.ua.iPhone4 = ig.ua.iPhone && ig.ua.pixelRatio == 2; 3196 | ig.ua.iPad = /iPad/i.test(navigator.userAgent); 3197 | ig.ua.android = /android/i.test(navigator.userAgent); 3198 | ig.ua.winPhone = /Windows Phone/i.test(navigator.userAgent); 3199 | ig.ua.iOS = ig.ua.iPhone || ig.ua.iPad; 3200 | ig.ua.mobile = ig.ua.iOS || ig.ua.android || ig.ua.winPhone || /mobile/i.test(navigator.userAgent); 3201 | ig.ua.touchDevice = 'ontouchstart' in window || window.navigator.msMaxTouchPoints; 3202 | }, 3203 | 3204 | _initDOMReady: function _initDOMReady() { 3205 | if (ig.modules['dom.ready']) { 3206 | ig._execModules(); 3207 | return; 3208 | } 3209 | 3210 | ig._boot(); 3211 | 3212 | ig.modules['dom.ready'] = { requires: [], loaded: false, body: null }; 3213 | ig._waitForOnload++; 3214 | if (document.readyState === 'complete') { 3215 | ig._DOMReady(); 3216 | } else { 3217 | document.addEventListener('DOMContentLoaded', ig._DOMReady, false); 3218 | window.addEventListener('load', ig._DOMReady, false); 3219 | } 3220 | } 3221 | }; 3222 | 3223 | // ----------------------------------------------------------------------------- 3224 | // Provide ig.setAnimation and ig.clearAnimation as a compatible way to use 3225 | // requestAnimationFrame if available or setInterval otherwise 3226 | 3227 | // Use requestAnimationFrame if available 3228 | ig.normalizeVendorAttribute(window, 'requestAnimationFrame'); 3229 | if (window.requestAnimationFrame) { 3230 | var next = 1, 3231 | anims = {}; 3232 | 3233 | window.ig.setAnimation = function (callback, element) { 3234 | var current = next++; 3235 | anims[current] = true; 3236 | 3237 | var animate = function animate() { 3238 | if (!anims[current]) { 3239 | return; 3240 | } // deleted? 3241 | window.requestAnimationFrame(animate, element); 3242 | callback(); 3243 | }; 3244 | window.requestAnimationFrame(animate, element); 3245 | return current; 3246 | }; 3247 | 3248 | window.ig.clearAnimation = function (id) { 3249 | delete anims[id]; 3250 | }; 3251 | } 3252 | 3253 | // [set/clear]Interval fallback 3254 | else { 3255 | window.ig.setAnimation = function (callback, element) { 3256 | return window.setInterval(callback, 1000 / 60); 3257 | }; 3258 | window.ig.clearAnimation = function (id) { 3259 | window.clearInterval(id); 3260 | }; 3261 | } 3262 | 3263 | // ----------------------------------------------------------------------------- 3264 | // Class object based on John Resigs code; inspired by base2 and Prototype 3265 | // http://ejohn.org/blog/simple-javascript-inheritance/ 3266 | 3267 | var initializing = false, 3268 | fnTest = /xyz/.test(function () { 3269 | xyz; 3270 | }) ? /\bparent\b/ : /.*/; 3271 | var lastClassId = 0; 3272 | 3273 | window.ig.Class = function () {}; 3274 | var inject = function inject(prop) { 3275 | var proto = this.prototype; 3276 | var parent = {}; 3277 | for (var name in prop) { 3278 | if (typeof prop[name] == "function" && typeof proto[name] == "function" && fnTest.test(prop[name])) { 3279 | parent[name] = proto[name]; // save original function 3280 | proto[name] = function (name, fn) { 3281 | return function () { 3282 | var tmp = this.parent; 3283 | this.parent = parent[name]; 3284 | var ret = fn.apply(this, arguments); 3285 | this.parent = tmp; 3286 | return ret; 3287 | }; 3288 | }(name, prop[name]); 3289 | } else { 3290 | proto[name] = prop[name]; 3291 | } 3292 | } 3293 | }; 3294 | 3295 | window.ig.Class.extend = function (prop) { 3296 | var parent = this.prototype; 3297 | 3298 | initializing = true; 3299 | var prototype = new this(); 3300 | initializing = false; 3301 | 3302 | for (var name in prop) { 3303 | if (typeof prop[name] == "function" && typeof parent[name] == "function" && fnTest.test(prop[name])) { 3304 | prototype[name] = function (name, fn) { 3305 | return function () { 3306 | var tmp = this.parent; 3307 | this.parent = parent[name]; 3308 | var ret = fn.apply(this, arguments); 3309 | this.parent = tmp; 3310 | return ret; 3311 | }; 3312 | }(name, prop[name]); 3313 | } else { 3314 | prototype[name] = prop[name]; 3315 | } 3316 | } 3317 | 3318 | function Class() { 3319 | if (!initializing) { 3320 | 3321 | // If this class has a staticInstantiate method, invoke it 3322 | // and check if we got something back. If not, the normal 3323 | // constructor (init) is called. 3324 | if (this.staticInstantiate) { 3325 | var obj = this.staticInstantiate.apply(this, arguments); 3326 | if (obj) { 3327 | return obj; 3328 | } 3329 | } 3330 | for (var p in this) { 3331 | if (_typeof(this[p]) == 'object') { 3332 | this[p] = ig.copy(this[p]); // deep copy! 3333 | } 3334 | } 3335 | if (this.init) { 3336 | this.init.apply(this, arguments); 3337 | } 3338 | } 3339 | return this; 3340 | } 3341 | 3342 | Class.prototype = prototype; 3343 | Class.prototype.constructor = Class; 3344 | Class.extend = window.ig.Class.extend; 3345 | Class.inject = inject; 3346 | Class.classId = prototype.classId = ++lastClassId; 3347 | 3348 | return Class; 3349 | }; 3350 | 3351 | // Merge the ImpactMixin - if present - into the 'ig' namespace. This gives other 3352 | // code the chance to modify 'ig' before it's doing any work. 3353 | if (window.ImpactMixin) { 3354 | ig.merge(ig, window.ImpactMixin); 3355 | } 3356 | })(window); 3357 | 3358 | // ----------------------------------------------------------------------------- 3359 | // The main() function creates the system, input, sound and game objects, 3360 | // creates a preloader and starts the run loop 3361 | 3362 | ig.module('impact.impact').requires('dom.ready', 'impact.loader', 'impact.system', 'impact.input', 'impact.sound').defines(function () { 3363 | "use strict"; 3364 | 3365 | ig.main = function (canvasId, gameClass, fps, width, height, scale, loaderClass) { 3366 | ig.system = new ig.System(canvasId, fps, width, height, scale || 1); 3367 | ig.input = new ig.Input(); 3368 | ig.soundManager = new ig.SoundManager(); 3369 | ig.music = new ig.Music(); 3370 | ig.ready = true; 3371 | 3372 | var loader = new (loaderClass || ig.Loader)(gameClass, ig.resources); 3373 | loader.load(); 3374 | }; 3375 | }); 3376 | }.call(window)); 3377 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(/*! ig */ 1))) 3378 | 3379 | /***/ }, 3380 | /* 19 */ 3381 | /*!*****************************!*\ 3382 | !*** ./lib/impact/input.js ***! 3383 | \*****************************/ 3384 | /***/ function(module, exports, __webpack_require__) { 3385 | 3386 | /* WEBPACK VAR INJECTION */(function(ig) {/*** IMPORTS FROM imports-loader ***/ 3387 | (function() { 3388 | 3389 | 'use strict'; 3390 | 3391 | ig.module('impact.input').defines(function () { 3392 | "use strict"; 3393 | 3394 | ig.KEY = { 3395 | 'MOUSE1': -1, 3396 | 'MOUSE2': -3, 3397 | 'MWHEEL_UP': -4, 3398 | 'MWHEEL_DOWN': -5, 3399 | 3400 | 'BACKSPACE': 8, 3401 | 'TAB': 9, 3402 | 'ENTER': 13, 3403 | 'PAUSE': 19, 3404 | 'CAPS': 20, 3405 | 'ESC': 27, 3406 | 'SPACE': 32, 3407 | 'PAGE_UP': 33, 3408 | 'PAGE_DOWN': 34, 3409 | 'END': 35, 3410 | 'HOME': 36, 3411 | 'LEFT_ARROW': 37, 3412 | 'UP_ARROW': 38, 3413 | 'RIGHT_ARROW': 39, 3414 | 'DOWN_ARROW': 40, 3415 | 'INSERT': 45, 3416 | 'DELETE': 46, 3417 | '_0': 48, 3418 | '_1': 49, 3419 | '_2': 50, 3420 | '_3': 51, 3421 | '_4': 52, 3422 | '_5': 53, 3423 | '_6': 54, 3424 | '_7': 55, 3425 | '_8': 56, 3426 | '_9': 57, 3427 | 'A': 65, 3428 | 'B': 66, 3429 | 'C': 67, 3430 | 'D': 68, 3431 | 'E': 69, 3432 | 'F': 70, 3433 | 'G': 71, 3434 | 'H': 72, 3435 | 'I': 73, 3436 | 'J': 74, 3437 | 'K': 75, 3438 | 'L': 76, 3439 | 'M': 77, 3440 | 'N': 78, 3441 | 'O': 79, 3442 | 'P': 80, 3443 | 'Q': 81, 3444 | 'R': 82, 3445 | 'S': 83, 3446 | 'T': 84, 3447 | 'U': 85, 3448 | 'V': 86, 3449 | 'W': 87, 3450 | 'X': 88, 3451 | 'Y': 89, 3452 | 'Z': 90, 3453 | 'NUMPAD_0': 96, 3454 | 'NUMPAD_1': 97, 3455 | 'NUMPAD_2': 98, 3456 | 'NUMPAD_3': 99, 3457 | 'NUMPAD_4': 100, 3458 | 'NUMPAD_5': 101, 3459 | 'NUMPAD_6': 102, 3460 | 'NUMPAD_7': 103, 3461 | 'NUMPAD_8': 104, 3462 | 'NUMPAD_9': 105, 3463 | 'MULTIPLY': 106, 3464 | 'ADD': 107, 3465 | 'SUBSTRACT': 109, 3466 | 'DECIMAL': 110, 3467 | 'DIVIDE': 111, 3468 | 'F1': 112, 3469 | 'F2': 113, 3470 | 'F3': 114, 3471 | 'F4': 115, 3472 | 'F5': 116, 3473 | 'F6': 117, 3474 | 'F7': 118, 3475 | 'F8': 119, 3476 | 'F9': 120, 3477 | 'F10': 121, 3478 | 'F11': 122, 3479 | 'F12': 123, 3480 | 'SHIFT': 16, 3481 | 'CTRL': 17, 3482 | 'ALT': 18, 3483 | 'PLUS': 187, 3484 | 'COMMA': 188, 3485 | 'MINUS': 189, 3486 | 'PERIOD': 190 3487 | }; 3488 | 3489 | ig.Input = ig.Class.extend({ 3490 | bindings: {}, 3491 | actions: {}, 3492 | presses: {}, 3493 | locks: {}, 3494 | delayedKeyup: {}, 3495 | 3496 | isUsingMouse: false, 3497 | isUsingKeyboard: false, 3498 | isUsingAccelerometer: false, 3499 | mouse: { x: 0, y: 0 }, 3500 | accel: { x: 0, y: 0, z: 0 }, 3501 | 3502 | initMouse: function initMouse() { 3503 | if (this.isUsingMouse) { 3504 | return; 3505 | } 3506 | this.isUsingMouse = true; 3507 | var mouseWheelBound = this.mousewheel.bind(this); 3508 | ig.system.canvas.addEventListener('mousewheel', mouseWheelBound, false); 3509 | ig.system.canvas.addEventListener('DOMMouseScroll', mouseWheelBound, false); 3510 | 3511 | ig.system.canvas.addEventListener('contextmenu', this.contextmenu.bind(this), false); 3512 | ig.system.canvas.addEventListener('mousedown', this.keydown.bind(this), false); 3513 | ig.system.canvas.addEventListener('mouseup', this.keyup.bind(this), false); 3514 | ig.system.canvas.addEventListener('mousemove', this.mousemove.bind(this), false); 3515 | 3516 | if (ig.ua.touchDevice) { 3517 | // Standard 3518 | ig.system.canvas.addEventListener('touchstart', this.keydown.bind(this), false); 3519 | ig.system.canvas.addEventListener('touchend', this.keyup.bind(this), false); 3520 | ig.system.canvas.addEventListener('touchmove', this.mousemove.bind(this), false); 3521 | 3522 | // MS 3523 | ig.system.canvas.addEventListener('MSPointerDown', this.keydown.bind(this), false); 3524 | ig.system.canvas.addEventListener('MSPointerUp', this.keyup.bind(this), false); 3525 | ig.system.canvas.addEventListener('MSPointerMove', this.mousemove.bind(this), false); 3526 | ig.system.canvas.style.msTouchAction = 'none'; 3527 | } 3528 | }, 3529 | 3530 | initKeyboard: function initKeyboard() { 3531 | if (this.isUsingKeyboard) { 3532 | return; 3533 | } 3534 | this.isUsingKeyboard = true; 3535 | window.addEventListener('keydown', this.keydown.bind(this), false); 3536 | window.addEventListener('keyup', this.keyup.bind(this), false); 3537 | }, 3538 | 3539 | initAccelerometer: function initAccelerometer() { 3540 | if (this.isUsingAccelerometer) { 3541 | return; 3542 | } 3543 | this.isUsingAccelerometer = true; 3544 | window.addEventListener('devicemotion', this.devicemotion.bind(this), false); 3545 | }, 3546 | 3547 | mousewheel: function mousewheel(event) { 3548 | var delta = event.wheelDelta ? event.wheelDelta : event.detail * -1; 3549 | var code = delta > 0 ? ig.KEY.MWHEEL_UP : ig.KEY.MWHEEL_DOWN; 3550 | var action = this.bindings[code]; 3551 | if (action) { 3552 | this.actions[action] = true; 3553 | this.presses[action] = true; 3554 | this.delayedKeyup[action] = true; 3555 | event.stopPropagation(); 3556 | event.preventDefault(); 3557 | } 3558 | }, 3559 | 3560 | mousemove: function mousemove(event) { 3561 | var internalWidth = parseInt(ig.system.canvas.offsetWidth) || ig.system.realWidth; 3562 | var scale = ig.system.scale * (internalWidth / ig.system.realWidth); 3563 | 3564 | var pos = { left: 0, top: 0 }; 3565 | if (ig.system.canvas.getBoundingClientRect) { 3566 | pos = ig.system.canvas.getBoundingClientRect(); 3567 | } 3568 | 3569 | var ev = event.touches ? event.touches[0] : event; 3570 | this.mouse.x = (ev.clientX - pos.left) / scale; 3571 | this.mouse.y = (ev.clientY - pos.top) / scale; 3572 | }, 3573 | 3574 | contextmenu: function contextmenu(event) { 3575 | if (this.bindings[ig.KEY.MOUSE2]) { 3576 | event.stopPropagation(); 3577 | event.preventDefault(); 3578 | } 3579 | }, 3580 | 3581 | keydown: function keydown(event) { 3582 | var tag = event.target.tagName; 3583 | if (tag == 'INPUT' || tag == 'TEXTAREA') { 3584 | return; 3585 | } 3586 | 3587 | var code = event.type == 'keydown' ? event.keyCode : event.button == 2 ? ig.KEY.MOUSE2 : ig.KEY.MOUSE1; 3588 | 3589 | // Focus window element for mouse clicks. Prevents issues when 3590 | // running the game in an iframe. 3591 | if (code < 0 && !ig.ua.mobile) { 3592 | window.focus(); 3593 | } 3594 | 3595 | if (event.type == 'touchstart' || event.type == 'mousedown') { 3596 | this.mousemove(event); 3597 | } 3598 | 3599 | var action = this.bindings[code]; 3600 | if (action) { 3601 | this.actions[action] = true; 3602 | if (!this.locks[action]) { 3603 | this.presses[action] = true; 3604 | this.locks[action] = true; 3605 | } 3606 | event.preventDefault(); 3607 | } 3608 | }, 3609 | 3610 | keyup: function keyup(event) { 3611 | var tag = event.target.tagName; 3612 | if (tag == 'INPUT' || tag == 'TEXTAREA') { 3613 | return; 3614 | } 3615 | 3616 | var code = event.type == 'keyup' ? event.keyCode : event.button == 2 ? ig.KEY.MOUSE2 : ig.KEY.MOUSE1; 3617 | 3618 | var action = this.bindings[code]; 3619 | if (action) { 3620 | this.delayedKeyup[action] = true; 3621 | event.preventDefault(); 3622 | } 3623 | }, 3624 | 3625 | devicemotion: function devicemotion(event) { 3626 | this.accel = event.accelerationIncludingGravity; 3627 | }, 3628 | 3629 | bind: function bind(key, action) { 3630 | if (key < 0) { 3631 | this.initMouse(); 3632 | } else if (key > 0) { 3633 | this.initKeyboard(); 3634 | } 3635 | this.bindings[key] = action; 3636 | }, 3637 | 3638 | bindTouch: function bindTouch(selector, action) { 3639 | var element = ig.$(selector); 3640 | 3641 | var that = this; 3642 | element.addEventListener('touchstart', function (ev) { 3643 | that.touchStart(ev, action); 3644 | }, false); 3645 | element.addEventListener('touchend', function (ev) { 3646 | that.touchEnd(ev, action); 3647 | }, false); 3648 | element.addEventListener('MSPointerDown', function (ev) { 3649 | that.touchStart(ev, action); 3650 | }, false); 3651 | element.addEventListener('MSPointerUp', function (ev) { 3652 | that.touchEnd(ev, action); 3653 | }, false); 3654 | }, 3655 | 3656 | unbind: function unbind(key) { 3657 | var action = this.bindings[key]; 3658 | this.delayedKeyup[action] = true; 3659 | 3660 | this.bindings[key] = null; 3661 | }, 3662 | 3663 | unbindAll: function unbindAll() { 3664 | this.bindings = {}; 3665 | this.actions = {}; 3666 | this.presses = {}; 3667 | this.locks = {}; 3668 | this.delayedKeyup = {}; 3669 | }, 3670 | 3671 | state: function state(action) { 3672 | return this.actions[action]; 3673 | }, 3674 | 3675 | pressed: function pressed(action) { 3676 | return this.presses[action]; 3677 | }, 3678 | 3679 | released: function released(action) { 3680 | return !!this.delayedKeyup[action]; 3681 | }, 3682 | 3683 | clearPressed: function clearPressed() { 3684 | for (var action in this.delayedKeyup) { 3685 | this.actions[action] = false; 3686 | this.locks[action] = false; 3687 | } 3688 | this.delayedKeyup = {}; 3689 | this.presses = {}; 3690 | }, 3691 | 3692 | touchStart: function touchStart(event, action) { 3693 | this.actions[action] = true; 3694 | this.presses[action] = true; 3695 | 3696 | event.stopPropagation(); 3697 | event.preventDefault(); 3698 | return false; 3699 | }, 3700 | 3701 | touchEnd: function touchEnd(event, action) { 3702 | this.delayedKeyup[action] = true; 3703 | event.stopPropagation(); 3704 | event.preventDefault(); 3705 | return false; 3706 | } 3707 | }); 3708 | }); 3709 | }.call(window)); 3710 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(/*! ig */ 1))) 3711 | 3712 | /***/ }, 3713 | /* 20 */ 3714 | /*!******************************!*\ 3715 | !*** ./lib/impact/loader.js ***! 3716 | \******************************/ 3717 | /***/ function(module, exports, __webpack_require__) { 3718 | 3719 | /* WEBPACK VAR INJECTION */(function(ig) {/*** IMPORTS FROM imports-loader ***/ 3720 | (function() { 3721 | 3722 | 'use strict'; 3723 | 3724 | ig.module('impact.loader').requires('impact.image', 'impact.font', 'impact.sound').defines(function () { 3725 | "use strict"; 3726 | 3727 | ig.Loader = ig.Class.extend({ 3728 | resources: [], 3729 | 3730 | gameClass: null, 3731 | status: 0, 3732 | done: false, 3733 | 3734 | _unloaded: [], 3735 | _drawStatus: 0, 3736 | _intervalId: 0, 3737 | _loadCallbackBound: null, 3738 | 3739 | init: function init(gameClass, resources) { 3740 | this.gameClass = gameClass; 3741 | this.resources = resources; 3742 | this._loadCallbackBound = this._loadCallback.bind(this); 3743 | 3744 | for (var i = 0; i < this.resources.length; i++) { 3745 | this._unloaded.push(this.resources[i].path); 3746 | } 3747 | }, 3748 | 3749 | load: function load() { 3750 | ig.system.clear('#000'); 3751 | 3752 | if (!this.resources.length) { 3753 | this.end(); 3754 | return; 3755 | } 3756 | 3757 | for (var i = 0; i < this.resources.length; i++) { 3758 | this.loadResource(this.resources[i]); 3759 | } 3760 | this._intervalId = setInterval(this.draw.bind(this), 16); 3761 | }, 3762 | 3763 | loadResource: function loadResource(res) { 3764 | res.load(this._loadCallbackBound); 3765 | }, 3766 | 3767 | end: function end() { 3768 | if (this.done) { 3769 | return; 3770 | } 3771 | 3772 | this.done = true; 3773 | clearInterval(this._intervalId); 3774 | ig.system.setGame(this.gameClass); 3775 | }, 3776 | 3777 | draw: function draw() { 3778 | this._drawStatus += (this.status - this._drawStatus) / 5; 3779 | var s = ig.system.scale; 3780 | var w = ig.system.width * 0.6; 3781 | var h = ig.system.height * 0.1; 3782 | var x = ig.system.width * 0.5 - w / 2; 3783 | var y = ig.system.height * 0.5 - h / 2; 3784 | 3785 | ig.system.context.fillStyle = '#000'; 3786 | ig.system.context.fillRect(0, 0, 480, 320); 3787 | 3788 | ig.system.context.fillStyle = '#fff'; 3789 | ig.system.context.fillRect(x * s, y * s, w * s, h * s); 3790 | 3791 | ig.system.context.fillStyle = '#000'; 3792 | ig.system.context.fillRect(x * s + s, y * s + s, w * s - s - s, h * s - s - s); 3793 | 3794 | ig.system.context.fillStyle = '#fff'; 3795 | ig.system.context.fillRect(x * s, y * s, w * s * this._drawStatus, h * s); 3796 | }, 3797 | 3798 | _loadCallback: function _loadCallback(path, status) { 3799 | if (status) { 3800 | this._unloaded.erase(path); 3801 | } else { 3802 | throw 'Failed to load resource: ' + path; 3803 | } 3804 | 3805 | this.status = 1 - this._unloaded.length / this.resources.length; 3806 | if (this._unloaded.length == 0) { 3807 | // all done? 3808 | setTimeout(this.end.bind(this), 250); 3809 | } 3810 | } 3811 | }); 3812 | }); 3813 | }.call(window)); 3814 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(/*! ig */ 1))) 3815 | 3816 | /***/ }, 3817 | /* 21 */ 3818 | /*!***************************!*\ 3819 | !*** ./lib/impact/map.js ***! 3820 | \***************************/ 3821 | /***/ function(module, exports, __webpack_require__) { 3822 | 3823 | /* WEBPACK VAR INJECTION */(function(ig) {/*** IMPORTS FROM imports-loader ***/ 3824 | (function() { 3825 | 3826 | "use strict"; 3827 | 3828 | ig.module('impact.map').defines(function () { 3829 | "use strict"; 3830 | 3831 | ig.Map = ig.Class.extend({ 3832 | tilesize: 8, 3833 | width: 1, 3834 | height: 1, 3835 | data: [[]], 3836 | name: null, 3837 | 3838 | init: function init(tilesize, data) { 3839 | this.tilesize = tilesize; 3840 | this.data = data; 3841 | this.height = data.length; 3842 | this.width = data[0].length; 3843 | 3844 | this.pxWidth = this.width * this.tilesize; 3845 | this.pxHeight = this.height * this.tilesize; 3846 | }, 3847 | 3848 | getTile: function getTile(x, y) { 3849 | var tx = Math.floor(x / this.tilesize); 3850 | var ty = Math.floor(y / this.tilesize); 3851 | if (tx >= 0 && tx < this.width && ty >= 0 && ty < this.height) { 3852 | return this.data[ty][tx]; 3853 | } else { 3854 | return 0; 3855 | } 3856 | }, 3857 | 3858 | setTile: function setTile(x, y, tile) { 3859 | var tx = Math.floor(x / this.tilesize); 3860 | var ty = Math.floor(y / this.tilesize); 3861 | if (tx >= 0 && tx < this.width && ty >= 0 && ty < this.height) { 3862 | this.data[ty][tx] = tile; 3863 | } 3864 | } 3865 | }); 3866 | }); 3867 | }.call(window)); 3868 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(/*! ig */ 1))) 3869 | 3870 | /***/ }, 3871 | /* 22 */ 3872 | /*!*****************************!*\ 3873 | !*** ./lib/impact/sound.js ***! 3874 | \*****************************/ 3875 | /***/ function(module, exports, __webpack_require__) { 3876 | 3877 | /* WEBPACK VAR INJECTION */(function(ig) {/*** IMPORTS FROM imports-loader ***/ 3878 | (function() { 3879 | 3880 | 'use strict'; 3881 | 3882 | ig.module('impact.sound').defines(function () { 3883 | "use strict"; 3884 | 3885 | ig.SoundManager = ig.Class.extend({ 3886 | clips: {}, 3887 | volume: 1, 3888 | format: null, 3889 | 3890 | init: function init() { 3891 | // Quick sanity check if the Browser supports the Audio tag 3892 | if (!ig.Sound.enabled || !window.Audio) { 3893 | ig.Sound.enabled = false; 3894 | return; 3895 | } 3896 | 3897 | // Probe sound formats and determine the file extension to load 3898 | var probe = new Audio(); 3899 | for (var i = 0; i < ig.Sound.use.length; i++) { 3900 | var format = ig.Sound.use[i]; 3901 | if (probe.canPlayType(format.mime)) { 3902 | this.format = format; 3903 | break; 3904 | } 3905 | } 3906 | 3907 | // No compatible format found? -> Disable sound 3908 | if (!this.format) { 3909 | ig.Sound.enabled = false; 3910 | } 3911 | 3912 | // Create WebAudio Context 3913 | if (ig.Sound.enabled && ig.Sound.useWebAudio) { 3914 | this.audioContext = new AudioContext(); 3915 | this.boundWebAudioUnlock = this.unlockWebAudio.bind(this); 3916 | document.addEventListener('touchstart', this.boundWebAudioUnlock, false); 3917 | } 3918 | }, 3919 | 3920 | unlockWebAudio: function unlockWebAudio() { 3921 | document.removeEventListener('touchstart', this.boundWebAudioUnlock, false); 3922 | 3923 | // create empty buffer 3924 | var buffer = this.audioContext.createBuffer(1, 1, 22050); 3925 | var source = this.audioContext.createBufferSource(); 3926 | source.buffer = buffer; 3927 | 3928 | source.connect(this.audioContext.destination); 3929 | source.start(0); 3930 | }, 3931 | 3932 | load: function load(path, multiChannel, loadCallback) { 3933 | if (multiChannel && ig.Sound.useWebAudio) { 3934 | // Requested as Multichannel and we're using WebAudio? 3935 | return this.loadWebAudio(path, multiChannel, loadCallback); 3936 | } else { 3937 | // Oldschool HTML5 Audio - always used for Music 3938 | return this.loadHTML5Audio(path, multiChannel, loadCallback); 3939 | } 3940 | }, 3941 | 3942 | loadWebAudio: function loadWebAudio(path, multiChannel, loadCallback) { 3943 | // Path to the soundfile with the right extension (.ogg or .mp3) 3944 | var realPath = ig.prefix + path.replace(/[^\.]+$/, this.format.ext) + ig.nocache; 3945 | 3946 | if (this.clips[path]) { 3947 | return this.clips[path]; 3948 | } 3949 | 3950 | var audioSource = new ig.Sound.WebAudioSource(); 3951 | this.clips[path] = audioSource; 3952 | 3953 | var request = new XMLHttpRequest(); 3954 | request.open('GET', realPath, true); 3955 | request.responseType = 'arraybuffer'; 3956 | 3957 | var that = this; 3958 | request.onload = function (ev) { 3959 | that.audioContext.decodeAudioData(request.response, function (buffer) { 3960 | audioSource.buffer = buffer; 3961 | loadCallback(path, true, ev); 3962 | }, function (ev) { 3963 | loadCallback(path, false, ev); 3964 | }); 3965 | }; 3966 | request.onerror = function (ev) { 3967 | loadCallback(path, false, ev); 3968 | }; 3969 | request.send(); 3970 | 3971 | return audioSource; 3972 | }, 3973 | 3974 | loadHTML5Audio: function loadHTML5Audio(path, multiChannel, loadCallback) { 3975 | 3976 | // Path to the soundfile with the right extension (.ogg or .mp3) 3977 | var realPath = ig.prefix + path.replace(/[^\.]+$/, this.format.ext) + ig.nocache; 3978 | 3979 | // Sound file already loaded? 3980 | if (this.clips[path]) { 3981 | // Loaded as WebAudio, but now requested as HTML5 Audio? Probably Music? 3982 | if (this.clips[path] instanceof ig.Sound.WebAudioSource) { 3983 | return this.clips[path]; 3984 | } 3985 | 3986 | // Only loaded as single channel and now requested as multichannel? 3987 | if (multiChannel && this.clips[path].length < ig.Sound.channels) { 3988 | for (var i = this.clips[path].length; i < ig.Sound.channels; i++) { 3989 | var a = new Audio(realPath); 3990 | a.load(); 3991 | this.clips[path].push(a); 3992 | } 3993 | } 3994 | return this.clips[path][0]; 3995 | } 3996 | 3997 | var clip = new Audio(realPath); 3998 | if (loadCallback) { 3999 | 4000 | // The canplaythrough event is dispatched when the browser determines 4001 | // that the sound can be played without interuption, provided the 4002 | // download rate doesn't change. 4003 | // Mobile browsers stubbornly refuse to preload HTML5, so we simply 4004 | // ignore the canplaythrough event and immediately "fake" a successful 4005 | // load callback 4006 | if (ig.ua.mobile) { 4007 | setTimeout(function () { 4008 | loadCallback(path, true, null); 4009 | }, 0); 4010 | } else { 4011 | clip.addEventListener('canplaythrough', function cb(ev) { 4012 | clip.removeEventListener('canplaythrough', cb, false); 4013 | loadCallback(path, true, ev); 4014 | }, false); 4015 | 4016 | clip.addEventListener('error', function (ev) { 4017 | loadCallback(path, false, ev); 4018 | }, false); 4019 | } 4020 | } 4021 | clip.preload = 'auto'; 4022 | clip.load(); 4023 | 4024 | this.clips[path] = [clip]; 4025 | if (multiChannel) { 4026 | for (var i = 1; i < ig.Sound.channels; i++) { 4027 | var a = new Audio(realPath); 4028 | a.load(); 4029 | this.clips[path].push(a); 4030 | } 4031 | } 4032 | 4033 | return clip; 4034 | }, 4035 | 4036 | get: function get(path) { 4037 | // Find and return a channel that is not currently playing 4038 | var channels = this.clips[path]; 4039 | 4040 | // Is this a WebAudio source? We only ever have one for each Sound 4041 | if (channels && channels instanceof ig.Sound.WebAudioSource) { 4042 | return channels; 4043 | } 4044 | 4045 | // Oldschool HTML5 Audio - find a channel that's not currently 4046 | // playing or, if all are playing, rewind one 4047 | for (var i = 0, clip; clip = channels[i++];) { 4048 | if (clip.paused || clip.ended) { 4049 | if (clip.ended) { 4050 | clip.currentTime = 0; 4051 | } 4052 | return clip; 4053 | } 4054 | } 4055 | 4056 | // Still here? Pause and rewind the first channel 4057 | channels[0].pause(); 4058 | channels[0].currentTime = 0; 4059 | return channels[0]; 4060 | } 4061 | }); 4062 | 4063 | ig.Music = ig.Class.extend({ 4064 | tracks: [], 4065 | namedTracks: {}, 4066 | currentTrack: null, 4067 | currentIndex: 0, 4068 | random: false, 4069 | 4070 | _volume: 1, 4071 | _loop: false, 4072 | _fadeInterval: 0, 4073 | _fadeTimer: null, 4074 | _endedCallbackBound: null, 4075 | 4076 | init: function init() { 4077 | this._endedCallbackBound = this._endedCallback.bind(this); 4078 | 4079 | Object.defineProperty(this, "volume", { 4080 | get: this.getVolume.bind(this), 4081 | set: this.setVolume.bind(this) 4082 | }); 4083 | 4084 | Object.defineProperty(this, "loop", { 4085 | get: this.getLooping.bind(this), 4086 | set: this.setLooping.bind(this) 4087 | }); 4088 | }, 4089 | 4090 | add: function add(music, name) { 4091 | if (!ig.Sound.enabled) { 4092 | return; 4093 | } 4094 | 4095 | var path = music instanceof ig.Sound ? music.path : music; 4096 | 4097 | var track = ig.soundManager.load(path, false); 4098 | 4099 | // Did we get a WebAudio Source? This is suboptimal; Music should be loaded 4100 | // as HTML5 Audio so it can be streamed 4101 | if (track instanceof ig.Sound.WebAudioSource) { 4102 | // Since this error will likely occour at game start, we stop the game 4103 | // to not produce any more errors. 4104 | ig.system.stopRunLoop(); 4105 | throw "Sound '" + path + "' loaded as Multichannel but used for Music. " + "Set the multiChannel param to false when loading, e.g.: new ig.Sound(path, false)"; 4106 | } 4107 | 4108 | track.loop = this._loop; 4109 | track.volume = this._volume; 4110 | track.addEventListener('ended', this._endedCallbackBound, false); 4111 | this.tracks.push(track); 4112 | 4113 | if (name) { 4114 | this.namedTracks[name] = track; 4115 | } 4116 | 4117 | if (!this.currentTrack) { 4118 | this.currentTrack = track; 4119 | } 4120 | }, 4121 | 4122 | next: function next() { 4123 | if (!this.tracks.length) { 4124 | return; 4125 | } 4126 | 4127 | this.stop(); 4128 | this.currentIndex = this.random ? Math.floor(Math.random() * this.tracks.length) : (this.currentIndex + 1) % this.tracks.length; 4129 | this.currentTrack = this.tracks[this.currentIndex]; 4130 | this.play(); 4131 | }, 4132 | 4133 | pause: function pause() { 4134 | if (!this.currentTrack) { 4135 | return; 4136 | } 4137 | this.currentTrack.pause(); 4138 | }, 4139 | 4140 | stop: function stop() { 4141 | if (!this.currentTrack) { 4142 | return; 4143 | } 4144 | this.currentTrack.pause(); 4145 | this.currentTrack.currentTime = 0; 4146 | }, 4147 | 4148 | play: function play(name) { 4149 | // If a name was provided, stop playing the current track (if any) 4150 | // and play the named track 4151 | if (name && this.namedTracks[name]) { 4152 | var newTrack = this.namedTracks[name]; 4153 | if (newTrack != this.currentTrack) { 4154 | this.stop(); 4155 | this.currentTrack = newTrack; 4156 | } 4157 | } else if (!this.currentTrack) { 4158 | return; 4159 | } 4160 | this.currentTrack.play(); 4161 | }, 4162 | 4163 | getLooping: function getLooping() { 4164 | return this._loop; 4165 | }, 4166 | 4167 | setLooping: function setLooping(l) { 4168 | this._loop = l; 4169 | for (var i in this.tracks) { 4170 | this.tracks[i].loop = l; 4171 | } 4172 | }, 4173 | 4174 | getVolume: function getVolume() { 4175 | return this._volume; 4176 | }, 4177 | 4178 | setVolume: function setVolume(v) { 4179 | this._volume = v.limit(0, 1); 4180 | for (var i in this.tracks) { 4181 | this.tracks[i].volume = this._volume; 4182 | } 4183 | }, 4184 | 4185 | fadeOut: function fadeOut(time) { 4186 | if (!this.currentTrack) { 4187 | return; 4188 | } 4189 | 4190 | clearInterval(this._fadeInterval); 4191 | this.fadeTimer = new ig.Timer(time); 4192 | this._fadeInterval = setInterval(this._fadeStep.bind(this), 50); 4193 | }, 4194 | 4195 | _fadeStep: function _fadeStep() { 4196 | var v = this.fadeTimer.delta().map(-this.fadeTimer.target, 0, 1, 0).limit(0, 1) * this._volume; 4197 | 4198 | if (v <= 0.01) { 4199 | this.stop(); 4200 | this.currentTrack.volume = this._volume; 4201 | clearInterval(this._fadeInterval); 4202 | } else { 4203 | this.currentTrack.volume = v; 4204 | } 4205 | }, 4206 | 4207 | _endedCallback: function _endedCallback() { 4208 | if (this._loop) { 4209 | this.play(); 4210 | } else { 4211 | this.next(); 4212 | } 4213 | } 4214 | }); 4215 | 4216 | ig.Sound = ig.Class.extend({ 4217 | path: '', 4218 | volume: 1, 4219 | currentClip: null, 4220 | multiChannel: true, 4221 | _loop: false, 4222 | 4223 | init: function init(path, multiChannel) { 4224 | this.path = path; 4225 | this.multiChannel = multiChannel !== false; 4226 | 4227 | Object.defineProperty(this, "loop", { 4228 | get: this.getLooping.bind(this), 4229 | set: this.setLooping.bind(this) 4230 | }); 4231 | 4232 | this.load(); 4233 | }, 4234 | 4235 | getLooping: function getLooping() { 4236 | return this._loop; 4237 | }, 4238 | 4239 | setLooping: function setLooping(loop) { 4240 | this._loop = loop; 4241 | 4242 | if (this.currentClip) { 4243 | this.currentClip.loop = loop; 4244 | } 4245 | }, 4246 | 4247 | load: function load(loadCallback) { 4248 | if (!ig.Sound.enabled) { 4249 | if (loadCallback) { 4250 | loadCallback(this.path, true); 4251 | } 4252 | return; 4253 | } 4254 | 4255 | if (ig.ready) { 4256 | ig.soundManager.load(this.path, this.multiChannel, loadCallback); 4257 | } else { 4258 | ig.addResource(this); 4259 | } 4260 | }, 4261 | 4262 | play: function play() { 4263 | if (!ig.Sound.enabled) { 4264 | return; 4265 | } 4266 | 4267 | this.currentClip = ig.soundManager.get(this.path); 4268 | this.currentClip.loop = this._loop; 4269 | this.currentClip.volume = ig.soundManager.volume * this.volume; 4270 | this.currentClip.play(); 4271 | }, 4272 | 4273 | stop: function stop() { 4274 | if (this.currentClip) { 4275 | this.currentClip.pause(); 4276 | this.currentClip.currentTime = 0; 4277 | } 4278 | } 4279 | }); 4280 | 4281 | ig.Sound.WebAudioSource = ig.Class.extend({ 4282 | sources: [], 4283 | gain: null, 4284 | buffer: null, 4285 | _loop: false, 4286 | 4287 | init: function init() { 4288 | this.gain = ig.soundManager.audioContext.createGain(); 4289 | this.gain.connect(ig.soundManager.audioContext.destination); 4290 | 4291 | Object.defineProperty(this, "loop", { 4292 | get: this.getLooping.bind(this), 4293 | set: this.setLooping.bind(this) 4294 | }); 4295 | 4296 | Object.defineProperty(this, "volume", { 4297 | get: this.getVolume.bind(this), 4298 | set: this.setVolume.bind(this) 4299 | }); 4300 | }, 4301 | 4302 | play: function play() { 4303 | if (!this.buffer) { 4304 | return; 4305 | } 4306 | var source = ig.soundManager.audioContext.createBufferSource(); 4307 | source.buffer = this.buffer; 4308 | source.connect(this.gain); 4309 | source.loop = this._loop; 4310 | 4311 | // Add this new source to our sources array and remove it again 4312 | // later when it has finished playing. 4313 | var that = this; 4314 | this.sources.push(source); 4315 | source.onended = function () { 4316 | that.sources.erase(source); 4317 | }; 4318 | 4319 | source.start(0); 4320 | }, 4321 | 4322 | pause: function pause() { 4323 | for (var i = 0; i < this.sources.length; i++) { 4324 | try { 4325 | this.sources[i].stop(); 4326 | } catch (err) {} 4327 | } 4328 | }, 4329 | 4330 | getLooping: function getLooping() { 4331 | return this._loop; 4332 | }, 4333 | 4334 | setLooping: function setLooping(loop) { 4335 | this._loop = loop; 4336 | 4337 | for (var i = 0; i < this.sources.length; i++) { 4338 | this.sources[i].loop = loop; 4339 | } 4340 | }, 4341 | 4342 | getVolume: function getVolume() { 4343 | return this.gain.gain.value; 4344 | }, 4345 | 4346 | setVolume: function setVolume(volume) { 4347 | this.gain.gain.value = volume; 4348 | } 4349 | }); 4350 | 4351 | ig.Sound.FORMAT = { 4352 | MP3: { ext: 'mp3', mime: 'audio/mpeg' }, 4353 | M4A: { ext: 'm4a', mime: 'audio/mp4; codecs=mp4a' }, 4354 | OGG: { ext: 'ogg', mime: 'audio/ogg; codecs=vorbis' }, 4355 | WEBM: { ext: 'webm', mime: 'audio/webm; codecs=vorbis' }, 4356 | CAF: { ext: 'caf', mime: 'audio/x-caf' } 4357 | }; 4358 | ig.Sound.use = [ig.Sound.FORMAT.OGG, ig.Sound.FORMAT.MP3]; 4359 | ig.Sound.channels = 4; 4360 | ig.Sound.enabled = true; 4361 | 4362 | ig.normalizeVendorAttribute(window, 'AudioContext'); 4363 | ig.Sound.useWebAudio = !!window.AudioContext && !window.nwf; 4364 | }); 4365 | }.call(window)); 4366 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(/*! ig */ 1))) 4367 | 4368 | /***/ }, 4369 | /* 23 */ 4370 | /*!******************************!*\ 4371 | !*** ./lib/impact/system.js ***! 4372 | \******************************/ 4373 | /***/ function(module, exports, __webpack_require__) { 4374 | 4375 | /* WEBPACK VAR INJECTION */(function(ig) {/*** IMPORTS FROM imports-loader ***/ 4376 | (function() { 4377 | 4378 | 'use strict'; 4379 | 4380 | ig.module('impact.system').requires('impact.timer', 'impact.image').defines(function () { 4381 | "use strict"; 4382 | 4383 | ig.System = ig.Class.extend({ 4384 | fps: 30, 4385 | width: 320, 4386 | height: 240, 4387 | realWidth: 320, 4388 | realHeight: 240, 4389 | scale: 1, 4390 | 4391 | tick: 0, 4392 | animationId: 0, 4393 | newGameClass: null, 4394 | running: false, 4395 | 4396 | delegate: null, 4397 | clock: null, 4398 | canvas: null, 4399 | context: null, 4400 | 4401 | init: function init(canvasId, fps, width, height, scale) { 4402 | this.fps = fps; 4403 | 4404 | this.clock = new ig.Timer(); 4405 | this.canvas = ig.$(canvasId); 4406 | this.resize(width, height, scale); 4407 | this.context = this.canvas.getContext('2d'); 4408 | 4409 | this.getDrawPos = ig.System.drawMode; 4410 | 4411 | // Automatically switch to crisp scaling when using a scale 4412 | // other than 1 4413 | if (this.scale != 1) { 4414 | ig.System.scaleMode = ig.System.SCALE.CRISP; 4415 | } 4416 | ig.System.scaleMode(this.canvas, this.context); 4417 | }, 4418 | 4419 | resize: function resize(width, height, scale) { 4420 | this.width = width; 4421 | this.height = height; 4422 | this.scale = scale || this.scale; 4423 | 4424 | this.realWidth = this.width * this.scale; 4425 | this.realHeight = this.height * this.scale; 4426 | this.canvas.width = this.realWidth; 4427 | this.canvas.height = this.realHeight; 4428 | }, 4429 | 4430 | setGame: function setGame(gameClass) { 4431 | if (this.running) { 4432 | this.newGameClass = gameClass; 4433 | } else { 4434 | this.setGameNow(gameClass); 4435 | } 4436 | }, 4437 | 4438 | setGameNow: function setGameNow(gameClass) { 4439 | ig.game = new gameClass(); 4440 | ig.system.setDelegate(ig.game); 4441 | }, 4442 | 4443 | setDelegate: function setDelegate(object) { 4444 | if (typeof object.run == 'function') { 4445 | this.delegate = object; 4446 | this.startRunLoop(); 4447 | } else { 4448 | throw 'System.setDelegate: No run() function in object'; 4449 | } 4450 | }, 4451 | 4452 | stopRunLoop: function stopRunLoop() { 4453 | ig.clearAnimation(this.animationId); 4454 | this.running = false; 4455 | }, 4456 | 4457 | startRunLoop: function startRunLoop() { 4458 | this.stopRunLoop(); 4459 | this.animationId = ig.setAnimation(this.run.bind(this), this.canvas); 4460 | this.running = true; 4461 | }, 4462 | 4463 | clear: function clear(color) { 4464 | this.context.fillStyle = color; 4465 | this.context.fillRect(0, 0, this.realWidth, this.realHeight); 4466 | }, 4467 | 4468 | run: function run() { 4469 | ig.Timer.step(); 4470 | this.tick = this.clock.tick(); 4471 | 4472 | this.delegate.run(); 4473 | ig.input.clearPressed(); 4474 | 4475 | if (this.newGameClass) { 4476 | this.setGameNow(this.newGameClass); 4477 | this.newGameClass = null; 4478 | } 4479 | }, 4480 | 4481 | getDrawPos: null // Set through constructor 4482 | }); 4483 | 4484 | ig.System.DRAW = { 4485 | AUTHENTIC: function AUTHENTIC(p) { 4486 | return Math.round(p) * this.scale; 4487 | }, 4488 | SMOOTH: function SMOOTH(p) { 4489 | return Math.round(p * this.scale); 4490 | }, 4491 | SUBPIXEL: function SUBPIXEL(p) { 4492 | return p * this.scale; 4493 | } 4494 | }; 4495 | ig.System.drawMode = ig.System.DRAW.SMOOTH; 4496 | 4497 | ig.System.SCALE = { 4498 | CRISP: function CRISP(canvas, context) { 4499 | ig.setVendorAttribute(context, 'imageSmoothingEnabled', false); 4500 | canvas.style.imageRendering = '-moz-crisp-edges'; 4501 | canvas.style.imageRendering = '-o-crisp-edges'; 4502 | canvas.style.imageRendering = '-webkit-optimize-contrast'; 4503 | canvas.style.imageRendering = 'crisp-edges'; 4504 | canvas.style.msInterpolationMode = 'nearest-neighbor'; // No effect on Canvas :/ 4505 | }, 4506 | SMOOTH: function SMOOTH(canvas, context) { 4507 | ig.setVendorAttribute(context, 'imageSmoothingEnabled', true); 4508 | canvas.style.imageRendering = ''; 4509 | canvas.style.msInterpolationMode = ''; 4510 | } 4511 | }; 4512 | ig.System.scaleMode = ig.System.SCALE.SMOOTH; 4513 | }); 4514 | }.call(window)); 4515 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(/*! ig */ 1))) 4516 | 4517 | /***/ }, 4518 | /* 24 */ 4519 | /*!*****************************!*\ 4520 | !*** ./lib/impact/timer.js ***! 4521 | \*****************************/ 4522 | /***/ function(module, exports, __webpack_require__) { 4523 | 4524 | /* WEBPACK VAR INJECTION */(function(ig) {/*** IMPORTS FROM imports-loader ***/ 4525 | (function() { 4526 | 4527 | "use strict"; 4528 | 4529 | ig.module('impact.timer').defines(function () { 4530 | "use strict"; 4531 | 4532 | ig.Timer = ig.Class.extend({ 4533 | target: 0, 4534 | base: 0, 4535 | last: 0, 4536 | pausedAt: 0, 4537 | 4538 | init: function init(seconds) { 4539 | this.base = ig.Timer.time; 4540 | this.last = ig.Timer.time; 4541 | 4542 | this.target = seconds || 0; 4543 | }, 4544 | 4545 | set: function set(seconds) { 4546 | this.target = seconds || 0; 4547 | this.base = ig.Timer.time; 4548 | this.pausedAt = 0; 4549 | }, 4550 | 4551 | reset: function reset() { 4552 | this.base = ig.Timer.time; 4553 | this.pausedAt = 0; 4554 | }, 4555 | 4556 | tick: function tick() { 4557 | var delta = ig.Timer.time - this.last; 4558 | this.last = ig.Timer.time; 4559 | return this.pausedAt ? 0 : delta; 4560 | }, 4561 | 4562 | delta: function delta() { 4563 | return (this.pausedAt || ig.Timer.time) - this.base - this.target; 4564 | }, 4565 | 4566 | pause: function pause() { 4567 | if (!this.pausedAt) { 4568 | this.pausedAt = ig.Timer.time; 4569 | } 4570 | }, 4571 | 4572 | unpause: function unpause() { 4573 | if (this.pausedAt) { 4574 | this.base += ig.Timer.time - this.pausedAt; 4575 | this.pausedAt = 0; 4576 | } 4577 | } 4578 | }); 4579 | 4580 | ig.Timer._last = 0; 4581 | ig.Timer.time = Number.MIN_VALUE; 4582 | ig.Timer.timeScale = 1; 4583 | ig.Timer.maxStep = 0.05; 4584 | 4585 | ig.Timer.step = function () { 4586 | var current = Date.now(); 4587 | var delta = (current - ig.Timer._last) / 1000; 4588 | ig.Timer.time += Math.min(delta, ig.Timer.maxStep) * ig.Timer.timeScale; 4589 | ig.Timer._last = current; 4590 | }; 4591 | }); 4592 | }.call(window)); 4593 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(/*! ig */ 1))) 4594 | 4595 | /***/ } 4596 | /******/ ]); 4597 | //# sourceMappingURL=game.min.js.map --------------------------------------------------------------------------------