[READ-ONLY] Mirror of https://github.com/excaliburjs/Excalibur. 🎮 Your friendly TypeScript 2D game engine for the web 🗡️ excaliburjs.com
excalibur excaliburjs game-development game-engine game-framework gamedev games html5-canvas typescript
2

Configure Feed

Select the types of activity you want to include in your feed.

[#1031] Implement play game start button (#1035)

Closes #1031

## Changes:

- Build in start game to loader

authored by

Erik Onarheim and committed by
GitHub
(Oct 6, 2018, 8:35 PM -0500) 870cc2cf 3131a0af

+670 -140
+2
CHANGELOG.md
··· 11 11 12 12 ### Changed 13 13 14 + - Excalibur will now prompt for user input before starting the game to be inline with the new webaudio requirments from chrome/mobile browsers ([#1031](https://github.com/excaliburjs/Excalibur/issues/1031)) 15 + 14 16 ### Deprecated 15 17 16 18 ### Fixed
+235
package-lock.json
··· 324 324 "uri-js": "^4.2.1" 325 325 } 326 326 }, 327 + "ajv-errors": { 328 + "version": "1.0.0", 329 + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.0.tgz", 330 + "integrity": "sha1-7PAh+hCP0X37Xms4Py3SM+Mf/Fk=", 331 + "dev": true 332 + }, 327 333 "ajv-keywords": { 328 334 "version": "3.2.0", 329 335 "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz", ··· 2590 2596 } 2591 2597 } 2592 2598 }, 2599 + "css-loader": { 2600 + "version": "1.0.0", 2601 + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-1.0.0.tgz", 2602 + "integrity": "sha512-tMXlTYf3mIMt3b0dDCOQFJiVvxbocJ5Ho577WiGPYPZcqVEO218L2iU22pDXzkTZCLDE+9AmGSUkWxeh/nZReA==", 2603 + "dev": true, 2604 + "requires": { 2605 + "babel-code-frame": "^6.26.0", 2606 + "css-selector-tokenizer": "^0.7.0", 2607 + "icss-utils": "^2.1.0", 2608 + "loader-utils": "^1.0.2", 2609 + "lodash.camelcase": "^4.3.0", 2610 + "postcss": "^6.0.23", 2611 + "postcss-modules-extract-imports": "^1.2.0", 2612 + "postcss-modules-local-by-default": "^1.2.0", 2613 + "postcss-modules-scope": "^1.1.0", 2614 + "postcss-modules-values": "^1.3.0", 2615 + "postcss-value-parser": "^3.3.0", 2616 + "source-list-map": "^2.0.0" 2617 + } 2618 + }, 2619 + "css-selector-tokenizer": { 2620 + "version": "0.7.0", 2621 + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz", 2622 + "integrity": "sha1-5piEdK6MlTR3v15+/s/OzNnPTIY=", 2623 + "dev": true, 2624 + "requires": { 2625 + "cssesc": "^0.1.0", 2626 + "fastparse": "^1.1.1", 2627 + "regexpu-core": "^1.0.0" 2628 + }, 2629 + "dependencies": { 2630 + "regexpu-core": { 2631 + "version": "1.0.0", 2632 + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz", 2633 + "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=", 2634 + "dev": true, 2635 + "requires": { 2636 + "regenerate": "^1.2.1", 2637 + "regjsgen": "^0.2.0", 2638 + "regjsparser": "^0.1.4" 2639 + } 2640 + } 2641 + } 2642 + }, 2643 + "cssesc": { 2644 + "version": "0.1.0", 2645 + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-0.1.0.tgz", 2646 + "integrity": "sha1-yBSQPkViM3GgR3tAEJqq++6t27Q=", 2647 + "dev": true 2648 + }, 2593 2649 "currently-unhandled": { 2594 2650 "version": "0.4.1", 2595 2651 "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", ··· 3768 3824 "version": "2.0.6", 3769 3825 "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 3770 3826 "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", 3827 + "dev": true 3828 + }, 3829 + "fastparse": { 3830 + "version": "1.1.1", 3831 + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.1.tgz", 3832 + "integrity": "sha1-0eJkOzipTXWDtHkGDmxK/8lAcfg=", 3771 3833 "dev": true 3772 3834 }, 3773 3835 "figures": { ··· 5498 5560 "safer-buffer": ">= 2.1.2 < 3" 5499 5561 } 5500 5562 }, 5563 + "icss-replace-symbols": { 5564 + "version": "1.1.0", 5565 + "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", 5566 + "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=", 5567 + "dev": true 5568 + }, 5569 + "icss-utils": { 5570 + "version": "2.1.0", 5571 + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-2.1.0.tgz", 5572 + "integrity": "sha1-g/Cg7DeL8yRheLbCrZE28TWxyWI=", 5573 + "dev": true, 5574 + "requires": { 5575 + "postcss": "^6.0.1" 5576 + } 5577 + }, 5501 5578 "ieee754": { 5502 5579 "version": "1.1.11", 5503 5580 "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.11.tgz", ··· 6680 6757 "version": "4.17.10", 6681 6758 "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", 6682 6759 "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==", 6760 + "dev": true 6761 + }, 6762 + "lodash.camelcase": { 6763 + "version": "4.3.0", 6764 + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", 6765 + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", 6683 6766 "dev": true 6684 6767 }, 6685 6768 "lodash.isplainobject": { ··· 8073 8156 "version": "0.1.1", 8074 8157 "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", 8075 8158 "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", 8159 + "dev": true 8160 + }, 8161 + "postcss": { 8162 + "version": "6.0.23", 8163 + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", 8164 + "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", 8165 + "dev": true, 8166 + "requires": { 8167 + "chalk": "^2.4.1", 8168 + "source-map": "^0.6.1", 8169 + "supports-color": "^5.4.0" 8170 + }, 8171 + "dependencies": { 8172 + "ansi-styles": { 8173 + "version": "3.2.1", 8174 + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 8175 + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 8176 + "dev": true, 8177 + "requires": { 8178 + "color-convert": "^1.9.0" 8179 + } 8180 + }, 8181 + "chalk": { 8182 + "version": "2.4.1", 8183 + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", 8184 + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", 8185 + "dev": true, 8186 + "requires": { 8187 + "ansi-styles": "^3.2.1", 8188 + "escape-string-regexp": "^1.0.5", 8189 + "supports-color": "^5.3.0" 8190 + } 8191 + }, 8192 + "has-flag": { 8193 + "version": "3.0.0", 8194 + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 8195 + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 8196 + "dev": true 8197 + }, 8198 + "source-map": { 8199 + "version": "0.6.1", 8200 + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 8201 + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 8202 + "dev": true 8203 + }, 8204 + "supports-color": { 8205 + "version": "5.5.0", 8206 + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 8207 + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 8208 + "dev": true, 8209 + "requires": { 8210 + "has-flag": "^3.0.0" 8211 + } 8212 + } 8213 + } 8214 + }, 8215 + "postcss-modules-extract-imports": { 8216 + "version": "1.2.0", 8217 + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.0.tgz", 8218 + "integrity": "sha1-ZhQOzs447wa/DT41XWm/WdFB6oU=", 8219 + "dev": true, 8220 + "requires": { 8221 + "postcss": "^6.0.1" 8222 + } 8223 + }, 8224 + "postcss-modules-local-by-default": { 8225 + "version": "1.2.0", 8226 + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz", 8227 + "integrity": "sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=", 8228 + "dev": true, 8229 + "requires": { 8230 + "css-selector-tokenizer": "^0.7.0", 8231 + "postcss": "^6.0.1" 8232 + } 8233 + }, 8234 + "postcss-modules-scope": { 8235 + "version": "1.1.0", 8236 + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz", 8237 + "integrity": "sha1-1upkmUx5+XtipytCb75gVqGUu5A=", 8238 + "dev": true, 8239 + "requires": { 8240 + "css-selector-tokenizer": "^0.7.0", 8241 + "postcss": "^6.0.1" 8242 + } 8243 + }, 8244 + "postcss-modules-values": { 8245 + "version": "1.3.0", 8246 + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz", 8247 + "integrity": "sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=", 8248 + "dev": true, 8249 + "requires": { 8250 + "icss-replace-symbols": "^1.1.0", 8251 + "postcss": "^6.0.1" 8252 + } 8253 + }, 8254 + "postcss-value-parser": { 8255 + "version": "3.3.0", 8256 + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz", 8257 + "integrity": "sha1-h/OPnxj3dKSrTIojL1xc6IcqnRU=", 8076 8258 "dev": true 8077 8259 }, 8078 8260 "prelude-ls": { ··· 9851 10033 } 9852 10034 } 9853 10035 }, 10036 + "to-string-loader": { 10037 + "version": "1.1.5", 10038 + "resolved": "https://registry.npmjs.org/to-string-loader/-/to-string-loader-1.1.5.tgz", 10039 + "integrity": "sha1-e3qheJG3u0lHp6Eb+wO1/enG5pU=", 10040 + "dev": true, 10041 + "requires": { 10042 + "loader-utils": "^0.2.16" 10043 + }, 10044 + "dependencies": { 10045 + "loader-utils": { 10046 + "version": "0.2.17", 10047 + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", 10048 + "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", 10049 + "dev": true, 10050 + "requires": { 10051 + "big.js": "^3.1.3", 10052 + "emojis-list": "^2.0.0", 10053 + "json5": "^0.5.0", 10054 + "object-assign": "^4.0.1" 10055 + } 10056 + } 10057 + } 10058 + }, 9854 10059 "tough-cookie": { 9855 10060 "version": "2.3.4", 9856 10061 "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", ··· 10698 10903 "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", 10699 10904 "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", 10700 10905 "dev": true 10906 + } 10907 + } 10908 + }, 10909 + "url-loader": { 10910 + "version": "1.1.1", 10911 + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-1.1.1.tgz", 10912 + "integrity": "sha512-vugEeXjyYFBCUOpX+ZuaunbK3QXMKaQ3zUnRfIpRBlGkY7QizCnzyyn2ASfcxsvyU3ef+CJppVywnl3Kgf13Gg==", 10913 + "dev": true, 10914 + "requires": { 10915 + "loader-utils": "^1.1.0", 10916 + "mime": "^2.0.3", 10917 + "schema-utils": "^1.0.0" 10918 + }, 10919 + "dependencies": { 10920 + "mime": { 10921 + "version": "2.3.1", 10922 + "resolved": "https://registry.npmjs.org/mime/-/mime-2.3.1.tgz", 10923 + "integrity": "sha512-OEUllcVoydBHGN1z84yfQDimn58pZNNNXgZlHXSboxMlFvgI6MXSWpWKpFRra7H1HxpVhHTkrghfRW49k6yjeg==", 10924 + "dev": true 10925 + }, 10926 + "schema-utils": { 10927 + "version": "1.0.0", 10928 + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", 10929 + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", 10930 + "dev": true, 10931 + "requires": { 10932 + "ajv": "^6.1.0", 10933 + "ajv-errors": "^1.0.0", 10934 + "ajv-keywords": "^3.1.0" 10935 + } 10701 10936 } 10702 10937 } 10703 10938 },
+3
package.json
··· 43 43 "@types/node": "8.10.18", 44 44 "copy-webpack-plugin": "4.5.1", 45 45 "cross-env": "5.1.6", 46 + "css-loader": "1.0.0", 46 47 "grunt": "1.0.2", 47 48 "grunt-build-control": "0.7.1", 48 49 "grunt-bumpup": "0.6.3", ··· 71 72 "rimraf": "2.6.2", 72 73 "source-map-support": "0.4.18", 73 74 "sync-request": "4.1.0", 75 + "to-string-loader": "1.1.5", 74 76 "travis-ci": "2.1.1", 75 77 "ts-loader": "4.3.0", 76 78 "tslint": "3.15.1", 77 79 "typedoc": "0.11.1", 78 80 "typescript": "2.8.3", 81 + "url-loader": "1.1.1", 79 82 "webpack": "4.8.1", 80 83 "webpack-cli": "2.1.3" 81 84 },
+15
webpack.config.js
··· 26 26 { 27 27 test: /\.tsx?$/, 28 28 loader: 'ts-loader' 29 + }, 30 + { 31 + test: /\.css$/, 32 + use: ['to-string-loader', 'css-loader'] 33 + }, 34 + { 35 + test: /\.(png|jpg|gif)$/i, 36 + use: [ 37 + { 38 + loader: 'url-loader', 39 + options: { 40 + limit: 8192 41 + } 42 + } 43 + ] 29 44 } 30 45 ] 31 46 },
+23 -23
.vscode/settings.json
··· 1 1 // Place your settings in this file to overwrite default and user settings. 2 2 { 3 - "editor.tabSize": 3, 4 - "editor.insertSpaces": true, 5 - "editor.detectIndentation": false, 6 - "restructuredtext.confPath": "docs/source/conf.py", 7 - "restructuredtext.builtDocumentationPath" : "docs/build/html", 8 - "tslint.enable": true, 9 - "tslint.configFile": "./tslint/tslint.json", 10 - "files.exclude": { 11 - "**/.git": true, 12 - ".grunt/": true, 13 - ".tscache": true, 14 - "**/.DS_Store": true, 15 - "**/node_modules": true, 16 - "**/node_shrinkwrap": true, 17 - "**/bin": true, 18 - "**/obj": true, 19 - "_SpecRunner.html": true, 20 - "TestsSpec.js*": true, 21 - "src/engine/*.js": true, 22 - "src/spec/*.js": true, 23 - "src/spec/*.map": true 24 - }, 25 - "typescript.tsdk": "./node_modules/typescript/lib" 3 + "editor.tabSize": 4, 4 + "editor.insertSpaces": true, 5 + "editor.detectIndentation": false, 6 + "restructuredtext.confPath": "docs/source/conf.py", 7 + "restructuredtext.builtDocumentationPath": "docs/build/html", 8 + "tslint.enable": true, 9 + "tslint.configFile": "./tslint/tslint.json", 10 + "files.exclude": { 11 + "**/.git": true, 12 + ".grunt/": true, 13 + ".tscache": true, 14 + "**/.DS_Store": true, 15 + "**/node_modules": true, 16 + "**/node_shrinkwrap": true, 17 + "**/bin": true, 18 + "**/obj": true, 19 + "_SpecRunner.html": true, 20 + "TestsSpec.js*": true, 21 + "src/engine/*.js": true, 22 + "src/spec/*.js": true, 23 + "src/spec/*.map": true 24 + }, 25 + "typescript.tsdk": "./node_modules/typescript/lib" 26 26 }
+42 -76
tslint/tslint.json
··· 1 1 { 2 - "rulesDirectory": [ 3 - "./rules" 4 - ], 5 - "rules": { 6 - "underscore-prefix": true, 7 - "class-name": true, 8 - "curly": true, 9 - "indent": [ 10 - true, 11 - "spaces" 12 - ], 13 - "label-position": true, 14 - "label-undefined": true, 15 - "interface-name": true, 16 - "max-line-length": [ 17 - true, 18 - 140 19 - ], 20 - "no-arg": true, 21 - "no-console": [ 22 - true, 23 - "debug", 24 - "info", 25 - "time", 26 - "timeEnd", 27 - "trace" 28 - ], 29 - "no-construct": true, 30 - "no-debugger": true, 31 - "no-duplicate-key": true, 32 - "no-duplicate-variable": true, 33 - "no-empty": true, 34 - "no-eval": true, 35 - "no-string-literal": true, 36 - "no-switch-case-fall-through": true, 37 - "trailing-comma": [ 38 - true, 39 - { 40 - "multiline": "never", 41 - "single": "never" 42 - } 43 - ], 44 - "no-trailing-whitespace": false, 45 - "no-unused-expression": true, 46 - "no-unused-variable": false, 47 - "no-unreachable": true, 48 - "no-use-before-declare": true, 49 - "one-line": [ 50 - true, 51 - "check-open-brace", 52 - "check-catch", 53 - "check-else", 54 - "check-whitespace" 55 - ], 56 - "jsdoc-format": true, 57 - "quotemark": [ 58 - true, 59 - "single" 60 - ], 61 - "radix": true, 62 - "semicolon": true, 63 - "triple-equals": [ 64 - true, 65 - "allow-null-check" 66 - ], 67 - "variable-name": false, 68 - "whitespace": [ 69 - true, 70 - "check-branch", 71 - "check-decl", 72 - "check-operator", 73 - "check-separator", 74 - "check-type" 75 - ] 76 - } 77 - } 2 + "rulesDirectory": ["./rules"], 3 + "rules": { 4 + "underscore-prefix": true, 5 + "class-name": true, 6 + "curly": true, 7 + "indent": [true, "spaces"], 8 + "label-position": true, 9 + "label-undefined": true, 10 + "interface-name": false, 11 + "max-line-length": [true, 140], 12 + "no-arg": true, 13 + "no-console": [true, "debug", "info", "time", "timeEnd", "trace"], 14 + "no-construct": true, 15 + "no-debugger": true, 16 + "no-duplicate-key": true, 17 + "no-duplicate-variable": true, 18 + "no-empty": true, 19 + "no-eval": true, 20 + "no-string-literal": true, 21 + "no-switch-case-fall-through": true, 22 + "trailing-comma": [ 23 + true, 24 + { 25 + "multiline": "never", 26 + "single": "never" 27 + } 28 + ], 29 + "no-trailing-whitespace": false, 30 + "no-unused-expression": true, 31 + "no-unused-variable": false, 32 + "no-unreachable": true, 33 + "no-use-before-declare": true, 34 + "one-line": [true, "check-open-brace", "check-catch", "check-else", "check-whitespace"], 35 + "jsdoc-format": true, 36 + "quotemark": [true, "single"], 37 + "radix": true, 38 + "semicolon": true, 39 + "triple-equals": [true, "allow-null-check"], 40 + "variable-name": false, 41 + "whitespace": [true, "check-branch", "check-decl", "check-operator", "check-separator", "check-type"] 42 + } 43 + }
+23 -2
src/engine/Engine.ts
··· 141 141 suppressHiDPIScaling?: boolean; 142 142 143 143 /** 144 + * Suppress play button, it is not recommended users of excalibur switch this feature. Some browsers require a user gesture (like a click) 145 + * for certain browser features to work like web audio. 146 + */ 147 + suppressPlayButton?: boolean; 148 + 149 + /** 144 150 * Specify how the game window is to be positioned when the [[DisplayMode.Position]] is chosen. This option MUST be specified 145 151 * if the DisplayMode is set as [[DisplayMode.Position]]. The position can be either a string or an [[IAbsolutePosition]]. 146 152 * String must be in the format of css style background-position. The vertical position must precede the horizontal position in strings. ··· 309 315 public displayMode: DisplayMode = DisplayMode.FullScreen; 310 316 311 317 private _suppressHiDPIScaling: boolean = false; 318 + 319 + private _suppressPlayButton: boolean = false; 312 320 /** 313 321 * Returns the calculated pixel ration for use in rendering 314 322 */ ··· 434 442 suppressConsoleBootMessage: null, 435 443 suppressMinimumBrowserFeatureDetection: null, 436 444 suppressHiDPIScaling: null, 445 + suppressPlayButton: null, 437 446 scrollPreventionMode: ScrollPreventionMode.Canvas, 438 447 backgroundColor: Color.fromHex('#2185d0') // Excalibur blue 439 448 }; ··· 502 511 O|===|* >________________>\n\ 503 512 \\|'); 504 513 console.log('Visit', 'http://excaliburjs.com', 'for more information'); 514 + } 515 + 516 + // Suppress play button 517 + if (options.suppressPlayButton) { 518 + this._suppressPlayButton = true; 505 519 } 506 520 507 521 this._logger = Logger.getInstance(); ··· 1267 1281 var loadingComplete: Promise<any>; 1268 1282 if (loader) { 1269 1283 this._loader = loader; 1284 + this._loader.suppressPlayButton = this._suppressPlayButton; 1270 1285 this._loader.wireEngine(this); 1271 1286 loadingComplete = this.load(this._loader); 1272 1287 } else { ··· 1382 1397 this._isLoading = true; 1383 1398 1384 1399 loader.load().then(() => { 1385 - setTimeout(() => { 1400 + if (this._suppressPlayButton) { 1401 + setTimeout(() => { 1402 + this._isLoading = false; 1403 + complete.resolve(); 1404 + // Delay is to give the logo a chance to show, otherwise don't delay 1405 + }, 500); 1406 + } else { 1386 1407 this._isLoading = false; 1387 1408 complete.resolve(); 1388 - }, 500); 1409 + } 1389 1410 }); 1390 1411 1391 1412 return complete;
+120
src/engine/Loader.css
··· 1 + /* Buttons styles start */ 2 + 3 + button#excalibur-play { 4 + display: inline-block; 5 + position: relative; 6 + border-radius: 6px; 7 + border: none; 8 + /*border: 3px solid; 9 + border-color: white; 10 + box-shadow: 0 0 10px #ccc;*/ 11 + padding: 1rem 1.5rem 1rem 4rem; 12 + margin: 0; 13 + text-decoration: none; 14 + background: #00b233; 15 + color: #ffffff; 16 + font-family: sans-serif; 17 + font-size: 2rem; 18 + line-height: 1; 19 + cursor: pointer; 20 + text-align: center; 21 + transition: background 250ms ease-in-out, transform 150ms ease; 22 + -webkit-appearance: none; 23 + -moz-appearance: none; 24 + 25 + -webkit-animation: excalibur-button-fadein 200ms; /* Safari, Chrome and Opera > 12.1 */ 26 + -moz-animation: excalibur-button-fadein 200ms; /* Firefox < 16 */ 27 + -ms-animation: excalibur-button-fadein 200ms; /* Internet Explorer */ 28 + -o-animation: excalibur-button-fadein 200ms; /* Opera < 12.1 */ 29 + animation: excalibur-button-fadein 200ms; 30 + } 31 + 32 + /* 33 + button#excalibur-play { 34 + display: none; 35 + }*/ 36 + 37 + button#excalibur-play:after { 38 + position: absolute; 39 + content: ''; 40 + border: 8px solid; 41 + border-color: transparent transparent transparent white; 42 + left: 35px; 43 + top: 24px; 44 + width: 0; 45 + height: 0; 46 + } 47 + 48 + button#excalibur-play:before { 49 + position: absolute; 50 + content: ''; 51 + border: 3px solid; 52 + left: 19px; 53 + top: 14px; 54 + border-radius: 20px; 55 + width: 30px; 56 + height: 30px; 57 + } 58 + 59 + button#excalibur-play:hover, 60 + button#excalibur-play:focus { 61 + background: #00982c; 62 + } 63 + 64 + button#excalibur-play:focus { 65 + outline: 1px solid #fff; 66 + outline-offset: -4px; 67 + } 68 + 69 + button#excalibur-play:active { 70 + transform: scale(0.99); 71 + } 72 + 73 + @keyframes excalibur-button-fadein { 74 + from { 75 + opacity: 0; 76 + } 77 + to { 78 + opacity: 1; 79 + } 80 + } 81 + 82 + /* Firefox < 16 */ 83 + @-moz-keyframes excalibur-button-fadein { 84 + from { 85 + opacity: 0; 86 + } 87 + to { 88 + opacity: 1; 89 + } 90 + } 91 + 92 + /* Safari, Chrome and Opera > 12.1 */ 93 + @-webkit-keyframes excalibur-button-fadein { 94 + from { 95 + opacity: 0; 96 + } 97 + to { 98 + opacity: 1; 99 + } 100 + } 101 + 102 + /* Internet Explorer */ 103 + @-ms-keyframes excalibur-button-fadein { 104 + from { 105 + opacity: 0; 106 + } 107 + to { 108 + opacity: 1; 109 + } 110 + } 111 + 112 + /* Opera < 12.1 */ 113 + @-o-keyframes excalibur-button-fadein { 114 + from { 115 + opacity: 0; 116 + } 117 + to { 118 + opacity: 1; 119 + } 120 + }
src/engine/Loader.logo.png

