├── .gitignore ├── types.js ├── panel ├── res │ ├── splash.png │ ├── favicon.ico │ └── style.css └── scripts │ ├── engine.js │ ├── module.js │ ├── init.js │ └── boot.js ├── screenshot └── quick-preview.gif ├── package.json ├── README.md ├── .jshintrc ├── template ├── toolbar.jade └── index.jade └── main.js /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /panel/index.html -------------------------------------------------------------------------------- /types.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '.js', 3 | '.ts', 4 | '.coffee' 5 | ]; -------------------------------------------------------------------------------- /panel/res/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2youyou2/quick-preview/HEAD/panel/res/splash.png -------------------------------------------------------------------------------- /panel/res/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2youyou2/quick-preview/HEAD/panel/res/favicon.ico -------------------------------------------------------------------------------- /screenshot/quick-preview.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2youyou2/quick-preview/HEAD/screenshot/quick-preview.gif -------------------------------------------------------------------------------- /panel/scripts/engine.js: -------------------------------------------------------------------------------- 1 | 2 | var originMainLoop = cc.director.mainLoop; 3 | cc.director.mainLoop = function () { 4 | try { 5 | originMainLoop.call(cc.director); 6 | } 7 | catch (err) { 8 | console.error(err); 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "quick-preview", 3 | "version": "0.0.1", 4 | "description": "The package template for getting started.", 5 | "author": "Cocos Creator", 6 | "main": "main.js", 7 | "main-menu": { 8 | "i18n:MAIN_MENU.package.title/quick-preview/open": { 9 | "message": "quick-preview:open", 10 | "accelerator": "CmdOrCtrl+Shift+O" 11 | }, 12 | "i18n:MAIN_MENU.package.title/quick-preview/reload": { 13 | "message": "quick-preview:reload", 14 | "accelerator": "CmdOrCtrl+Shift+R" 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deprecated 2 | 3 | # quick-preview 4 | Quick Preview Plugin for CocosCreator 1.4+ 5 | 6 | # screenshot 7 | ![screen](https://github.com/2youyou2/quick-preview/blob/master/screenshot/quick-preview.gif?raw=true) 8 | 9 | # feature 10 | - Load original engine files as modules 11 | - Load original project files as modules 12 | - Auto watch project files. 13 | Once detect file changed, Quick Preview will reload this single file and the modules depend on this module, then reload the scene. 14 | This task will be done super fast. 15 | - Auto reload scene when save scene in editor 16 | - Auto reload without focus back to editor 17 | 18 | # accelerator 19 | - cmd/ctrl + shift + o - open window 20 | - cmd/strl + shift + r - reload page (not reload scene) 21 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "bitwise": false, 5 | "camelcase": false, 6 | "curly": false, 7 | "eqeqeq": true, 8 | "immed": true, 9 | "indent": 2, 10 | "latedef": false, 11 | "newcap": false, 12 | "noarg": true, 13 | "quotmark": "single", 14 | "undef": true, 15 | "unused": true, 16 | "strict": true, 17 | "predef": [ 18 | "window", 19 | "document", 20 | "Image", 21 | "unused", 22 | "Editor", 23 | "EditorUI", 24 | "Helper", 25 | "_Scene", 26 | "Mousetrap", 27 | "Polymer", 28 | "sinon", 29 | "after", 30 | "afterAll", 31 | "afterEach", 32 | "assert", 33 | "before", 34 | "beforeAll", 35 | "beforeEach", 36 | "describe", 37 | "expect", 38 | "it", 39 | "cc", 40 | "CC_EDITOR", 41 | "CC_TEST" 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /template/toolbar.jade: -------------------------------------------------------------------------------- 1 | div.toolbar 2 | div.item 3 | select#opts-device 4 | option(value='0') Default 5 | 6 | div.item 7 | button#btn-rotate Rotate 8 | 9 | div.item 10 | select#opts-render-mode 11 | option(value='0') WebGL 12 | option(value='1') Canvas 13 | 14 | span.item(style='font-size: small;') Debug Mode: 15 | 16 | div.item 17 | select#opts-debug-mode 18 | option(value='0') None 19 | option(value='1') Info 20 | option(value='2') Warn 21 | option(value='3') Error 22 | option(value='4') Info For Web Page 23 | option(value='5') Warn For Web Page 24 | option(value='6') Error For Web Page 25 | 26 | div.item 27 | button#btn-show-fps Show FPS 28 | 29 | div.item 30 | span.item(style='font-size: small;') FPS: 31 | input#input-set-fps(type='number') 32 | 33 | div.item(style='margin-right: 0px;') 34 | button#btn-pause Pause 35 | 36 | div.item 37 | button#btn-reload(style='margin-right: 0px;') Reload 38 | 39 | div.item 40 | button#btn-step(style='display: none;') Step 41 | -------------------------------------------------------------------------------- /template/index.jade: -------------------------------------------------------------------------------- 1 | html 2 | head 3 | link(rel='icon' href='app/editor/static/preview-templates/favicon.ico') 4 | meta(charset='utf-8') 5 | title=title 6 | meta(name='viewport' content='width=device-width,user-scalable=no,initial-scale=1, minimum-scale=1,maximum-scale=1') 7 | meta(name='apple-mobile-web-app-capable' content='yes') 8 | meta(name='full-screen' content='yes') 9 | meta(name='screen-orientation' content='portrait') 10 | meta(name='x5-fullscreen' content='true') 11 | meta(name='360-fullscreen' content='true') 12 | 13 | meta(name='renderer' content='webkit') 14 | meta(name='force-rendering' content='webkit') 15 | meta(http-equiv='X-UA-Compatible' content='IE=edge,chrome=1') 16 | 17 | link(rel='stylesheet' href='res/style.css') 18 | 19 | body 20 | include ./template/toolbar.jade 21 | 22 | div.content#content 23 | div.wrapper#GameDiv 24 | canvas#GameCanvas 25 | 26 | div#splash 27 | div.progress-bar.stripes 28 | span 29 | div#bulletin 30 | div.inner#sceneIsEmpty= tip_sceneIsEmpty 31 | 32 | script(type='text/javascript'). 33 | _Settings = {}; 34 | _Settings.CCSettings = '#{settings}'; 35 | _Settings.libraryPath = '#{libraryPath}'; 36 | _Settings.rawAssetsBase = '#{rawAssetsBase}'; 37 | _Settings['preview-scene.json'] = '#{previewScene}'; 38 | _Settings.appPath = '#{appPath}'; 39 | _Settings.assetPath = '#{assetPath}'; 40 | _Settings.projectPath = '#{projectPath}'; 41 | _Settings.tmpScriptPath = '#{tmpScriptPath}'; 42 | 43 | script(type='text/javascript'). 44 | 45 | window.CC_DEV = true; 46 | 47 | require('./scripts/module'); 48 | require('#{engine}'); 49 | require('./scripts/init'); 50 | 51 | script(type='text/javascript' charset='utf-8' src='scripts/boot.js') 52 | -------------------------------------------------------------------------------- /panel/scripts/module.js: -------------------------------------------------------------------------------- 1 | let Module = require('module'); 2 | let Path = require('path'); 3 | 4 | function basenameNoExt(path) { 5 | return Path.basename(path, Path.extname(path) ); 6 | } 7 | 8 | let originRequire = Module.prototype.require; 9 | Module.prototype.require = function (path) { 10 | if (path.indexOf('modular-cocos2d-cut') !== -1) { 11 | return null; 12 | } 13 | return originRequire.apply(this, arguments); 14 | }; 15 | 16 | // reimplement Module._findPath 17 | let originFindPath = Module._findPath; 18 | Module._findPath = function (request, paths, isMain) { 19 | if (window.qp && qp.modules) { 20 | let module = qp.modules[request]; 21 | if (module) { 22 | return module.path; 23 | } 24 | } 25 | 26 | return originFindPath.apply(Module, arguments); 27 | }; 28 | 29 | let originLoad = Module._load; 30 | Module._load = function (request, parent, isMain) { 31 | 32 | if (window.qp && qp.modules) { 33 | let name = basenameNoExt(request); 34 | let module = qp.modules[name]; 35 | 36 | let parentName = basenameNoExt(parent.filename); 37 | let parentModule = qp.modules[parentName]; 38 | 39 | if (module && parentModule) { 40 | request = module.path; 41 | 42 | if (parentModule && module.parents.indexOf(parentModule) === -1) { 43 | module.parents.push(parentModule); 44 | } 45 | } 46 | } 47 | 48 | return originLoad.apply(Module, [request, parent, isMain]); 49 | }; 50 | 51 | // reimplement Module._nodeModulePaths 52 | let appPaths = Module._nodeModulePaths( _Settings.appPath ); 53 | let originResolveLookupPaths = Module._resolveLookupPaths; 54 | Module._resolveLookupPaths = function () { 55 | let resolvedModule = originResolveLookupPaths.apply(Module, arguments); 56 | let paths = resolvedModule[1]; 57 | appPaths.forEach(path => { 58 | if (paths.indexOf(path) === -1) { 59 | paths.push(path); 60 | } 61 | }); 62 | return resolvedModule; 63 | }; 64 | -------------------------------------------------------------------------------- /panel/res/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | cursor: default; 3 | color: #888; 4 | background-color: #333; 5 | 6 | display: -webkit-flex; 7 | display: flex; 8 | 9 | -webkit-flex-direction: column; 10 | flex-direction: column; 11 | 12 | height: 100%; /* for firefox */ 13 | width: 100%; 14 | 15 | position: absolute; 16 | padding: 0px; 17 | border: 0px; 18 | margin: 0px; 19 | } 20 | 21 | /* Remove spin of input type number */ 22 | input::-webkit-outer-spin-button, 23 | input::-webkit-inner-spin-button { 24 | /* display: none; <- Crashes Chrome on hover */ 25 | -webkit-appearance: none; 26 | margin: 0; /* <-- Apparently some margin are still there even though it's hidden */ 27 | } 28 | 29 | body, canvas, div { 30 | outline: none; 31 | -moz-user-select: none; 32 | -webkit-user-select: none; 33 | -ms-user-select: none; 34 | -khtml-user-select: none; 35 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 36 | } 37 | 38 | #splash { 39 | position: absolute; 40 | top: 0; 41 | left: 0; 42 | width: 100%; 43 | height: 100%; 44 | 45 | background: #171717 url(./splash.png) no-repeat center; 46 | background-size: 40%; 47 | } 48 | 49 | #GameDiv { 50 | visibility: hidden; 51 | } 52 | 53 | .content { 54 | display: -webkit-flex; 55 | display: flex; 56 | 57 | -webkit-justify-content: center; 58 | justify-content: center; 59 | 60 | -webkit-align-items: center; 61 | align-items: center; 62 | 63 | -webkit-flex-direction: column; 64 | flex-direction: column; 65 | 66 | -webkit-flex: auto; 67 | flex: auto; 68 | 69 | overflow: auto; 70 | } 71 | 72 | .wrapper { 73 | position: relative; 74 | 75 | border: 1px solid #444; 76 | background: #222; 77 | } 78 | 79 | .toolbar { 80 | /*position: absolute;*/ 81 | /*left: 10px;*/ 82 | /*top: 10px;*/ 83 | min-height: 27px; 84 | padding: 4px 0px 4px 10px; 85 | 86 | display: -webkit-flex; 87 | display: flex; 88 | 89 | -webkit-align-items: center; 90 | align-items: center; 91 | 92 | -webkit-flex-direction: row; 93 | flex-direction: row; 94 | 95 | z-index: 999; 96 | } 97 | 98 | .toolbar * { 99 | font-size: 12px; 100 | font-family: /* https://www.smashingmagazine.com/2015/11/using-system-ui-fonts-practical-guide/ */ 101 | -apple-system, BlinkMacSystemFont, 102 | "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", 103 | "Helvetica Neue", sans-serif; 104 | } 105 | 106 | .toolbar .item { 107 | display: inline-block; 108 | margin-right: 10px; 109 | } 110 | 111 | .toolbar select { 112 | height: 25px; 113 | padding: 0px 8px; 114 | 115 | box-shadow: none; 116 | background-image: none; 117 | 118 | border: 1px solid #171717; 119 | background: #444; 120 | color: #aaa; 121 | } 122 | 123 | .toolbar select:focus { 124 | outline: none; 125 | /* border: 1px solid #09f; */ 126 | } 127 | 128 | .toolbar button { 129 | border: 1px solid #171717; 130 | border-radius: 2px; 131 | text-align: center; 132 | padding: 4px 8px; 133 | 134 | cursor: pointer; 135 | color: #bdbdbd; 136 | font-weight: bold; 137 | 138 | background-image: linear-gradient(#5a5a5a, #444); 139 | } 140 | 141 | .toolbar button.checked { 142 | box-shadow: inset 0 2px 4px rgba(0,0,0,0.5); 143 | color: #09f; 144 | background-image: linear-gradient(#333, #222); 145 | } 146 | 147 | .toolbar button:focus { 148 | outline: none; 149 | } 150 | 151 | .toolbar button:active { 152 | box-shadow: inset 0 2px 4px rgba(0,0,0,0.5); 153 | color: #888; 154 | background-image: linear-gradient(#333, #222); 155 | } 156 | 157 | .toolbar input { 158 | width: 41px; 159 | height: 24px; 160 | padding: 4px 4px; 161 | box-shadow: inset 0px 0px 2px 1px rgba(0,0,0,0.3); 162 | border: 1px solid #171717; 163 | background: #444; 164 | color: #aaa; 165 | } 166 | 167 | @media screen and (max-width: 760px) { 168 | .toolbar { 169 | display: none; 170 | } 171 | 172 | .wrapper { 173 | border: 0px; 174 | 175 | position: absolute; 176 | top: 0; 177 | left: 0; 178 | right: 0; 179 | bottom: 0; 180 | } 181 | } 182 | 183 | #bulletin { 184 | position: absolute; 185 | left: 50%; 186 | top: 50%; 187 | display: none; 188 | } 189 | 190 | #bulletin .inner { 191 | position: relative; 192 | left: -50%; 193 | top: -50%; 194 | display: none; 195 | } 196 | 197 | .progress-bar { 198 | background-color: #1a1a1a; 199 | position: absolute; 200 | left: 25%; 201 | top: 80%; 202 | height: 15px; 203 | padding: 5px; 204 | width: 50%; 205 | /*margin: 0 -175px; */ 206 | border-radius: 5px; 207 | box-shadow: 0 1px 5px #000 inset, 0 1px 0 #444; 208 | } 209 | 210 | .progress-bar span { 211 | display: block; 212 | height: 100%; 213 | border-radius: 3px; 214 | box-shadow: 0 1px 0 rgba(255, 255, 255, .5) inset; 215 | transition: width .4s ease-in-out; 216 | background-color: #34c2e3; 217 | } 218 | 219 | .stripes span { 220 | background-size: 30px 30px; 221 | background-image: linear-gradient(135deg, rgba(255, 255, 255, .15) 25%, transparent 25%, 222 | transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, 223 | transparent 75%, transparent); 224 | 225 | animation: animate-stripes 1s linear infinite; 226 | } 227 | 228 | @keyframes animate-stripes { 229 | 0% {background-position: 0 0;} 100% {background-position: 60px 0;} 230 | } 231 | -------------------------------------------------------------------------------- /panel/scripts/init.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const ipcRenderer = require('electron').ipcRenderer; 4 | const Path = require('fire-path'); 5 | const Globby = require('globby'); 6 | const Fs = require('fire-fs'); 7 | const Del = require('del'); 8 | 9 | // reload 10 | let errorList = []; 11 | let reloadTimeoutId; 12 | function reload () { 13 | if (!reloadTimeoutId) { 14 | reloadTimeoutId = setTimeout(() => { 15 | if (errorList.length === 0) { 16 | window.reloadScene(); 17 | } 18 | reloadTimeoutId = null; 19 | }, 100); 20 | } 21 | } 22 | 23 | function unregisterPathClass (path) { 24 | let name = Path.basenameNoExt(path); 25 | if (!qp.modules[name]) return; 26 | 27 | let cls = cc.js.getClassByName( name ); 28 | if (cls) { 29 | cc.js.unregisterClass( cls ); 30 | } 31 | 32 | delete require.cache[path]; 33 | delete qp.modules[name]; 34 | } 35 | 36 | function registerPathClass (path) { 37 | let module = qp._addModule(path); 38 | if (!module) return; 39 | 40 | try { 41 | module.module = require(path); 42 | cc.js.array.remove(errorList, path); 43 | } 44 | catch(err) { 45 | errorList.push(path); 46 | unregisterPathClass(path); 47 | // console.error(err); 48 | console.log(err); 49 | } 50 | } 51 | 52 | function reregisterParentModules (module) { 53 | if (!module) return; 54 | 55 | for (let i = 0; i < module.parents.length; i++) { 56 | let parentModule = module.parents[i]; 57 | let parentPath = parentModule.path; 58 | unregisterPathClass(parentPath); 59 | registerPathClass(parentPath); 60 | 61 | reregisterParentModules(parentModule); 62 | } 63 | } 64 | 65 | // ipc messages 66 | ipcRenderer.on('generate-src-file-complete', (event, src, dst) => { 67 | let name = Path.basenameNoExt(dst); 68 | let module = qp.modules[name]; 69 | 70 | unregisterPathClass(dst); 71 | registerPathClass(dst); 72 | 73 | reregisterParentModules(module); 74 | 75 | reload(); 76 | }); 77 | 78 | ipcRenderer.on('reload-scene', () => { 79 | reload(); 80 | }); 81 | 82 | 83 | let watcher; 84 | 85 | // quick preview 86 | window.qp = { 87 | modules: {}, 88 | 89 | _updateModules: function (cb) { 90 | let pattern = Path.join(_Settings.tmpScriptPath, '**/*.js'); 91 | 92 | Globby.sync(pattern) 93 | .forEach(path => { 94 | path = Path.normalize(path); 95 | this._addModule(path); 96 | } 97 | ); 98 | }, 99 | 100 | _addModule: function (path) { 101 | let name = Path.basenameNoExt(path); 102 | let module = this.modules[name]; 103 | 104 | if (qp.plugins.indexOf(name) !== -1) { 105 | if (module) { 106 | this.unregisterPathClass(module.path); 107 | } 108 | return null; 109 | } 110 | 111 | if (!module) { 112 | module = this.modules[name] = { 113 | name: name, 114 | path: path, 115 | parents: [] 116 | }; 117 | } 118 | 119 | return module; 120 | }, 121 | 122 | _watch: function () { 123 | if (watcher) return; 124 | 125 | const Chokidar = require('chokidar'); 126 | 127 | let pattern = require('../../types').map(extname => { 128 | return Path.join(_Settings.assetPath, '**/*' + extname); 129 | }); 130 | 131 | watcher = Chokidar.watch(pattern, { 132 | ignoreInitial: true 133 | }); 134 | 135 | watcher.on('all', (event, path) => { 136 | let src = path; 137 | let dst = Path.join(_Settings.tmpScriptPath, 'assets', Path.relative(_Settings.assetPath, path)); 138 | dst = Path.join(Path.dirname(dst), Path.basenameNoExt(dst) + '.js'); 139 | 140 | if (event === 'change') { 141 | ipcRenderer.send('generate-src-file', src, dst); 142 | } 143 | else if (event === 'add') { 144 | qp._updateModules(); 145 | ipcRenderer.send('generate-src-file', src, dst); 146 | } 147 | else if (event === 'unlink') { 148 | unregisterPathClass(dst); 149 | 150 | if (Fs.existsSync(dst)) { 151 | try { 152 | Del.sync(dst, {force: true}); 153 | } 154 | catch(err) { 155 | Editor.error(err); 156 | } 157 | } 158 | } 159 | }); 160 | }, 161 | 162 | init: function () { 163 | if (this._inited) return; 164 | this._inited = true; 165 | 166 | qp._updateModules(); 167 | 168 | for (let name in this.modules) { 169 | registerPathClass(this.modules[name].path); 170 | } 171 | 172 | qp._watch(); 173 | }, 174 | 175 | loadScript: function (src, callback) { 176 | var timer = 'load ' + src; 177 | var scriptElement = document.createElement('script'); 178 | 179 | function done() { 180 | // console.timeEnd(timer); 181 | // deallocation immediate whatever 182 | scriptElement.remove(); 183 | } 184 | 185 | scriptElement.onload = function () { 186 | done(); 187 | callback(); 188 | }; 189 | scriptElement.onerror = function () { 190 | done(); 191 | var error = 'Failed to load ' + src; 192 | console.error(error); 193 | callback(new Error(error)); 194 | }; 195 | scriptElement.setAttribute('type','text/javascript'); 196 | scriptElement.setAttribute('charset', 'utf-8'); 197 | scriptElement.setAttribute('src', src); 198 | 199 | // console.time(timer); 200 | document.head.appendChild(scriptElement); 201 | }, 202 | 203 | loadPlugins: function (cb) { 204 | // jsList 205 | var jsList = _CCSettings.jsList || []; 206 | jsList = jsList.map(function (x) { return _Settings.rawAssetsBase + x; }); 207 | 208 | this.plugins = jsList.map(path => { 209 | return Path.basenameNoExt(path); 210 | }); 211 | 212 | let originModule = window.module; 213 | window.module = null; 214 | cc.loader.load(jsList, function () { 215 | window.module = originModule; 216 | if (cb) cb(); 217 | }); 218 | }, 219 | 220 | _moduleStack: [], 221 | _RFpush: function (module) { 222 | let stack = this._moduleStack; 223 | if (stack.length > 0) { 224 | module.ccParent = stack[stack.length - 1]; 225 | } 226 | stack.push(module); 227 | 228 | cc._RF.push.apply(cc._RFpush, arguments); 229 | }, 230 | 231 | _RFpop: function (module) { 232 | this._moduleStack.pop(); 233 | 234 | cc._RF.pop.apply(cc._RFpush, arguments); 235 | } 236 | }; 237 | -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const {app, BrowserWindow, ipcMain} = require('electron'); 4 | const Path = require('fire-path'); 5 | const Url = require('url'); 6 | const Jade = require('jade'); 7 | const Globby = require('globby'); 8 | const Fs = require('fire-fs'); 9 | const Del = require('del'); 10 | const Async = require('async'); 11 | 12 | const UuidUtils = require( Editor.url('app://editor/share/editor-utils/uuid-utils') ); 13 | 14 | const assetPath = Path.join(Editor.projectPath, 'assets').replace(/\\/g, '/'); 15 | const tmpScriptPath = Path.join(Editor.projectPath, 'temp/qp-scripts').replace(/\\/g, '/'); 16 | 17 | 18 | function generateHtml () { 19 | let content = Fs.readFileSync(Path.join(__dirname, 'template/index.jade'), 'utf8'); 20 | 21 | let fn = Jade.compile(content, { 22 | filename: Path.join(__dirname, 'template'), 23 | pretty: true 24 | }); 25 | 26 | let urlPrefix = `http://localhost:${Editor.PreviewServer.previewPort}`; 27 | 28 | let libraryPath = `${urlPrefix}/res/import`; 29 | let rawAssetsBase = `${urlPrefix}/res/raw-`; 30 | 31 | content = fn({ 32 | engine: Editor.url('unpack://engine').replace(/\\/g, '/'), 33 | settings: `${urlPrefix}/settings.js`, 34 | libraryPath: libraryPath, 35 | rawAssetsBase: rawAssetsBase, 36 | previewScene: `${urlPrefix}/preview-scene.json`, 37 | appPath: Editor.App.path.replace(/\\/g, '/'), 38 | assetPath: assetPath, 39 | projectPath: Editor.projectPath.replace(/\\/g, '/'), 40 | tmpScriptPath: tmpScriptPath 41 | }); 42 | 43 | Fs.writeFileSync(Path.join(__dirname, 'panel/index.html'), content); 44 | } 45 | 46 | function generateContent (cb) { 47 | generateHtml(); 48 | generateSrcFiles(cb); 49 | } 50 | 51 | function url (path) { 52 | return Url.format({ 53 | pathname: path, 54 | protocol: 'file:', 55 | slashes: true 56 | }); 57 | } 58 | 59 | let compiledJsMap = {}; 60 | 61 | function transformJs (src, dest, uuid, reimportScript, time, cb) { 62 | let meta = Editor.assetdb.loadMetaByUuid(uuid); 63 | 64 | if (!meta) { 65 | return cb(new Error(`load meta for [${src}] failed`)); 66 | } 67 | 68 | function copyDests (cb) { 69 | let dstDir = Path.dirname(dest); 70 | 71 | if (meta.isPlugin) { 72 | Fs.copySync(src, dest); 73 | return cb(); 74 | } 75 | 76 | let dests = [ 77 | Editor.assetdb._uuidToImportPathNoExt( meta.uuid ) + '.js', 78 | Editor.assetdb._uuidToImportPathNoExt( meta.uuid ) + '.js.map' 79 | ]; 80 | 81 | dests.forEach(importPath => { 82 | let basenameNoExt = Path.basenameNoExt(src); 83 | let extname = Path.extname(src); 84 | 85 | let importBasename = Path.basename(importPath); 86 | let importExtname = importBasename.substr(importBasename.indexOf('.'), importBasename.length); 87 | 88 | if (importExtname === '.js.map') { 89 | dest = Path.join(dstDir, `${basenameNoExt}-${time}.js.map`); 90 | let contents = JSON.parse( Fs.readFileSync(importPath, 'utf8') ); 91 | 92 | contents.sources = [`${basenameNoExt}-${time}${extname}`]; 93 | contents = JSON.stringify(contents); 94 | 95 | Fs.writeFileSync(dest, contents); 96 | } 97 | else { 98 | dest = Path.join(dstDir, basenameNoExt + importExtname); 99 | Fs.copySync( importPath, dest ); 100 | } 101 | }); 102 | 103 | cb(); 104 | } 105 | 106 | if (!reimportScript) { 107 | copyDests( cb ); 108 | } 109 | else { 110 | meta.import(src, (err) => { 111 | if (err) return cb(err); 112 | copyDests( cb ); 113 | }); 114 | } 115 | } 116 | 117 | function addMetaData (src, dst, reimportScript, cb) { 118 | let name = Path.basenameNoExt(dst); 119 | let uuid = Editor.assetdb.fspathToUuid(src) || ''; 120 | 121 | if (!compiledJsMap[src]) { 122 | compiledJsMap[src] = 1; 123 | } 124 | let time = compiledJsMap[src]++; 125 | 126 | transformJs(src, dst, uuid, reimportScript, time, (err) => { 127 | if (err) return cb(err); 128 | 129 | let contents = Fs.readFileSync(dst, 'utf8'); 130 | let header; 131 | if (uuid) { 132 | uuid = UuidUtils.compressUuid(uuid); 133 | header = `"use strict";` + 134 | `qp._RFpush(module, '${uuid}', '${name}');`; 135 | } 136 | else { 137 | header = `"use strict";` + 138 | `qp._RFpush(module, '${name}');`; 139 | } 140 | let endsWithNewLine = (contents[contents.length - 1] === '\n' || contents[contents.length - 1] === '\r'); 141 | 142 | let footer = "\nqp._RFpop();"; 143 | footer += `\n//# sourceMappingURL=${Path.basenameNoExt(dst)}-${time}.js.map`; 144 | 145 | // let mapPath = dst + '.map'; 146 | // if (Fs.existsSync(mapPath)) { 147 | // let json = Fs.readFileSync(mapPath, 'utf8'); 148 | 149 | // let convert = require('convert-source-map'); 150 | // let mapping = convert.fromJSON(json) 151 | // .setProperty('sources', [`${Path.basenameNoExt(src)}-${time}${Path.extname(src)}`]) 152 | // .toComment(); 153 | 154 | // footer += mapping; 155 | // } 156 | 157 | let newLineFooter = '\n' + footer; 158 | contents = header + contents + (endsWithNewLine ? footer : newLineFooter); 159 | 160 | Fs.ensureDirSync(Path.dirname(dst)); 161 | Fs.writeFileSync(dst, contents); 162 | 163 | cb (); 164 | }); 165 | } 166 | 167 | function generateSrcFiles (cb) { 168 | Del.sync(tmpScriptPath, {force: true}); 169 | 170 | let pattern = require('./types').map(extname => { 171 | return Path.join(assetPath, '**/*' + extname); 172 | }); 173 | 174 | Globby(pattern, (err, paths) => { 175 | Async.forEach(paths, (path, done) => { 176 | path = Path.normalize(path); 177 | let dst = Path.join(tmpScriptPath, 'assets', Path.relative(assetPath, path)); 178 | dst = Path.join(Path.dirname(dst), Path.basenameNoExt(dst) + '.js'); 179 | addMetaData(path, dst, false, done); 180 | }, err => { 181 | if (err) Editor.error(err); 182 | cb (); 183 | }); 184 | }); 185 | } 186 | 187 | let win; 188 | function openWindow () { 189 | if (win) { 190 | win.focus(); 191 | return; 192 | } 193 | 194 | win = new BrowserWindow({ 195 | x: 100, 196 | y: 100, 197 | width: 960, 198 | height: 640, 199 | minWidth: 400, 200 | minHeight: 300, 201 | 202 | webPreferences: { 203 | devTools: true 204 | } 205 | }); 206 | 207 | win.webContents.openDevTools(); 208 | 209 | win.once('closed', function () { 210 | win = null; 211 | }); 212 | 213 | generateContent(() => { 214 | win.loadURL( url(Path.join(__dirname, 'panel/index.html')) ); 215 | }); 216 | } 217 | 218 | Editor.App.on('quit', function () { 219 | if (win) { 220 | win.close(); 221 | } 222 | }); 223 | 224 | function onGenerateSrcFile (event, src, dst) { 225 | addMetaData(src, dst, true, (err) => { 226 | if (err) Editor.error(err); 227 | event.sender.send('generate-src-file-complete', src, dst); 228 | }); 229 | } 230 | 231 | function onAppReloadOnDevice () { 232 | if (win) { 233 | win.webContents.send('reload-scene'); 234 | } 235 | } 236 | 237 | module.exports = { 238 | load () { 239 | Editor.Metrics.trackEvent({ 240 | category: 'Packages', 241 | label: 'quick-preview', 242 | action: 'Panel Load' 243 | }, null); 244 | 245 | ipcMain.on('generate-src-file', onGenerateSrcFile); 246 | ipcMain.on('app:reload-on-device', onAppReloadOnDevice); 247 | }, 248 | 249 | unload () { 250 | ipcMain.removeListener('generate-src-file', onGenerateSrcFile); 251 | ipcMain.removeListener('app:reload-on-device', onAppReloadOnDevice); 252 | }, 253 | 254 | messages: { 255 | 'open' () { 256 | openWindow(); 257 | 258 | Editor.Metrics.trackEvent({ 259 | category: 'Packages', 260 | label: 'quick-preview', 261 | action: 'Panel Open' 262 | }, null); 263 | }, 264 | 'reload' () { 265 | if (win) { 266 | win.loadURL( url(Path.join(__dirname, 'panel/index.html')) ); 267 | } 268 | } 269 | }, 270 | }; 271 | -------------------------------------------------------------------------------- /panel/scripts/boot.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | require('electron-cookies'); 5 | 6 | // init device resolutions 7 | var devices = [ 8 | { name: 'Apple iPad', width: 1024, height: 768, ratio: 2 }, 9 | { name: 'Apple iPad Mini', width: 1024, height: 768, ratio: 1 }, 10 | { name: 'Apple iPhone 4', width: 320, height: 480, ratio: 2 }, 11 | { name: 'Apple iPhone 5', width: 320, height: 568, ratio: 2 }, 12 | { name: 'Apple iPhone 6', width: 375, height: 667, ratio: 2 }, 13 | { name: 'Apple iPhone 6 Plus', width: 414, height: 736, ratio: 3 }, 14 | { name: 'Goolge Nexus 4', width: 384, height: 640, ratio: 2 }, 15 | { name: 'Goolge Nexus 5', width: 360, height: 640, ratio: 3 }, 16 | { name: 'Goolge Nexus 6', width: 412, height: 732, ratio: 3.5 }, 17 | { name: 'Goolge Nexus 7', width: 960, height: 600, ratio: 2 }, 18 | ]; 19 | 20 | function setCSSChecked (element, checked) { 21 | if (checked) { 22 | element.classList.add('checked'); 23 | } 24 | else { 25 | element.classList.remove('checked'); 26 | } 27 | return checked; 28 | } 29 | 30 | function refreshPauseBtnState () { 31 | if (cc.game.isPaused()) { 32 | btnPause.style.borderTopRightRadius = '0'; 33 | btnPause.style.borderBottomRightRadius = '0'; 34 | btnStep.style.borderTopLeftRadius = '0'; 35 | btnStep.style.borderBottomLeftRadius = '0'; 36 | btnStep.style.display = ''; 37 | setCSSChecked(btnPause, true); 38 | } 39 | else { 40 | btnPause.style.borderTopRightRadius = ''; 41 | btnPause.style.borderBottomRightRadius = ''; 42 | btnStep.style.borderTopLeftRadius = ''; 43 | btnStep.style.borderBottomLeftRadius = ''; 44 | btnStep.style.display = 'none'; 45 | setCSSChecked(btnPause, false); 46 | } 47 | } 48 | 49 | var isMobile = function () { 50 | var check = false; 51 | (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true;})(navigator.userAgent||navigator.vendor||window.opera); 52 | return check; 53 | }; 54 | 55 | // init toolbar 56 | // ======================= 57 | 58 | var rotated = false; 59 | // var paused = false; 60 | var canvas = document.getElementById('GameCanvas'); 61 | var btnRotate = document.getElementById('btn-rotate'); 62 | var optsDevice = document.getElementById('opts-device'); 63 | var optsRenderMode = document.getElementById('opts-render-mode'); 64 | var btnPause = document.getElementById('btn-pause'); 65 | var btnStep = document.getElementById('btn-step'); 66 | var optsDebugMode = document.getElementById('opts-debug-mode'); 67 | var btnShowFPS = document.getElementById('btn-show-fps'); 68 | var inputSetFPS = document.getElementById('input-set-fps'); 69 | var btnReload = document.getElementById('btn-reload'); 70 | 71 | devices.forEach( function ( info, idx ) { 72 | var opt = document.createElement('option'); 73 | opt.value = idx+1; 74 | opt.text = info.name; 75 | optsDevice.add( opt, null ); 76 | }); 77 | 78 | // coockie 79 | // ======================= 80 | function setCookie (name, value, days) { 81 | days = days || 30; //cookie will be saved for 30 days 82 | var expires = new Date(); 83 | expires.setTime(expires.getTime() + days*24*60*60*1000); 84 | document.cookie = name + '='+ encodeURIComponent(value);// + ';expires=' + expires.toGMTString(); 85 | } 86 | 87 | function getCookie (name) { 88 | var arr = document.cookie.match(new RegExp('(^| )' + name + '=([^;]*)(;|$)')); 89 | if(arr !== null) return (arr[2]); 90 | return null; 91 | } 92 | 93 | function isFullScreen () { 94 | var toolbar = document.getElementsByClassName('toolbar')[0]; 95 | return getComputedStyle(toolbar).display === 'none'; 96 | } 97 | 98 | function getEmulatedScreenSize () { 99 | var w, h; 100 | var idx = optsDevice.value; 101 | if ( idx === '0' ) { 102 | w = _CCSettings.designWidth; 103 | h = _CCSettings.designHeight; 104 | } 105 | else { 106 | var info = devices[parseInt(idx) - 1]; 107 | w = info.width; 108 | h = info.height; 109 | } 110 | return { 111 | width: rotated ? h : w, 112 | height: rotated ? w : h 113 | }; 114 | } 115 | 116 | function showSplash () { 117 | var size = isFullScreen() ? document.documentElement.getBoundingClientRect() : getEmulatedScreenSize(); 118 | 119 | var splash = document.getElementById('splash'); 120 | var progressBar = splash.querySelector('.progress-bar span'); 121 | splash.style.width = size.width + 'px'; 122 | splash.style.height = size.height + 'px'; 123 | if (size.width < size.height) { 124 | // portrait 125 | splash.style.backgroundImage = 'res/splash_portrait.png)'; 126 | } 127 | splash.style.display = ''; 128 | progressBar.style.width = '0%'; 129 | 130 | var div = document.getElementById('GameDiv'); 131 | if (div) { 132 | div.style.visibility = 'visible'; 133 | } 134 | 135 | if ( !isMobile() ) { 136 | // make the splash screen in center 137 | canvas.width = size.width; 138 | canvas.height = size.height; 139 | } 140 | } 141 | 142 | // init options 143 | function initPreviewOptions () { 144 | var defaultDevice = getCookie('device'); 145 | var defaultRotate = getCookie('rotate'); 146 | 147 | var hasDefaultDevice = defaultDevice !== null; 148 | var hasDefaultRotate = defaultRotate !== null; 149 | 150 | if (hasDefaultDevice) { 151 | optsDevice.value = parseInt(defaultDevice); 152 | } 153 | 154 | if (hasDefaultRotate && defaultRotate === 'true') { 155 | rotated = !rotated; 156 | setCSSChecked(btnRotate, rotated); 157 | } 158 | 159 | optsRenderMode.value = getCookie('renderMode') || '0'; 160 | optsDebugMode.value = getCookie('debugMode') || '1'; 161 | setCSSChecked(btnShowFPS, getCookie('showFPS') === 'true'); 162 | inputSetFPS.value = getCookie('frameRate') || '60'; 163 | } 164 | 165 | function isShowFPS() { 166 | return Array.prototype.indexOf.call(btnShowFPS.classList, 'checked') !== -1; 167 | } 168 | 169 | function setDisplayStats (display) { 170 | if (cc.debug && cc.debug.setDisplayStats) { 171 | cc.debug.setDisplayStats(display); 172 | } 173 | else { 174 | cc.director.setDisplayStats(display); 175 | } 176 | } 177 | 178 | function isDisplayStats () { 179 | if (cc.debug && cc.debug.isDisplayStats) { 180 | return cc.debug.isDisplayStats(); 181 | } 182 | else { 183 | return cc.director.isDisplayStats(); 184 | } 185 | } 186 | 187 | initPreviewOptions(); 188 | 189 | window.onload = function () { 190 | 191 | function updateResolution () { 192 | var size = isFullScreen() ? document.documentElement.getBoundingClientRect() : getEmulatedScreenSize(); 193 | var gameDiv = document.getElementById('GameDiv'); 194 | gameDiv.style.width = size.width + 'px'; 195 | gameDiv.style.height = size.height + 'px'; 196 | 197 | cc.view.setCanvasSize(size.width, size.height); 198 | } 199 | 200 | // init rotate button 201 | btnRotate.addEventListener('click', function () { 202 | rotated = !rotated; 203 | setCSSChecked(btnRotate, rotated); 204 | setCookie('rotate', rotated.toString()); 205 | updateResolution(); 206 | }); 207 | 208 | optsDevice.addEventListener( 'change', function () { 209 | var idx = optsDevice.value; 210 | setCookie('device', idx.toString()); 211 | updateResolution(); 212 | }); 213 | 214 | // init render modes 215 | (function () { 216 | var REFRESH_TIP = ' (Refresh to take effect)'; 217 | var tipAdded = false; 218 | optsRenderMode.addEventListener('change', function (event) { 219 | var value = event.target.value; 220 | setCookie('renderMode', value); 221 | // display refresh tip 222 | var current = cc.game.config.renderMode; 223 | if (!tipAdded && parseInt(value) !== current) { 224 | optsRenderMode.children[0].text += REFRESH_TIP; 225 | optsRenderMode.children[1].text += REFRESH_TIP; 226 | tipAdded = true; 227 | } 228 | }); 229 | })(); 230 | 231 | // init debug modes 232 | optsDebugMode.addEventListener('change', function (event) { 233 | var value = event.target.value; 234 | setCookie('debugMode', value); 235 | cc._initDebugSetting(parseInt(value)); 236 | }); 237 | 238 | // init pause button 239 | btnPause.addEventListener('click', function () { 240 | var shouldPause = !cc.game.isPaused(); 241 | if (shouldPause) { 242 | cc.game.pause(); 243 | } 244 | else { 245 | cc.game.resume(); 246 | } 247 | refreshPauseBtnState(); 248 | }); 249 | 250 | // init reload button 251 | btnReload.addEventListener('click', function () { 252 | window.reloadScene(); 253 | }); 254 | 255 | // init step button 256 | btnStep.addEventListener('click', function () { 257 | cc.game.step(); 258 | }); 259 | 260 | // init show fps, true by default 261 | btnShowFPS.addEventListener('click', function () { 262 | var show = cc.director.isDisplayStats ? !cc.director.isDisplayStats() : !cc.debug.isDisplayStats(); 263 | setDisplayStats(show); 264 | setCSSChecked(btnShowFPS, show); 265 | setCookie('showFPS', show.toString()); 266 | }); 267 | 268 | // init set fps 269 | inputSetFPS.addEventListener('change', function (event) { 270 | var fps = parseInt(inputSetFPS.value); 271 | if (isNaN(fps)) { 272 | fps = 60; 273 | inputSetFPS.value = fps.toString(); 274 | } 275 | cc.game.setFrameRate(fps); 276 | setCookie('frameRate', fps); 277 | }); 278 | 279 | 280 | // init engine 281 | // ======================= 282 | 283 | if (isFullScreen()) { 284 | window.addEventListener('resize', updateResolution); 285 | } 286 | 287 | var option = { 288 | id: canvas, 289 | renderMode: parseInt(optsRenderMode.value), 290 | debugMode: parseInt(optsDebugMode.value), 291 | showFPS: isShowFPS(), 292 | frameRate: parseInt(inputSetFPS.value), 293 | }; 294 | 295 | 296 | window.reloadScene = function () { 297 | const Async = require('async'); 298 | 299 | cc.game.pause(); 300 | 301 | let AssetOptions; 302 | Async.series([ 303 | // clear web cache 304 | function (next) { 305 | // var Electron = require('electron'); 306 | // var win = Electron.remote.getCurrentWindow(); 307 | // win.webContents.session.clearCache(next); 308 | next(); 309 | }, 310 | 311 | // load CCSettings 312 | function (next) { 313 | qp.loadScript(_Settings.CCSettings, next); 314 | }, 315 | 316 | function (next) { 317 | // resize canvas 318 | if (!isFullScreen()) { 319 | updateResolution(); 320 | } 321 | 322 | showSplash(); 323 | 324 | next(); 325 | }, 326 | 327 | function (next) { 328 | qp.loadPlugins(next); 329 | }, 330 | 331 | function (next) { 332 | cc.game._sceneInfos = _CCSettings.scenes; 333 | cc.game.collisionMatrix = _CCSettings.collisionMatrix; 334 | cc.game.groupList = _CCSettings.groupList; 335 | 336 | next(); 337 | }, 338 | 339 | function (next) { 340 | // init assets 341 | AssetOptions = { 342 | libraryPath: _Settings.libraryPath, 343 | rawAssetsBase: _Settings.rawAssetsBase, 344 | rawAssets: _CCSettings.rawAssets 345 | }; 346 | cc.AssetLibrary.init(AssetOptions); 347 | 348 | // clear loader cache 349 | // cc.loader.clear(); 350 | 351 | cc.director.reset(); 352 | cc.loader.releaseAll(); 353 | 354 | let device = cc.renderer.device; 355 | if (device && device._current && device._next) { 356 | device._current = new device._current.constructor(device); 357 | device._next = new device._next.constructor(device); 358 | } 359 | 360 | // clear persist root nodes 361 | let nodes = cc.game._persistRootNodes; 362 | for (let name in nodes) { 363 | cc.game.removePersistRootNode(nodes[name]); 364 | } 365 | 366 | next(); 367 | }, 368 | 369 | function (next) { 370 | qp.init(); 371 | next(); 372 | }, 373 | 374 | function (next) { 375 | // load stashed scene 376 | cc.loader.load(_Settings['preview-scene.json'], function (error, json) { 377 | if (error) { 378 | cc.error(error.stack); 379 | return; 380 | } 381 | 382 | // Loading splash scene 383 | var splash = document.getElementById('splash'); 384 | var progressBar = splash.querySelector('.progress-bar span'); 385 | 386 | cc.director.once(cc.Director.EVENT_AFTER_SCENE_LAUNCH, function () { 387 | splash.style.display = 'none'; 388 | checkEmptyScene(); 389 | }); 390 | 391 | cc.loader.onProgress = function (completedCount, totalCount, item) { 392 | var percent = 100 * completedCount / totalCount; 393 | if (progressBar) { 394 | progressBar.style.width = percent.toFixed(2) + '%'; 395 | } 396 | }; 397 | 398 | cc.AssetLibrary.loadJson(json, 399 | function (err, sceneAsset) { 400 | if (err) { 401 | cc.error(err.stack); 402 | return; 403 | } 404 | var scene = sceneAsset.scene; 405 | scene._name = sceneAsset._name; 406 | cc.director.runSceneImmediate(scene, function () { 407 | cc.game.resume(); 408 | setDisplayStats( isShowFPS() ); 409 | }); 410 | 411 | cc.loader.onProgress = null; 412 | next(); 413 | } 414 | ); 415 | }); 416 | } 417 | ]); 418 | }; 419 | 420 | cc.game.run(option, function () { 421 | var Path = require('path'); 422 | 423 | require(Path.join(__dirname, 'scripts/engine.js')); 424 | 425 | reloadScene(); 426 | 427 | // purge 428 | //noinspection JSUnresolvedVariable 429 | // _CCSettings = undefined; 430 | }); 431 | }; 432 | 433 | function checkEmptyScene () { 434 | var scene = cc.director.getScene(); 435 | if (scene) { 436 | if (scene.children.length > 1) { 437 | return; 438 | } 439 | if (scene.children.length === 1) { 440 | var node = scene.children[0]; 441 | if (node.children.length > 0) { 442 | return; 443 | } 444 | if (node._components.length > 1) { 445 | return; 446 | } 447 | if (node._components.length > 0 && !(node._components[0] instanceof cc.Canvas)) { 448 | return; 449 | } 450 | } 451 | } 452 | document.getElementById('bulletin').style.display = 'block'; 453 | document.getElementById('sceneIsEmpty').style.display = 'block'; 454 | } 455 | })(); 456 | 457 | --------------------------------------------------------------------------------