This is a binary file and will not be displayed.

+141 -9
src/engine/Loader.ts
··· 7 7 import { ILoader } from './Interfaces/ILoader'; 8 8 import { Class } from './Class'; 9 9 import * as DrawUtil from './Util/DrawUtil'; 10 + import { obsolete } from './Util/Decorators'; 11 + 12 + import logoImg from './Loader.logo.png'; 13 + import loaderCss from './Loader.css'; 10 14 11 15 /** 12 16 * Pre-loading assets ··· 41 45 * console.log("Game started!"); 42 46 * }); 43 47 * ``` 48 + * 49 + * ## Customize the Loader 50 + * 51 + * The loader can be customized to show different, text, logo, background color, and button. 52 + * 53 + * ```typescript 54 + * var loader = new ex.Loader([playerTexture]); 55 + * 56 + * // The loaders button text can simply modified using this 57 + * loader.playButtonText = 'Start the best game ever'; 58 + * 59 + * // The logo can be changed by inserting a base64 image string here 60 + * 61 + * loader.logo = 'data:image/png;base64,iVBORw...'; 62 + * loader.logoWidth = 15; 63 + * loader.logoHeight = 14; 64 + * 65 + * // The background color can be changed like so by supplying a valid CSS color string 66 + * 67 + * loader.backgroundColor = 'red' 68 + * loader.backgroundColor = '#176BAA' 69 + * 70 + * // To build a completely new button 71 + * loader.startButtonFactory = () => { 72 + * let myButton = document.createElement('button'); 73 + * myButton.textContent = 'The best button'; 74 + * return myButton; 75 + * }; 76 + * 77 + * engine.start(loader).then(() => {}); 78 + * ``` 44 79 */ 45 80 export class Loader extends Class implements ILoader { 46 81 private _resourceList: ILoadable[] = []; 47 82 private _index = 0; 48 83 84 + private _playButtonShown: boolean = false; 49 85 private _resourceCount: number = 0; 50 86 private _numLoaded: number = 0; 51 87 private _progressCounts: { [key: string]: number } = {}; ··· 54 90 55 91 // logo drawing stuff 56 92 57 - /* tslint:disable:max-line-length */ 58 93 // base64 string encoding of the excalibur logo (logo-white.png) 59 - public logo = 60 - 'data:image/png;base64,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'; 61 - /* tslint:enable:max-line-length */ 94 + public logo = logoImg; 62 95 public logoWidth = 468; 63 96 public logoHeight = 118; 64 97 public backgroundColor = '#176BAA'; ··· 72 105 73 106 return this._imageElement; 74 107 } 108 + 109 + public suppressPlayButton: boolean = false; 110 + protected _playButtonRootElement: HTMLElement; 111 + protected _playButtonElement: HTMLButtonElement; 112 + protected _styleBlock: HTMLStyleElement; 113 + /** Loads the css from Loader.css */ 114 + protected _playButtonStyles: string = loaderCss.toString(); 115 + protected get _playButton() { 116 + if (!this._playButtonRootElement) { 117 + this._playButtonRootElement = document.createElement('div'); 118 + this._playButtonRootElement.style.position = 'absolute'; 119 + document.body.appendChild(this._playButtonRootElement); 120 + } 121 + if (!this._styleBlock) { 122 + this._styleBlock = document.createElement('style'); 123 + this._styleBlock.textContent = this._playButtonStyles; 124 + document.head.appendChild(this._styleBlock); 125 + } 126 + if (!this._playButtonElement) { 127 + this._playButtonElement = this.startButtonFactory(); 128 + this._playButtonRootElement.appendChild(this._playButtonElement); 129 + } 130 + return this._playButtonElement; 131 + } 132 + 133 + /** 134 + * Get/set play button text 135 + */ 136 + public playButtonText: string = 'Play game'; 137 + 138 + /** 139 + * Return a html button element for excalibur to use as a play button 140 + */ 141 + public startButtonFactory = () => { 142 + let buttonElement = document.createElement('button'); 143 + buttonElement.id = 'excalibur-play'; 144 + buttonElement.textContent = this.playButtonText; 145 + buttonElement.style.display = 'none'; 146 + return buttonElement; 147 + }; 75 148 76 149 /** 77 150 * @param loadables Optionally provide the list of resources you want to load at constructor time ··· 121 194 } 122 195 123 196 /** 197 + * Shows the play button and returns a promise that resolves when clicked 198 + */ 199 + public showPlayButton(): Promise<any> { 200 + if (this.suppressPlayButton) { 201 + return Promise.resolve(); 202 + } else { 203 + this._playButtonShown = true; 204 + this._playButton.style.display = 'block'; 205 + let promise = new Promise(); 206 + 207 + this._playButton.addEventListener('click', () => (promise.state() === PromiseState.Pending ? promise.resolve() : promise)); 208 + this._playButton.addEventListener('touchend', () => (promise.state() === PromiseState.Pending ? promise.resolve() : promise)); 209 + this._playButton.addEventListener('pointerup', () => (promise.state() === PromiseState.Pending ? promise.resolve() : promise)); 210 + 211 + return promise; 212 + } 213 + } 214 + 215 + public hidePlayButton() { 216 + this._playButtonShown = false; 217 + this._playButton.style.display = 'none'; 218 + } 219 + 220 + /** 124 221 * Begin loading all of the supplied resources, returning a promise 125 222 * that resolves when loading of all is complete 126 223 */ ··· 128 225 var complete = new Promise<any>(); 129 226 var me = this; 130 227 if (this._resourceList.length === 0) { 131 - me.oncomplete.call(me); 132 - return complete.resolve(); 228 + me.showPlayButton().then(() => { 229 + // Unlock audio context in chrome after user gesture 230 + // https://github.com/excaliburjs/Excalibur/issues/262 231 + // https://github.com/excaliburjs/Excalibur/issues/1031 232 + WebAudio.unlock().then(() => { 233 + me.hidePlayButton(); 234 + me.oncomplete.call(me); 235 + complete.resolve(); 236 + }); 237 + }); 238 + return complete; 133 239 } 134 240 135 241 var progressArray = new Array<any>(this._resourceList.length); ··· 156 262 r.oncomplete = r.onerror = function() { 157 263 me._numLoaded++; 158 264 if (me._numLoaded === me._resourceCount) { 159 - me.oncomplete.call(me); 160 - complete.resolve(); 265 + setTimeout(() => { 266 + me.showPlayButton().then(() => { 267 + // Unlock audio context in chrome after user gesture 268 + // https://github.com/excaliburjs/Excalibur/issues/262 269 + // https://github.com/excaliburjs/Excalibur/issues/1031 270 + WebAudio.unlock().then(() => { 271 + me.hidePlayButton(); 272 + me.oncomplete.call(me); 273 + complete.resolve(); 274 + }); 275 + }); 276 + }, 200); // short delay in showing the button for aesthetics 161 277 } 162 278 }; 163 279 }); ··· 184 300 let canvasHeight = this._engine.canvasHeight / window.devicePixelRatio; 185 301 let canvasWidth = this._engine.canvasWidth / window.devicePixelRatio; 186 302 303 + if (this._playButtonRootElement) { 304 + let left = ctx.canvas.offsetLeft; 305 + let top = ctx.canvas.offsetTop; 306 + let buttonWidth = this._playButton.clientWidth; 307 + let buttonHeight = this._playButton.clientHeight; 308 + this._playButtonRootElement.style.left = `${left + canvasWidth / 2 - buttonWidth / 2}px`; 309 + this._playButtonRootElement.style.top = `${top + canvasHeight / 2 - buttonHeight / 2 + 100}px`; 310 + } 311 + 187 312 ctx.fillStyle = this.backgroundColor; 188 313 ctx.fillRect(0, 0, canvasWidth, canvasHeight); 189 314 ··· 197 322 ctx.drawImage(this._image, 0, 0, this.logoWidth, this.logoHeight, x, y - imageHeight - 20, width, imageHeight); 198 323 199 324 // loading box 325 + if (!this.suppressPlayButton && this._playButtonShown) { 326 + this._engine.setAntialiasing(oldAntialias); 327 + return; 328 + } 329 + 200 330 ctx.lineWidth = 2; 201 331 DrawUtil.roundRect(ctx, x, y, width, 20, 10); 202 - 203 332 var progress = width * (this._numLoaded / this._resourceCount); 204 333 var margin = 5; 205 334 var progressWidth = progress - margin * 2; ··· 244 373 } 245 374 246 375 /** 376 + * @obsolete Use [[Loader]] instead, this functionality has been made default 377 + * 247 378 * A [[Loader]] that pauses after loading to allow user 248 379 * to proceed to play the game. Typically you will 249 380 * want to use this loader for iOS to allow sounds ··· 331 462 this._playTrigger.addEventListener('click', this._handleOnTrigger); 332 463 } 333 464 465 + @obsolete({ message: 'Deprecated in v0.20.0', alternateMethod: 'Use ex.Loader instead' }) 334 466 public load(): Promise<any> { 335 467 this._waitPromise = new Promise<any>(); 336 468
+1 -1
src/engine/UIActor.ts
··· 20 20 * @param height The starting height of the actor 21 21 */ 22 22 constructor(xOrConfig?: number | IActorArgs, y?: number, width?: number, height?: number) { 23 - if (typeof (xOrConfig !== 'object')) { 23 + if (typeof xOrConfig !== 'object') { 24 24 super(<number>xOrConfig, y, width, height); 25 25 } else { 26 26 super(<IActorArgs>xOrConfig);
+9
src/engine/files.d.ts
··· 1 + declare module '*.png' { 2 + const value: string; 3 + export default value; 4 + } 5 + 6 + declare module '*.css' { 7 + const value: { toString: () => string }; 8 + export default value; 9 + }
+1
src/spec/TestUtils.ts
··· 10 10 suppressConsoleBootMessage: true, 11 11 suppressMinimumBrowserFeatureDetection: true, 12 12 suppressHiDPIScaling: true, 13 + suppressPlayButton: true, 13 14 displayMode: ex.DisplayMode.Position, 14 15 position: 'top' 15 16 },
+5 -2
sandbox/tests/animation/animation.ts
··· 8 8 width: width, 9 9 height: height, 10 10 canvasElementId: 'game', 11 - pointerScope: ex.Input.PointerScope.Canvas 11 + pointerScope: ex.Input.PointerScope.Canvas, 12 + suppressPlayButton: false 12 13 }); 13 14 engine.backgroundColor = ex.Color.Black; 14 15 ··· 27 28 } 28 29 }); 29 30 30 - engine.start(new ex.Loader([playerTexture])).then(() => {}); 31 + var loader = new ex.Loader([playerTexture]); 32 + loader.playButtonText = 'Start the best game ever'; 33 + engine.start(loader).then(() => {});
+1
src/engine/Interfaces/ILoader.ts
··· 2 2 import { Engine } from '../Engine'; 3 3 4 4 export interface ILoader extends ILoadable { 5 + suppressPlayButton: boolean; 5 6 draw(ctx: CanvasRenderingContext2D, delta: number): void; 6 7 update(engine: Engine, delta: number): void; 7 8 }
+49 -27
src/engine/Util/WebAudio.ts
··· 1 1 import { AudioContextFactory } from '../Resources/Sound/AudioContext'; 2 + import { Promise } from '../Promises'; 3 + 4 + export interface LegacyWebAudioSource { 5 + playbackState: string; 6 + PLAYING_STATE: 'playing'; 7 + FINISHED_STATE: 'finished'; 8 + } 9 + 10 + function isLegacyWebAudioSource(source: any): source is LegacyWebAudioSource { 11 + return !!source.playbackState; 12 + } 2 13 3 14 export class WebAudio { 4 15 private static _unlocked: boolean = false; ··· 8 19 * right after a user interaction event. Typically used by [[PauseAfterLoader]] 9 20 * @source https://paulbakaus.com/tutorials/html5/web-audio-on-ios/ 10 21 */ 11 - static unlock() { 22 + static unlock(): Promise<boolean> { 23 + let promise = new Promise<boolean>(); 12 24 if (WebAudio._unlocked || !AudioContextFactory.create()) { 13 - return; 25 + return promise.resolve(true); 14 26 } 15 27 16 28 const audioContext = AudioContextFactory.create(); 17 - // create empty buffer and play it 18 - const buffer = audioContext.createBuffer(1, 1, 22050); 19 - const source = audioContext.createBufferSource(); 20 - let ended = false; 29 + audioContext.resume().then( 30 + () => { 31 + // create empty buffer and play it 32 + const buffer = audioContext.createBuffer(1, 1, 22050); 33 + const source = audioContext.createBufferSource(); 34 + let ended = false; 21 35 22 - source.buffer = buffer; 23 - source.connect(audioContext.destination); 24 - source.onended = () => (ended = true); 36 + source.buffer = buffer; 37 + source.connect(audioContext.destination); 38 + source.onended = () => (ended = true); 25 39 26 - if ((<any>source).noteOn) { 27 - // deprecated 28 - (<any>source).noteOn(0); 29 - } else { 30 - source.start(0); 31 - } 32 - 33 - // by checking the play state after some time, we know if we're really unlocked 34 - setTimeout(function() { 35 - if ((<any>source).playbackState) { 36 - var legacySource = <any>source; 37 - if (legacySource.playbackState === legacySource.PLAYING_STATE || legacySource.playbackState === legacySource.FINISHED_STATE) { 38 - WebAudio._unlocked = true; 40 + if ((<any>source).noteOn) { 41 + // deprecated 42 + (<any>source).noteOn(0); 43 + } else { 44 + source.start(0); 39 45 } 40 - } else { 41 - if (audioContext.currentTime > 0 || ended) { 42 - WebAudio._unlocked = true; 43 - } 46 + 47 + // by checking the play state after some time, we know if we're really unlocked 48 + setTimeout(() => { 49 + if (isLegacyWebAudioSource(source)) { 50 + if (source.playbackState === source.PLAYING_STATE || source.playbackState === source.FINISHED_STATE) { 51 + WebAudio._unlocked = true; 52 + } 53 + } else { 54 + if (audioContext.currentTime > 0 || ended) { 55 + WebAudio._unlocked = true; 56 + } 57 + } 58 + }, 0); 59 + 60 + promise.resolve(); 61 + }, 62 + () => { 63 + promise.reject(false); 44 64 } 45 - }, 0); 65 + ); 66 + 67 + return promise; 46 68 } 47 69 48 70 static isUnlocked() {